Release - TypeScript SDK (npm) workflow (tensorlakeai/tensorlake)
The Release - TypeScript SDK (npm) workflow from tensorlakeai/tensorlake, explained and optimized by Latchkey.
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.
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
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
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Cache dependency installs on the setup step so they are served from cache.
- Add a job timeout so a hung step cannot burn hours of runner time.
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:
- Dependency installs
This workflow runs 3 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.