Skip to content

Commit f7ae5c0

Browse files
committed
breaking(release): add OIDC npm release workflow. include all builds in package. add Alpine/MUSL support.
1 parent b904a1d commit f7ae5c0

File tree

4 files changed

+313
-15
lines changed

4 files changed

+313
-15
lines changed

.github/workflows/npm-release.yaml

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
name: "npm Release"
2+
3+
# Fork-specific workflow for publishing to npm with OIDC
4+
5+
# Separate from release.yaml to make merging upstream changes easier
6+
7+
#
8+
# APPROACH: We bundle all platform binaries in a single npm package (like
9+
# prebuildify) rather than using platform-specific optionalDependencies (like
10+
# esbuild/swc). Rationale:
11+
# - Simpler: one package to publish, not 5+ platform packages
12+
# - More secure: avoids post-install scripts and dependency on npm registry
13+
# - Reliable: works offline, with disabled scripts, and custom registries
14+
# - Small overhead: sqlite-vec binaries are ~200KB each, so bundling all is
15+
# fine
16+
17+
#
18+
# FIRST-TIME SETUP (required before this workflow will work):
19+
#
20+
# 1. Build and publish the package locally to create it on npm:
21+
# ./scripts/vendor.sh make loadable mkdir -p dist/$(node -p "process.platform
22+
# + '-' + process.arch") cp dist/vec0.* dist/$(node -p "process.platform +
23+
# '-' + process.arch")/ npm login npm publish --access public
24+
#
25+
# 2. Configure OIDC trusted publishing on npmjs.com:
26+
# - Go to https://www.npmjs.com/package/@USER/sqlite-vec/access
27+
# - Under "Publishing access" click "Add a trusted publisher"
28+
# - Repository: USER/sqlite-vec
29+
# - Workflow: npm-release.yaml
30+
# - Environment: (leave blank)
31+
#
32+
# 3. Now this workflow can publish subsequent versions automatically
33+
34+
on:
35+
workflow_dispatch:
36+
inputs:
37+
version:
38+
description: "Version bump type"
39+
required: false
40+
type: choice
41+
default: "patch"
42+
options:
43+
- patch
44+
- minor
45+
- major
46+
47+
permissions:
48+
contents: read
49+
50+
jobs:
51+
build-linux-x64:
52+
runs-on: ubuntu-24.04
53+
steps:
54+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
55+
- run: ./scripts/vendor.sh
56+
- run: make loadable
57+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
58+
with:
59+
name: linux-x64
60+
path: dist/vec0.so
61+
62+
build-linux-arm64:
63+
runs-on: ubuntu-24.04-arm
64+
steps:
65+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
66+
- run: ./scripts/vendor.sh
67+
- run: make sqlite-vec.h
68+
- run: make loadable
69+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
70+
with:
71+
name: linux-arm64
72+
path: dist/vec0.so
73+
74+
build-linux-x64-musl:
75+
runs-on: ubuntu-24.04
76+
steps:
77+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
78+
- run: |
79+
docker run --rm -v $(pwd):/tmp/project --entrypoint /bin/sh --platform linux/amd64 node:20-alpine -c "\
80+
apk add build-base --update-cache && \
81+
cd /tmp/project && \
82+
./scripts/vendor.sh && \
83+
make loadable"
84+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
85+
with:
86+
name: linux-x64-musl
87+
path: dist/vec0.so
88+
89+
build-linux-arm64-musl:
90+
runs-on: ubuntu-24.04-arm
91+
steps:
92+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
93+
- run: |
94+
docker run --rm -v $(pwd):/tmp/project --entrypoint /bin/sh --platform linux/arm64 node:20-alpine -c "\
95+
apk add build-base --update-cache && \
96+
cd /tmp/project && \
97+
./scripts/vendor.sh && \
98+
make loadable"
99+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
100+
with:
101+
name: linux-arm64-musl
102+
path: dist/vec0.so
103+
104+
build-darwin-x64:
105+
runs-on: macos-15-intel
106+
steps:
107+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
108+
- run: ./scripts/vendor.sh
109+
- run: make loadable
110+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
111+
with:
112+
name: darwin-x64
113+
path: dist/vec0.dylib
114+
115+
build-darwin-arm64:
116+
runs-on: macos-14
117+
steps:
118+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
119+
- run: ./scripts/vendor.sh
120+
- run: make loadable
121+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
122+
with:
123+
name: darwin-arm64
124+
path: dist/vec0.dylib
125+
126+
build-win32-x64:
127+
runs-on: windows-latest
128+
steps:
129+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
130+
- uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
131+
- run: ./scripts/vendor.sh
132+
shell: bash
133+
- run: make sqlite-vec.h
134+
- run: mkdir dist
135+
- run: cl.exe /fPIC -shared /W4 /Ivendor/ /O2 /LD sqlite-vec.c -o dist/vec0.dll
136+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
137+
with:
138+
name: win32-x64
139+
path: dist/vec0.dll
140+
141+
build-win32-arm64:
142+
runs-on: windows-11-arm
143+
steps:
144+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
145+
- uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0
146+
with:
147+
arch: arm64
148+
- run: ./scripts/vendor.sh
149+
shell: bash
150+
- run: make sqlite-vec.h
151+
- run: mkdir dist
152+
- run: cl.exe /fPIC -shared /W4 /Ivendor/ /O2 /LD sqlite-vec.c -o dist/vec0.dll
153+
- uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0
154+
with:
155+
name: win32-arm64
156+
path: dist/vec0.dll
157+
158+
publish-npm:
159+
runs-on: ubuntu-24.04
160+
needs:
161+
[
162+
build-linux-x64,
163+
build-linux-arm64,
164+
build-linux-x64-musl,
165+
build-linux-arm64-musl,
166+
build-darwin-x64,
167+
build-darwin-arm64,
168+
build-win32-x64,
169+
build-win32-arm64,
170+
]
171+
permissions:
172+
contents: write # Required to push version commits and tags
173+
id-token: write # Required for npm OIDC trusted publishing
174+
steps:
175+
- uses: actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8 # v6.0.1
176+
with:
177+
fetch-depth: 0 # Full history for version tags
178+
179+
# Download all artifacts into platform-specific subdirectories
180+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
181+
with:
182+
name: linux-x64
183+
path: dist/linux-x64
184+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
185+
with:
186+
name: linux-arm64
187+
path: dist/linux-arm64
188+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
189+
with:
190+
name: linux-x64-musl
191+
path: dist/linux-x64-musl
192+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
193+
with:
194+
name: linux-arm64-musl
195+
path: dist/linux-arm64-musl
196+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
197+
with:
198+
name: darwin-x64
199+
path: dist/darwin-x64
200+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
201+
with:
202+
name: darwin-arm64
203+
path: dist/darwin-arm64
204+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
205+
with:
206+
name: win32-x64
207+
path: dist/win32-x64
208+
- uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0
209+
with:
210+
name: win32-arm64
211+
path: dist/win32-arm64
212+
213+
- run: ls -laR dist/
214+
215+
- uses: actions/setup-node@395ad3262231945c25e8478fd5baf05154b1d79f # v6.1.0
216+
with:
217+
node-version: "20"
218+
registry-url: "https://registry.npmjs.org"
219+
220+
- uses: photostructure/git-ssh-signing-action@fdd4b062a9ba41473f013258cc9c7eea1640f826 # v1.2.0
221+
with:
222+
ssh-signing-key: ${{ secrets.SSH_SIGNING_KEY }}
223+
git-user-name: ${{ secrets.GIT_USER_NAME }}
224+
git-user-email: ${{ secrets.GIT_USER_EMAIL }}
225+
226+
- run: npm install -g npm@latest
227+
228+
- name: Bump version and create signed tag
229+
run: |
230+
npm version ${{ github.event.inputs.version }} --sign-git-tag -m "release: %s"
231+
echo "NEW_VERSION=$(npm pkg get version | tr -d '\"')" >> $GITHUB_ENV
232+
233+
- name: Push version commit and tag
234+
run: git push origin main --follow-tags
235+
236+
- name: Create GitHub Release
237+
run: gh release create "v${{ env.NEW_VERSION }}" --generate-notes
238+
env:
239+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
240+
241+
- name: Publish to npm with OIDC
242+
run: npm publish --provenance --access public

index.cjs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
const { join } = require("node:path");
22
const { arch, platform } = require("node:process");
3-
const { statSync } = require("node:fs");
3+
const { readdirSync, statSync } = require("node:fs");
44

55
const ENTRYPOINT_BASE_NAME = "vec0";
66

@@ -10,15 +10,48 @@ function extensionSuffix(platform) {
1010
return "so";
1111
}
1212

13+
/**
14+
* Detect if running on musl libc (Alpine Linux, etc.)
15+
* Uses detect-libc's primary heuristic: check for musl dynamic linker
16+
*/
17+
function isMusl() {
18+
if (platform !== "linux") return false;
19+
try {
20+
const files = readdirSync("/lib");
21+
return files.some((f) => f.startsWith("ld-musl-"));
22+
} catch {
23+
return false;
24+
}
25+
}
26+
1327
function getLoadablePath() {
28+
// Platform-specific subdirectory (e.g., darwin-arm64, linux-x64, linux-x64-musl)
29+
const platformDir =
30+
platform === "linux" && isMusl()
31+
? `${platform}-${arch}-musl`
32+
: `${platform}-${arch}`;
1433
const loadablePath = join(
1534
__dirname,
1635
"dist",
36+
platformDir,
1737
`${ENTRYPOINT_BASE_NAME}.${extensionSuffix(platform)}`
1838
);
1939

2040
if (!statSync(loadablePath, { throwIfNoEntry: false })) {
21-
throw new Error(`Loadable extension for sqlite-vec not found at ${loadablePath}. Was the extension built? Run: make loadable`);
41+
const supported = [
42+
"darwin-x64",
43+
"darwin-arm64",
44+
"linux-x64",
45+
"linux-x64-musl",
46+
"linux-arm64",
47+
"linux-arm64-musl",
48+
"win32-x64",
49+
"win32-arm64",
50+
];
51+
throw new Error(
52+
`Loadable extension for sqlite-vec not found for ${platformDir} at ${loadablePath}. ` +
53+
`Supported platforms: ${supported.join(", ")}.`
54+
);
2255
}
2356

2457
return loadablePath;

index.mjs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { join } from "node:path";
22
import { fileURLToPath } from "node:url";
33
import { arch, platform } from "node:process";
4-
import { statSync } from "node:fs";
4+
import { readdirSync, statSync } from "node:fs";
55

66
const ENTRYPOINT_BASE_NAME = "vec0";
77

@@ -11,15 +11,48 @@ function extensionSuffix(platform) {
1111
return "so";
1212
}
1313

14+
/**
15+
* Detect if running on musl libc (Alpine Linux, etc.)
16+
* Uses detect-libc's primary heuristic: check for musl dynamic linker
17+
*/
18+
function isMusl() {
19+
if (platform !== "linux") return false;
20+
try {
21+
const files = readdirSync("/lib");
22+
return files.some((f) => f.startsWith("ld-musl-"));
23+
} catch {
24+
return false;
25+
}
26+
}
27+
1428
function getLoadablePath() {
29+
// Platform-specific subdirectory (e.g., darwin-arm64, linux-x64, linux-x64-musl)
30+
const platformDir =
31+
platform === "linux" && isMusl()
32+
? `${platform}-${arch}-musl`
33+
: `${platform}-${arch}`;
1534
const loadablePath = join(
1635
fileURLToPath(new URL(".", import.meta.url)),
1736
"dist",
37+
platformDir,
1838
`${ENTRYPOINT_BASE_NAME}.${extensionSuffix(platform)}`
1939
);
2040

2141
if (!statSync(loadablePath, { throwIfNoEntry: false })) {
22-
throw new Error(`Loadable extension for sqlite-vec not found at ${loadablePath}. Was the extension built? Run: make loadable`);
42+
const supported = [
43+
"darwin-x64",
44+
"darwin-arm64",
45+
"linux-x64",
46+
"linux-x64-musl",
47+
"linux-arm64",
48+
"linux-arm64-musl",
49+
"win32-x64",
50+
"win32-arm64",
51+
];
52+
throw new Error(
53+
`Loadable extension for sqlite-vec not found for ${platformDir} at ${loadablePath}. ` +
54+
`Supported platforms: ${supported.join(", ")}.`
55+
);
2356
}
2457

2558
return loadablePath;

package.json

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
}
1414
},
1515
"scripts": {
16-
"install": "bash -c './scripts/vendor.sh && make loadable'",
1716
"test": "echo \"Error: no test specified\" && exit 1"
1817
},
1918
"repository": {
@@ -52,15 +51,6 @@
5251
"index.cjs",
5352
"index.mjs",
5453
"index.d.ts",
55-
"dist/vec0.so",
56-
"dist/vec0.dylib",
57-
"dist/vec0.dll",
58-
"sqlite-vec.c",
59-
"sqlite-vec.h",
60-
"sqlite-vec.h.tmpl",
61-
"VERSION",
62-
"vendor/",
63-
"scripts/vendor.sh",
64-
"Makefile"
54+
"dist/"
6555
]
6656
}

0 commit comments

Comments
 (0)