Skip to content

Commit d06bdf6

Browse files
TeoSlayerTeodor Calin
andauthored
Version-lock npm publish and bundle native binaries (#12)
* Version-lock npm publish and bundle native binaries * Normalize web4 checkout ref to vX.Y.Z tag * Point package repository at sdk-node for npm provenance --------- Co-authored-by: Teodor Calin <teodor@pilotprotocol.network>
1 parent 870d793 commit d06bdf6

2 files changed

Lines changed: 225 additions & 21 deletions

File tree

.github/workflows/publish.yml

Lines changed: 221 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,249 @@
11
name: publish
22

3-
# PILOT-203: npm publish workflow.
3+
# PILOT-203 / release fan-out: npm publish workflow.
44
#
5-
# Triggers on release published. Build the dist, then npm publish.
6-
# Optional-dependency platform packages (pilotprotocol-darwin-arm64,
7-
# etc.) are published separately by the release pipeline; this workflow
8-
# only publishes the main entry-point package.
5+
# Triggers on:
6+
# - workflow_dispatch with a `version` input — the canonical path. web4's
7+
# release pipeline dispatches this at the daemon tag (e.g. 1.12.3) so the
8+
# SDK publishes version-locked to the daemon, NOT to whatever stale
9+
# version sits in package.json.
10+
# - release published (legacy path for manual GitHub releases in this repo).
11+
#
12+
# The published package BUNDLES the native runtime under bin/<os>-<arch>/
13+
# (pilot-daemon, pilotctl, pilot-gateway, pilot-updater, libpilot.{so,dylib}),
14+
# which src/ffi.ts resolves at load time. The binaries are built from source:
15+
# libpilot (the CGO shared lib) lives in pilot-protocol/libpilot and builds
16+
# against a set of sibling Go modules — the same checkout set libpilot CI uses.
17+
# Each platform job uploads its bin/<os>-<arch>/ subtree; the publish job
18+
# merges all platforms into one multi-platform package and publishes once.
919
#
1020
# Required secret:
1121
# NPM_TOKEN — npmjs.org automation token with publish rights on the
1222
# pilotprotocol package.
1323

1424
on:
25+
workflow_dispatch:
26+
inputs:
27+
version:
28+
description: 'Version to publish (with or without leading v, e.g. 1.12.3)'
29+
required: true
30+
type: string
1531
release:
1632
types: [published]
17-
workflow_dispatch:
1833

1934
permissions:
2035
contents: read
2136

37+
env:
38+
PILOT_VERSION_RAW: ${{ inputs.version || github.event.release.tag_name }}
39+
2240
jobs:
41+
# Normalize the version once. `version` is bare (X.Y.Z) for package
42+
# metadata; `ref` is the web4 git tag (always vX.Y.Z) for source checkout.
43+
prep:
44+
runs-on: ubuntu-latest
45+
outputs:
46+
version: ${{ steps.v.outputs.version }}
47+
ref: ${{ steps.v.outputs.ref }}
48+
steps:
49+
- id: v
50+
shell: bash
51+
run: |
52+
RAW="${PILOT_VERSION_RAW}"
53+
if [ -z "$RAW" ]; then
54+
echo "::error::no version supplied (inputs.version / release tag both empty)"
55+
exit 1
56+
fi
57+
BARE="${RAW#v}"
58+
echo "version=$BARE" >> "$GITHUB_OUTPUT"
59+
echo "ref=v$BARE" >> "$GITHUB_OUTPUT"
60+
echo "version=$BARE ref=v$BARE"
61+
62+
build-binaries:
63+
needs: prep
64+
name: Build binaries (${{ matrix.platform }}/${{ matrix.goarch }})
65+
strategy:
66+
fail-fast: false
67+
matrix:
68+
include:
69+
- os: ubuntu-latest
70+
platform: linux
71+
goarch: amd64
72+
subdir: linux-amd64
73+
- os: macos-latest
74+
platform: darwin
75+
goarch: arm64
76+
subdir: darwin-arm64
77+
runs-on: ${{ matrix.os }}
78+
steps:
79+
- name: Checkout sdk-node
80+
uses: actions/checkout@v4
81+
with:
82+
path: sdk-node
83+
84+
- name: Checkout libpilot
85+
uses: actions/checkout@v4
86+
with: { repository: pilot-protocol/libpilot, path: libpilot }
87+
- name: Checkout web4
88+
uses: actions/checkout@v4
89+
with: { repository: pilot-protocol/pilotprotocol, path: web4, ref: "${{ needs.prep.outputs.ref }}" }
90+
- name: Checkout common
91+
uses: actions/checkout@v4
92+
with: { repository: pilot-protocol/common, path: common }
93+
- name: Checkout trustedagents
94+
uses: actions/checkout@v4
95+
with: { repository: pilot-protocol/trustedagents, path: trustedagents }
96+
- name: Checkout handshake
97+
uses: actions/checkout@v4
98+
with: { repository: pilot-protocol/handshake, path: handshake }
99+
- name: Checkout policy
100+
uses: actions/checkout@v4
101+
with: { repository: pilot-protocol/policy, path: policy }
102+
- name: Checkout runtime
103+
uses: actions/checkout@v4
104+
with: { repository: pilot-protocol/runtime, path: runtime }
105+
- name: Checkout skillinject
106+
uses: actions/checkout@v4
107+
with: { repository: pilot-protocol/skillinject, path: skillinject }
108+
- name: Checkout webhook
109+
uses: actions/checkout@v4
110+
with: { repository: pilot-protocol/webhook, path: webhook }
111+
- name: Checkout eventstream
112+
uses: actions/checkout@v4
113+
with: { repository: pilot-protocol/eventstream, path: eventstream }
114+
- name: Checkout dataexchange
115+
uses: actions/checkout@v4
116+
with: { repository: pilot-protocol/dataexchange, path: dataexchange }
117+
- name: Checkout updater
118+
uses: actions/checkout@v4
119+
with: { repository: pilot-protocol/updater, path: updater }
120+
- name: Checkout gateway
121+
uses: actions/checkout@v4
122+
with: { repository: pilot-protocol/gateway, path: gateway }
123+
- name: Checkout nameserver
124+
uses: actions/checkout@v4
125+
with: { repository: pilot-protocol/nameserver, path: nameserver }
126+
- name: Checkout rendezvous
127+
uses: actions/checkout@v4
128+
with: { repository: pilot-protocol/rendezvous, path: rendezvous }
129+
- name: Checkout beacon
130+
uses: actions/checkout@v4
131+
with: { repository: pilot-protocol/beacon, path: beacon }
132+
- name: Checkout app-store
133+
uses: actions/checkout@v4
134+
with: { repository: pilot-protocol/app-store, path: app-store }
135+
136+
- uses: actions/setup-go@v5
137+
with:
138+
go-version-file: web4/go.mod
139+
140+
- name: Build native binaries
141+
shell: bash
142+
run: |
143+
set -euo pipefail
144+
( cd libpilot && go mod tidy )
145+
146+
OS=${{ matrix.platform }}
147+
case "$OS" in
148+
linux) EXT=so ;;
149+
darwin) EXT=dylib ;;
150+
*) echo "::error::unsupported os $OS"; exit 1 ;;
151+
esac
152+
153+
OUT="$GITHUB_WORKSPACE/sdk-node/bin/${{ matrix.subdir }}"
154+
mkdir -p "$OUT"
155+
LDFLAGS="-s -w -X main.version=${{ needs.prep.outputs.version }}"
156+
157+
( cd web4 && CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o "$OUT/pilot-daemon" ./cmd/daemon )
158+
( cd web4 && CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o "$OUT/pilotctl" ./cmd/pilotctl )
159+
( cd web4 && CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o "$OUT/pilot-updater" ./cmd/updater )
160+
( cd gateway && go mod tidy && CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o "$OUT/pilot-gateway" ./cmd/gateway ) \
161+
|| ( cd gateway && CGO_ENABLED=0 go build -ldflags "$LDFLAGS" -o "$OUT/pilot-gateway" . )
162+
( cd libpilot && CGO_ENABLED=1 go build -buildmode=c-shared -ldflags "-s -w" -o "$OUT/libpilot.$EXT" . )
163+
164+
if [ "$OS" = "darwin" ]; then
165+
for b in "$OUT"/*; do codesign --force --deep --sign - "$b" || true; xattr -cr "$b" || true; done
166+
fi
167+
ls -lh "$OUT"
168+
169+
- name: Write .pilot-version marker (Linux only)
170+
if: matrix.platform == 'linux'
171+
run: echo "${{ needs.prep.outputs.version }}" > "$GITHUB_WORKSPACE/sdk-node/bin/.pilot-version"
172+
173+
- name: Upload bin subtree
174+
uses: actions/upload-artifact@v4
175+
with:
176+
name: node-bin-${{ matrix.subdir }}
177+
path: sdk-node/bin/
178+
retention-days: 7
179+
23180
publish:
24181
name: Publish to npm
182+
needs: [prep, build-binaries]
25183
runs-on: ubuntu-latest
26184
permissions:
27185
contents: read
28-
id-token: write # for npm provenance attestation
186+
id-token: write # npm provenance
29187
steps:
30-
- uses: actions/checkout@v4
188+
- name: Checkout sdk-node
189+
uses: actions/checkout@v4
190+
31191
- uses: actions/setup-node@v4
32192
with:
33193
node-version: '22'
34194
registry-url: 'https://registry.npmjs.org'
35-
- run: npm ci
36-
- run: npm run build
37-
- run: npm publish --provenance --access public
195+
196+
- name: Download all bin subtrees
197+
uses: actions/download-artifact@v4
198+
with:
199+
path: bin-artifacts
200+
201+
- name: Merge platform binaries into bin/
202+
run: |
203+
set -euo pipefail
204+
mkdir -p bin
205+
# Each artifact dir contains a bin/ subtree; merge them all.
206+
for art in bin-artifacts/node-bin-*; do
207+
cp -R "$art"/* bin/
208+
done
209+
echo "Merged bin/ layout:"
210+
find bin -maxdepth 2 | sort
211+
212+
- name: Pin package.json version
213+
run: |
214+
VERSION="${{ needs.prep.outputs.version }}"
215+
node -e "const fs=require('fs');const p=JSON.parse(fs.readFileSync('package.json','utf8'));p.version='$VERSION';fs.writeFileSync('package.json',JSON.stringify(p,null,2)+'\n');"
216+
echo "package.json version -> $VERSION"
217+
218+
- name: Build TypeScript
219+
run: |
220+
npm ci
221+
npm run build
222+
223+
- name: Check if version exists on npm
224+
id: check
225+
run: |
226+
if npm view pilotprotocol@${{ needs.prep.outputs.version }} version >/dev/null 2>&1; then
227+
echo "exists=true" >> "$GITHUB_OUTPUT"
228+
echo "::notice::pilotprotocol ${{ needs.prep.outputs.version }} already on npm — skipping publish"
229+
else
230+
echo "exists=false" >> "$GITHUB_OUTPUT"
231+
fi
232+
233+
- name: Verify package contents
234+
run: npm pack --dry-run
235+
236+
- name: Publish to npm
237+
if: steps.check.outputs.exists == 'false'
38238
env:
39239
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
240+
run: npm publish --provenance --access public
241+
242+
- name: Summary
243+
run: |
244+
{
245+
echo "## Node SDK"
246+
echo "- Version: \`${{ needs.prep.outputs.version }}\`"
247+
echo "- Already present: \`${{ steps.check.outputs.exists }}\`"
248+
echo "- Install: \`npm install pilotprotocol\`"
249+
} >> "$GITHUB_STEP_SUMMARY"

package.json

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,22 +49,15 @@
4949
],
5050
"repository": {
5151
"type": "git",
52-
"url": "https://github.com/TeoSlayer/pilotprotocol",
53-
"directory": "sdk/node"
52+
"url": "git+https://github.com/pilot-protocol/sdk-node.git"
5453
},
5554
"homepage": "https://pilotprotocol.network",
5655
"bugs": {
57-
"url": "https://github.com/TeoSlayer/pilotprotocol/issues"
56+
"url": "https://github.com/pilot-protocol/sdk-node/issues"
5857
},
5958
"dependencies": {
6059
"koffi": "^2.9.0"
6160
},
62-
"optionalDependencies": {
63-
"pilotprotocol-darwin-arm64": "0.1.1",
64-
"pilotprotocol-darwin-x64": "0.1.1",
65-
"pilotprotocol-linux-arm64": "0.1.1",
66-
"pilotprotocol-linux-x64": "0.1.1"
67-
},
6861
"devDependencies": {
6962
"@types/node": "^25.5.0",
7063
"@vitest/coverage-v8": "^3.2.4",
@@ -76,6 +69,7 @@
7669
},
7770
"files": [
7871
"dist/",
79-
"bin-stubs/"
72+
"bin-stubs/",
73+
"bin/"
8074
]
8175
}

0 commit comments

Comments
 (0)