-
Notifications
You must be signed in to change notification settings - Fork 0
Add npm publish infrastructure with platform-specific packages #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,119 @@ | ||||||||||||||
| on: | ||||||||||||||
| release: | ||||||||||||||
| types: [published] | ||||||||||||||
| name: "npm-publish" | ||||||||||||||
|
|
||||||||||||||
| # The release tag must match the version in package.json (e.g. v0.1.0). | ||||||||||||||
| # Uses npm trusted publishing (OIDC provenance) — no NPM_TOKEN secret needed. | ||||||||||||||
| # Setup: on npmjs.com, link each package to this repo + workflow file. | ||||||||||||||
|
|
||||||||||||||
| jobs: | ||||||||||||||
| build: | ||||||||||||||
| name: Build ${{ matrix.platform }} | ||||||||||||||
| runs-on: ${{ matrix.os }} | ||||||||||||||
| strategy: | ||||||||||||||
| matrix: | ||||||||||||||
| include: | ||||||||||||||
| - os: ubuntu-latest | ||||||||||||||
| platform: linux-x64 | ||||||||||||||
| ext: so | ||||||||||||||
| - os: macos-14 | ||||||||||||||
| platform: darwin-arm64 | ||||||||||||||
| ext: dylib | ||||||||||||||
| - os: macos-13 | ||||||||||||||
| platform: darwin-x64 | ||||||||||||||
| ext: dylib | ||||||||||||||
| - os: windows-latest | ||||||||||||||
| platform: win32-x64 | ||||||||||||||
| ext: dll | ||||||||||||||
| steps: | ||||||||||||||
| - uses: actions/checkout@v4 | ||||||||||||||
|
|
||||||||||||||
| - name: Build extension | ||||||||||||||
| run: | | ||||||||||||||
| cd core | ||||||||||||||
| cmake -B build -DCMAKE_BUILD_TYPE=Release | ||||||||||||||
| cmake --build build --config Release | ||||||||||||||
|
|
||||||||||||||
| - name: Copy binary to platform package | ||||||||||||||
| shell: bash | ||||||||||||||
| run: | | ||||||||||||||
| cp core/build/crsqlite.${{ matrix.ext }} npm/crsqlite-${{ matrix.platform }}/crsqlite.${{ matrix.ext }} | ||||||||||||||
|
||||||||||||||
| cp core/build/crsqlite.${{ matrix.ext }} npm/crsqlite-${{ matrix.platform }}/crsqlite.${{ matrix.ext }} | |
| if [ "${{ matrix.os }}" = "windows-latest" ]; then | |
| cp core/build/Release/crsqlite.${{ matrix.ext }} npm/crsqlite-${{ matrix.platform }}/crsqlite.${{ matrix.ext }} | |
| else | |
| cp core/build/crsqlite.${{ matrix.ext }} npm/crsqlite-${{ matrix.platform }}/crsqlite.${{ matrix.ext }} | |
| fi |
Copilot
AI
Apr 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow builds the Windows binary but does not run the Node integration tests on Windows. That means a broken Windows artifact could still be published. Consider adding a Windows entry to the test matrix (or an equivalent smoke test that loads the produced .dll).
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,4 +1,33 @@ | ||||||||||||||
| // CJS entry point — see nodejs-helper.js for usage examples. | ||||||||||||||
| // CJS entry point — see nodejs-helper.js for usage and resolution order. | ||||||||||||||
| const { join } = require("node:path"); | ||||||||||||||
| const extensionPath = join(__dirname, "dist", "crsqlite"); | ||||||||||||||
| module.exports = { extensionPath }; | ||||||||||||||
| const { existsSync } = require("node:fs"); | ||||||||||||||
|
|
||||||||||||||
| const PLATFORM_PACKAGES = { | ||||||||||||||
| "linux-x64": "@shards-lang/crsqlite-linux-x64", | ||||||||||||||
| "darwin-arm64": "@shards-lang/crsqlite-darwin-arm64", | ||||||||||||||
| "darwin-x64": "@shards-lang/crsqlite-darwin-x64", | ||||||||||||||
| "win32-x64": "@shards-lang/crsqlite-win32-x64", | ||||||||||||||
| }; | ||||||||||||||
|
|
||||||||||||||
| function resolve() { | ||||||||||||||
| const key = `${process.platform}-${process.arch}`; | ||||||||||||||
| const pkg = PLATFORM_PACKAGES[key]; | ||||||||||||||
| if (pkg) { | ||||||||||||||
| try { | ||||||||||||||
| return require(pkg).path; | ||||||||||||||
| } catch {} | ||||||||||||||
|
||||||||||||||
| } catch {} | |
| } catch (error) { | |
| if (!error || error.code !== "MODULE_NOT_FOUND") { | |
| throw error; | |
| } | |
| } |
Copilot
AI
Apr 12, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
resolve() returns dist/crsqlite as a last resort, but dist/ is not shipped with the npm package anymore, so consumers can get an extensionPath that does not exist (unsupported platform / optional dep skipped). Consider checking for an actual binary in dist and throwing a helpful error if none is found.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,20 +1,61 @@ | ||
| // Exports the path to the cr-sqlite loadable extension. | ||
| // | ||
| // Resolution order: | ||
| // 1. Platform-specific npm package (@shards-lang/crsqlite-{os}-{cpu}) | ||
| // 2. Local build/ directory (development) | ||
| // 3. Local dist/ directory (legacy / manual builds) | ||
| // | ||
| // Usage with node:sqlite (Node >= 22.5): | ||
| // | ||
| // import { extensionPath } from '@anthropic/crsqlite'; | ||
| // import { extensionPath } from '@shards-lang/crsqlite'; | ||
| // import { DatabaseSync } from 'node:sqlite'; | ||
| // const db = new DatabaseSync(':memory:', { allowExtension: true }); | ||
| // db.loadExtension(extensionPath); | ||
| // | ||
| // Usage with better-sqlite3: | ||
| // | ||
| // import { extensionPath } from '@anthropic/crsqlite'; | ||
| // import { extensionPath } from '@shards-lang/crsqlite'; | ||
| // import Database from 'better-sqlite3'; | ||
| // const db = new Database(':memory:'); | ||
| // db.loadExtension(extensionPath); | ||
|
|
||
| import { fileURLToPath } from "node:url"; | ||
| import { createRequire } from "node:module"; | ||
| import { join, dirname } from "node:path"; | ||
| import { fileURLToPath } from "node:url"; | ||
| import { existsSync } from "node:fs"; | ||
|
|
||
| const __dirname = dirname(fileURLToPath(import.meta.url)); | ||
| export const extensionPath = join(__dirname, "dist", "crsqlite"); | ||
| const require = createRequire(import.meta.url); | ||
|
|
||
| const PLATFORM_PACKAGES = { | ||
| "linux-x64": "@shards-lang/crsqlite-linux-x64", | ||
| "darwin-arm64": "@shards-lang/crsqlite-darwin-arm64", | ||
| "darwin-x64": "@shards-lang/crsqlite-darwin-x64", | ||
| "win32-x64": "@shards-lang/crsqlite-win32-x64", | ||
| }; | ||
|
|
||
| function resolve() { | ||
| // 1. Try the platform-specific npm package. | ||
| const key = `${process.platform}-${process.arch}`; | ||
| const pkg = PLATFORM_PACKAGES[key]; | ||
| if (pkg) { | ||
| try { | ||
| return require(pkg).path; | ||
| } catch {} | ||
| } | ||
|
Comment on lines
+37
to
+45
|
||
|
|
||
| // 2. Local build/ (dev). | ||
| const buildPath = join(__dirname, "build", "crsqlite"); | ||
| if ( | ||
| existsSync(buildPath + ".so") || | ||
| existsSync(buildPath + ".dylib") || | ||
| existsSync(buildPath + ".dll") | ||
| ) { | ||
| return buildPath; | ||
| } | ||
|
|
||
| // 3. Local dist/ (legacy). | ||
| return join(__dirname, "dist", "crsqlite"); | ||
| } | ||
|
Comment on lines
+47
to
+59
|
||
|
|
||
| export const extensionPath = resolve(); | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| { | ||
| "name": "@anthropic/crsqlite", | ||
| "name": "@shards-lang/crsqlite", | ||
| "version": "0.1.0", | ||
| "description": "cr-sqlite loadable extension for Node.js — CRDT-based multi-master replication for SQLite", | ||
| "type": "module", | ||
|
|
@@ -15,8 +15,7 @@ | |
| "files": [ | ||
| "nodejs-helper.js", | ||
| "nodejs-helper.cjs", | ||
| "nodejs-helper.d.ts", | ||
| "dist/" | ||
| "nodejs-helper.d.ts" | ||
| ], | ||
| "scripts": { | ||
| "build": "cmake -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build && mkdir -p dist && cp build/crsqlite.* dist/", | ||
|
|
@@ -26,6 +25,12 @@ | |
| "engines": { | ||
| "node": ">=22.5.0" | ||
| }, | ||
| "optionalDependencies": { | ||
| "@shards-lang/crsqlite-linux-x64": "0.1.0", | ||
| "@shards-lang/crsqlite-darwin-arm64": "0.1.0", | ||
| "@shards-lang/crsqlite-darwin-x64": "0.1.0", | ||
| "@shards-lang/crsqlite-win32-x64": "0.1.0" | ||
| }, | ||
|
Comment on lines
15
to
+33
|
||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| const { join } = require("node:path"); | ||
| module.exports.path = join(__dirname, "crsqlite"); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "name": "@shards-lang/crsqlite-darwin-arm64", | ||
| "version": "0.1.0", | ||
| "description": "cr-sqlite prebuilt binary for macOS arm64 (Apple Silicon)", | ||
| "os": ["darwin"], | ||
| "cpu": ["arm64"], | ||
| "main": "index.js", | ||
| "files": ["index.js", "crsqlite.dylib"], | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/shards-lang/cr-sqlite.git", | ||
| "directory": "npm/crsqlite-darwin-arm64" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| const { join } = require("node:path"); | ||
| module.exports.path = join(__dirname, "crsqlite"); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "name": "@shards-lang/crsqlite-darwin-x64", | ||
| "version": "0.1.0", | ||
| "description": "cr-sqlite prebuilt binary for macOS x64 (Intel)", | ||
| "os": ["darwin"], | ||
| "cpu": ["x64"], | ||
| "main": "index.js", | ||
| "files": ["index.js", "crsqlite.dylib"], | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/shards-lang/cr-sqlite.git", | ||
| "directory": "npm/crsqlite-darwin-x64" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| const { join } = require("node:path"); | ||
| module.exports.path = join(__dirname, "crsqlite"); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "name": "@shards-lang/crsqlite-linux-x64", | ||
| "version": "0.1.0", | ||
| "description": "cr-sqlite prebuilt binary for Linux x64", | ||
| "os": ["linux"], | ||
| "cpu": ["x64"], | ||
| "main": "index.js", | ||
| "files": ["index.js", "crsqlite.so"], | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/shards-lang/cr-sqlite.git", | ||
| "directory": "npm/crsqlite-linux-x64" | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| const { join } = require("node:path"); | ||
| module.exports.path = join(__dirname, "crsqlite"); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| { | ||
| "name": "@shards-lang/crsqlite-win32-x64", | ||
| "version": "0.1.0", | ||
| "description": "cr-sqlite prebuilt binary for Windows x64", | ||
| "os": ["win32"], | ||
| "cpu": ["x64"], | ||
| "main": "index.js", | ||
| "files": ["index.js", "crsqlite.dll"], | ||
| "license": "MIT", | ||
| "repository": { | ||
| "type": "git", | ||
| "url": "https://github.com/shards-lang/cr-sqlite.git", | ||
| "directory": "npm/crsqlite-win32-x64" | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The workflow comment says the release tag must match
package.json, but there is no step enforcing this. Without a guard, it's easy to accidentally publish with mismatched versions (which also breaksoptionalDependenciesresolution). Consider adding a step that validatesGITHUB_REF_NAME(strip leadingv) equals the version incore/package.jsonbefore publishing.