Skip to content
Latchkey

Release - TypeScript SDK (npm) workflow (tensorlakeai/tensorlake)

The Release - TypeScript SDK (npm) workflow from tensorlakeai/tensorlake, explained and optimized by Latchkey.

C

CI health: C - fair

Point runs-on at Latchkey and get caching, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.

Grade your own workflow free or run it on Latchkey →
Source: tensorlakeai/tensorlake.github/workflows/publish_npm.yamlLicense Apache-2.0View source

What it does

This is the Release - TypeScript SDK (npm) workflow from the tensorlakeai/tensorlake repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.

Below, Latchkey shows a faster, safer version produced by its optimization engine.

The workflow

workflow (.yml)
name: Release - TypeScript SDK (npm)

run-name: "Release - TypeScript SDK (npm) · ${{ github.ref_name }} · @${{ github.actor }}"

on:
  workflow_dispatch:

env:
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

permissions:
  contents: read

defaults:
  run:
    working-directory: typescript

jobs:
  build-sdk-and-test:
    name: Build SDK and test
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"
          registry-url: "https://registry.npmjs.org"
          cache: "npm"
          cache-dependency-path: typescript/package-lock.json

      - name: Install dependencies
        run: npm ci

      - name: Type check
        run: npm run typecheck

      - name: Run tests
        run: npm test

      - name: Build SDK
        run: npm run build:sdk

      - name: Upload SDK artifact
        uses: actions/upload-artifact@v4
        with:
          name: sdk-dist
          path: typescript/dist

  build-native-binaries:
    name: Build native binding (${{ matrix.target_id }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target_id: linux-x64
            rust_target: x86_64-unknown-linux-gnu.2.28
            rust_target_base: x86_64-unknown-linux-gnu
            libc: gnu
            native_build_tool: cargo-zigbuild
          - os: ubuntu-24.04-arm
            target_id: linux-arm64
            rust_target: aarch64-unknown-linux-gnu.2.28
            rust_target_base: aarch64-unknown-linux-gnu
            libc: gnu
            native_build_tool: cargo-zigbuild
          - os: ubuntu-latest
            target_id: linux-x64-musl
            rust_target: x86_64-unknown-linux-musl
            rust_target_base: x86_64-unknown-linux-musl
            libc: musl
            native_build_tool: cargo-zigbuild
          - os: ubuntu-24.04-arm
            target_id: linux-arm64-musl
            rust_target: aarch64-unknown-linux-musl
            rust_target_base: aarch64-unknown-linux-musl
            libc: musl
            native_build_tool: cargo-zigbuild
          - os: macos-14
            target_id: darwin-arm64
            rust_target: ""
            rust_target_base: ""
            libc: ""
            native_build_tool: cargo
          - os: windows-latest
            target_id: win32-x64
            rust_target: ""
            rust_target_base: ""
            libc: ""
            native_build_tool: cargo
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"
          cache: "npm"
          cache-dependency-path: typescript/package-lock.json

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Setup Zig
        if: matrix.native_build_tool == 'cargo-zigbuild'
        uses: mlugg/setup-zig@v2

      - name: Cache Rust build artifacts
        uses: Swatinem/rust-cache@v2
        with:
          prefix-key: v1-rust-no-bin
          cache-bin: false

      - name: Install cargo-zigbuild
        if: matrix.native_build_tool == 'cargo-zigbuild'
        run: cargo install cargo-zigbuild --locked

      - name: Install Rust target
        if: matrix.rust_target_base != ''
        run: rustup target add ${{ matrix.rust_target_base }}

      - name: Install dependencies
        run: npm ci

      - name: Build native binding
        run: npm run build:native
        env:
          TENSORLAKE_NODE_TARGET_ID: ${{ matrix.target_id }}
          TENSORLAKE_NODE_TARGET_TRIPLE: ${{ matrix.rust_target }}
          TENSORLAKE_NODE_BUILD_TOOL: ${{ matrix.native_build_tool }}

      - name: Verify Linux native libc compatibility
        if: startsWith(matrix.target_id, 'linux-')
        run: |
          set -euo pipefail
          binding="dist/native/${{ matrix.target_id }}/tensorlake-node.node"
          required_versions="$(readelf --version-info "$binding" | grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sort -Vu || true)"
          max_glibc="$(printf '%s\n' "$required_versions" | tail -n1)"
          echo "Maximum required glibc: ${max_glibc:-none}"
          if [ "${{ matrix.libc }}" = "musl" ] && [ -n "$max_glibc" ]; then
            echo "Musl native binding unexpectedly references glibc symbols."
            exit 1
          fi
          if [ "${{ matrix.libc }}" = "gnu" ] && [ -n "$max_glibc" ] && [ "$(printf '%s\n%s\n' "GLIBC_2.28" "$max_glibc" | sort -V | tail -n1)" != "GLIBC_2.28" ]; then
            echo "Native binding requires $max_glibc, above the GLIBC_2.28 compatibility floor."
            exit 1
          fi

      - name: Upload native artifact
        uses: actions/upload-artifact@v4
        with:
          name: native-${{ matrix.target_id }}
          path: typescript/dist/native/${{ matrix.target_id }}

  publish:
    name: Publish to npm
    needs:
      - build-sdk-and-test
      - build-native-binaries
    runs-on: ubuntu-latest
    environment:
      name: npm
      url: https://www.npmjs.com/package/tensorlake
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: "24"
          registry-url: "https://registry.npmjs.org"
          package-manager-cache: false

      - name: Install dependencies
        run: npm ci

      - name: Download SDK artifact
        uses: actions/download-artifact@v4
        with:
          name: sdk-dist
          path: typescript/dist

      - name: Download Linux native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-x64
          path: typescript/dist/native/linux-x64

      - name: Download Linux arm64 native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-arm64
          path: typescript/dist/native/linux-arm64

      - name: Download Linux musl native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-x64-musl
          path: typescript/dist/native/linux-x64-musl

      - name: Download Linux arm64 musl native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-arm64-musl
          path: typescript/dist/native/linux-arm64-musl

      - name: Download macOS arm64 native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-darwin-arm64
          path: typescript/dist/native/darwin-arm64

      - name: Download Windows x64 native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-win32-x64
          path: typescript/dist/native/win32-x64

      - name: Verify package contents
        run: npm pack --dry-run --ignore-scripts

      - name: Publish to npm
        run: npm publish --access public --ignore-scripts

The same workflow, on Latchkey

Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.

name: Release - TypeScript SDK (npm)
 
run-name: "Release - TypeScript SDK (npm) · ${{ github.ref_name }} · @${{ github.actor }}"
 
on:
  workflow_dispatch:
 
env:
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
 
permissions:
  contents: read
 
defaults:
  run:
    working-directory: typescript
 
jobs:
  build-sdk-and-test:
    timeout-minutes: 30
    name: Build SDK and test
    runs-on: latchkey-small
    steps:
      - uses: actions/checkout@v4
 
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"
          registry-url: "https://registry.npmjs.org"
          cache: "npm"
          cache-dependency-path: typescript/package-lock.json
 
      - name: Install dependencies
        run: npm ci
 
      - name: Type check
        run: npm run typecheck
 
      - name: Run tests
        run: npm test
 
      - name: Build SDK
        run: npm run build:sdk
 
      - name: Upload SDK artifact
        uses: actions/upload-artifact@v4
        with:
          name: sdk-dist
          path: typescript/dist
 
  build-native-binaries:
    timeout-minutes: 30
    name: Build native binding (${{ matrix.target_id }})
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            target_id: linux-x64
            rust_target: x86_64-unknown-linux-gnu.2.28
            rust_target_base: x86_64-unknown-linux-gnu
            libc: gnu
            native_build_tool: cargo-zigbuild
          - os: ubuntu-24.04-arm
            target_id: linux-arm64
            rust_target: aarch64-unknown-linux-gnu.2.28
            rust_target_base: aarch64-unknown-linux-gnu
            libc: gnu
            native_build_tool: cargo-zigbuild
          - os: ubuntu-latest
            target_id: linux-x64-musl
            rust_target: x86_64-unknown-linux-musl
            rust_target_base: x86_64-unknown-linux-musl
            libc: musl
            native_build_tool: cargo-zigbuild
          - os: ubuntu-24.04-arm
            target_id: linux-arm64-musl
            rust_target: aarch64-unknown-linux-musl
            rust_target_base: aarch64-unknown-linux-musl
            libc: musl
            native_build_tool: cargo-zigbuild
          - os: macos-14
            target_id: darwin-arm64
            rust_target: ""
            rust_target_base: ""
            libc: ""
            native_build_tool: cargo
          - os: windows-latest
            target_id: win32-x64
            rust_target: ""
            rust_target_base: ""
            libc: ""
            native_build_tool: cargo
    steps:
      - uses: actions/checkout@v4
 
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "22"
          cache: "npm"
          cache-dependency-path: typescript/package-lock.json
 
      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable
 
      - name: Setup Zig
        if: matrix.native_build_tool == 'cargo-zigbuild'
        uses: mlugg/setup-zig@v2
 
      - name: Cache Rust build artifacts
        uses: Swatinem/rust-cache@v2
        with:
          prefix-key: v1-rust-no-bin
          cache-bin: false
 
      - name: Install cargo-zigbuild
        if: matrix.native_build_tool == 'cargo-zigbuild'
        run: cargo install cargo-zigbuild --locked
 
      - name: Install Rust target
        if: matrix.rust_target_base != ''
        run: rustup target add ${{ matrix.rust_target_base }}
 
      - name: Install dependencies
        run: npm ci
 
      - name: Build native binding
        run: npm run build:native
        env:
          TENSORLAKE_NODE_TARGET_ID: ${{ matrix.target_id }}
          TENSORLAKE_NODE_TARGET_TRIPLE: ${{ matrix.rust_target }}
          TENSORLAKE_NODE_BUILD_TOOL: ${{ matrix.native_build_tool }}
 
      - name: Verify Linux native libc compatibility
        if: startsWith(matrix.target_id, 'linux-')
        run: |
          set -euo pipefail
          binding="dist/native/${{ matrix.target_id }}/tensorlake-node.node"
          required_versions="$(readelf --version-info "$binding" | grep -oE 'GLIBC_[0-9]+\.[0-9]+' | sort -Vu || true)"
          max_glibc="$(printf '%s\n' "$required_versions" | tail -n1)"
          echo "Maximum required glibc: ${max_glibc:-none}"
          if [ "${{ matrix.libc }}" = "musl" ] && [ -n "$max_glibc" ]; then
            echo "Musl native binding unexpectedly references glibc symbols."
            exit 1
          fi
          if [ "${{ matrix.libc }}" = "gnu" ] && [ -n "$max_glibc" ] && [ "$(printf '%s\n%s\n' "GLIBC_2.28" "$max_glibc" | sort -V | tail -n1)" != "GLIBC_2.28" ]; then
            echo "Native binding requires $max_glibc, above the GLIBC_2.28 compatibility floor."
            exit 1
          fi
 
      - name: Upload native artifact
        uses: actions/upload-artifact@v4
        with:
          name: native-${{ matrix.target_id }}
          path: typescript/dist/native/${{ matrix.target_id }}
 
  publish:
    timeout-minutes: 30
    name: Publish to npm
    needs:
      - build-sdk-and-test
      - build-native-binaries
    runs-on: latchkey-small
    environment:
      name: npm
      url: https://www.npmjs.com/package/tensorlake
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@v4
 
      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          cache: 'npm'
          node-version: "24"
          registry-url: "https://registry.npmjs.org"
          package-manager-cache: false
 
      - name: Install dependencies
        run: npm ci
 
      - name: Download SDK artifact
        uses: actions/download-artifact@v4
        with:
          name: sdk-dist
          path: typescript/dist
 
      - name: Download Linux native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-x64
          path: typescript/dist/native/linux-x64
 
      - name: Download Linux arm64 native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-arm64
          path: typescript/dist/native/linux-arm64
 
      - name: Download Linux musl native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-x64-musl
          path: typescript/dist/native/linux-x64-musl
 
      - name: Download Linux arm64 musl native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-linux-arm64-musl
          path: typescript/dist/native/linux-arm64-musl
 
      - name: Download macOS arm64 native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-darwin-arm64
          path: typescript/dist/native/darwin-arm64
 
      - name: Download Windows x64 native artifact
        uses: actions/download-artifact@v4
        with:
          name: native-win32-x64
          path: typescript/dist/native/win32-x64
 
      - name: Verify package contents
        run: npm pack --dry-run --ignore-scripts
 
      - name: Publish to npm
        run: npm publish --access public --ignore-scripts
 

What changed

3 third-party actions are referenced by a movable tag. Pin them to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.

What Latchkey heals here

This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:

This workflow runs 3 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.

Actions used in this workflow