Skip to content

Commit 83eae48

Browse files
joaoh82claude
andauthored
feat(examples): SQLR-64 publish sqlrite-notes example to npm (#144)
Lets users `npx sqlrite-notes init <dir>` on a fresh machine — the parent ticket's (SQLR-40) DoD that the shipped example didn't meet because it still required cloning the repo. - `examples/nodejs-notes/package.json`: drop `private: true`; bump to 0.10.1 (lockstep with engine); bump `@joaoh82/sqlrite` pin to ^0.10.1; add `files` whitelist + `publishConfig` (public, OIDC provenance). - `examples/nodejs-notes/src/cli.mjs`: read VERSION from package.json so the lockstep bump propagates automatically. - `examples/nodejs-notes/README.md`: Install / Run sections lead with `npx sqlrite-notes init <dir>`; clone path kept under Development. - `scripts/bump-version.sh`: add the example's package.json to JSON_FILES + new NPM_DEP_PIN_FILES sweep that rewrites the `@joaoh82/sqlrite` caret pin in lockstep; verification block extended to catch missed pins. - `.github/workflows/release.yml`: new `publish-notes-example` job (mirrors publish-nodejs — OIDC trusted publishing, sigstore provenance, `--access public`); `sqlrite-notes-v$V` tag added to tag-all; wired into finalize.needs + umbrella release body. - `docs/release-plan.md`: product-tag table row + lockstep note; bumped manifest list to include the example's package.json. - `docs/release-secrets.md`: §3 retitled "three packages"; new §3c documents the placeholder-publish + trusted-publisher bootstrap for unscoped `sqlrite-notes` (with `@joaoh82/sqlrite-notes` fallback if the registry rejects the unscoped name). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 7a314c5 commit 83eae48

8 files changed

Lines changed: 262 additions & 44 deletions

File tree

.github/workflows/release.yml

Lines changed: 105 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ jobs:
131131
"sqlrite-desktop-v$V"
132132
"sqlrite-py-v$V"
133133
"sqlrite-node-v$V"
134+
"sqlrite-notes-v$V"
134135
"sqlrite-wasm-v$V"
135136
"sdk/go/v$V"
136137
"v$V"
@@ -1154,6 +1155,108 @@ jobs:
11541155
See the umbrella release [v${{ needs.detect.outputs.version }}](../../releases/tag/v${{ needs.detect.outputs.version }}) for the full changelog.
11551156
generate_release_notes: true
11561157

1158+
# ---------------------------------------------------------------------------
1159+
# Step 3g': publish the `sqlrite-notes` example as a pure-JS npm
1160+
# package so users can `npx sqlrite-notes init <dir>` on a fresh
1161+
# machine without cloning the repo. (SQLR-64, follow-up from SQLR-40.)
1162+
#
1163+
# The package itself ships no binaries — it's a thin CLI on top of
1164+
# the `@joaoh82/sqlrite` N-API package (which carries the prebuilt
1165+
# `.node` binaries via the platform-dispatch shim) and spawns
1166+
# `sqlrite-mcp` as a subprocess for the read side. The Node bits
1167+
# are platform-agnostic JS modules, so this job is a single ubuntu
1168+
# cell instead of the publish-nodejs build matrix.
1169+
#
1170+
# `needs: publish-nodejs` is load-bearing: the example's
1171+
# `@joaoh82/sqlrite` dep pin resolves against the version that
1172+
# publish-nodejs just put on npm. Without that ordering, `npx
1173+
# sqlrite-notes@<new>` would resolve a slightly-stale engine on
1174+
# the first install after release (caret pin floats up *eventually*
1175+
# but the npm cache will have served the old one for minutes).
1176+
#
1177+
# Package name: **unscoped `sqlrite-notes`** (per ticket). The
1178+
# similarity rejection that hit `sqlrite` (vs `sqlite`) doesn't
1179+
# apply here — `notes` isn't a confusable suffix. If the registry
1180+
# ever rejects this on a future bootstrap, fall back to
1181+
# `@joaoh82/sqlrite-notes` and update both `package.json` and
1182+
# `docs/release-secrets.md`'s trusted-publisher section.
1183+
#
1184+
# OIDC trusted-publisher setup mirrors publish-nodejs verbatim —
1185+
# see that job's comment block for the long-form rationale on why
1186+
# `registry-url` is omitted, why we force-upgrade npm to 11.5+, and
1187+
# why `--provenance --access public --loglevel verbose` is the
1188+
# canonical flag combo.
1189+
publish-notes-example:
1190+
name: Publish sqlrite-notes example to npm
1191+
needs: [detect, tag-all, publish-nodejs]
1192+
if: needs.detect.outputs.should_release == 'true'
1193+
runs-on: ubuntu-latest
1194+
environment: release
1195+
permissions:
1196+
# OIDC for npm trusted publisher + provenance signing.
1197+
id-token: write
1198+
# For softprops/action-gh-release at the end.
1199+
contents: write
1200+
steps:
1201+
- uses: actions/checkout@v4
1202+
1203+
# Same OIDC dance as publish-nodejs — see that job's comment
1204+
# block for why we deliberately do NOT set `registry-url:`.
1205+
- uses: actions/setup-node@v4
1206+
with:
1207+
node-version: '20'
1208+
1209+
- name: Upgrade npm to latest (need 11.5+ for trusted publishing)
1210+
run: npm install -g npm@latest
1211+
1212+
- name: List publish payload + OIDC env diagnostics
1213+
working-directory: examples/nodejs-notes
1214+
run: |
1215+
ls -la
1216+
echo "---"
1217+
npm --version
1218+
echo "---"
1219+
echo "ACTIONS_ID_TOKEN_REQUEST_URL is set: ${ACTIONS_ID_TOKEN_REQUEST_URL:+yes}${ACTIONS_ID_TOKEN_REQUEST_URL:-NO}"
1220+
echo "ACTIONS_ID_TOKEN_REQUEST_TOKEN is set: ${ACTIONS_ID_TOKEN_REQUEST_TOKEN:+yes}${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-NO}"
1221+
echo "---"
1222+
# `npm pack --dry-run` prints exactly what will end up in
1223+
# the tarball. The `files` whitelist in package.json should
1224+
# produce: bin/sqlrite-notes.mjs, src/*.mjs, README.md,
1225+
# package.json — nothing else (no test fixtures, no
1226+
# node_modules).
1227+
npm pack --dry-run
1228+
1229+
- name: Publish to npm
1230+
working-directory: examples/nodejs-notes
1231+
run: npm publish --access public --provenance --loglevel verbose
1232+
1233+
- name: GitHub Release
1234+
uses: softprops/action-gh-release@v2
1235+
with:
1236+
tag_name: sqlrite-notes-v${{ needs.detect.outputs.version }}
1237+
name: sqlrite-notes example v${{ needs.detect.outputs.version }}
1238+
body: |
1239+
Published to npm: https://www.npmjs.com/package/sqlrite-notes/v/${{ needs.detect.outputs.version }}
1240+
1241+
```bash
1242+
# Ingest a folder of markdown notes into a SQLRite database
1243+
# — no clone, no Rust toolchain, no env setup beyond an
1244+
# optional embedding API key.
1245+
npx sqlrite-notes@${{ needs.detect.outputs.version }} init ~/Documents/notes
1246+
```
1247+
1248+
The example uses `@joaoh82/sqlrite@^${{ needs.detect.outputs.version }}` for storage + retrieval (HNSW + BM25) and spawns [`sqlrite-mcp`](../../releases/tag/sqlrite-mcp-v${{ needs.detect.outputs.version }}) as a subprocess to expose the database to Claude Desktop / any MCP client. Install `sqlrite-mcp` separately — `cargo install sqlrite-mcp` or a prebuilt binary from the MCP release.
1249+
1250+
Verify package provenance:
1251+
```bash
1252+
npm audit signatures
1253+
```
1254+
1255+
Full docs: [`examples/nodejs-notes/README.md`](https://github.com/joaoh82/rust_sqlite/blob/main/examples/nodejs-notes/README.md).
1256+
1257+
See the umbrella release [v${{ needs.detect.outputs.version }}](../../releases/tag/v${{ needs.detect.outputs.version }}) for the full changelog.
1258+
generate_release_notes: true
1259+
11571260
# ---------------------------------------------------------------------------
11581261
# Step 3h: build the WASM package via wasm-pack and publish to
11591262
# npm as @joaoh82/sqlrite-wasm. (Phase 6h.)
@@ -1480,7 +1583,7 @@ jobs:
14801583
# config if we add one later.
14811584
finalize:
14821585
name: Finalize umbrella release
1483-
needs: [detect, publish-crate, publish-ask, publish-mcp, build-mcp-binaries, publish-ffi, publish-desktop, publish-python, publish-nodejs, publish-wasm, publish-go]
1586+
needs: [detect, publish-crate, publish-ask, publish-mcp, build-mcp-binaries, publish-ffi, publish-desktop, publish-python, publish-nodejs, publish-notes-example, publish-wasm, publish-go]
14841587
if: needs.detect.outputs.should_release == 'true'
14851588
runs-on: ubuntu-latest
14861589
steps:
@@ -1504,6 +1607,7 @@ jobs:
15041607
- 🖥️ [Desktop](../../releases/tag/sqlrite-desktop-v${{ needs.detect.outputs.version }}) — unsigned installers for Linux (AppImage + deb), macOS (dmg aarch64), Windows (msi)
15051608
- 🐍 [Python](../../releases/tag/sqlrite-py-v${{ needs.detect.outputs.version }}) → [PyPI](https://pypi.org/project/sqlrite/${{ needs.detect.outputs.version }}/) — abi3-py38 wheels for Linux x86_64/aarch64, macOS aarch64, Windows x86_64 + sdist
15061609
- 🟢 [Node.js](../../releases/tag/sqlrite-node-v${{ needs.detect.outputs.version }}) → [npm](https://www.npmjs.com/package/@joaoh82/sqlrite/v/${{ needs.detect.outputs.version }}) — N-API bindings with prebuilt `.node` binaries for Linux x86_64/aarch64, macOS aarch64, Windows x86_64
1610+
- 📝 [`sqlrite-notes` example](../../releases/tag/sqlrite-notes-v${{ needs.detect.outputs.version }}) → [npm](https://www.npmjs.com/package/sqlrite-notes/v/${{ needs.detect.outputs.version }}) — `npx sqlrite-notes init <dir>` ingests a folder of markdown notes into a SQLRite DB and exposes it to Claude Desktop / any MCP client
15071611
- 🌐 [WASM](../../releases/tag/sqlrite-wasm-v${{ needs.detect.outputs.version }}) → [npm](https://www.npmjs.com/package/@joaoh82/sqlrite-wasm/v/${{ needs.detect.outputs.version }}) — browser/bundler-target WebAssembly build via wasm-pack
15081612
- 🐹 [Go SDK](../../releases/tag/sdk%2Fgo%2Fv${{ needs.detect.outputs.version }}) → `go get github.com/joaoh82/rust_sqlite/sdk/go@v${{ needs.detect.outputs.version }}` — `database/sql` driver via cgo against `libsqlrite_c`
15091613

docs/release-plan.md

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,17 +76,25 @@ GitHub Releases by product ("show me every Python release").
7676
| `sqlrite-mcp` | `sqlrite-mcp-vX.Y.Z` | crates.io + GitHub Release (per-platform binary tarballs) |
7777
| Python SDK | `sqlrite-py-vX.Y.Z` | PyPI + GitHub Release |
7878
| Node.js SDK | `sqlrite-node-vX.Y.Z` | npm (`@joaoh82/sqlrite`) + GitHub Release |
79+
| `sqlrite-notes` example | `sqlrite-notes-vX.Y.Z` | npm (`sqlrite-notes`) + GitHub Release |
7980
| Go SDK | `sdk/go/vX.Y.Z` | Git tag (no registry) + GitHub Release assets |
8081
| WASM | `sqlrite-wasm-vX.Y.Z` | npm (`@joaoh82/sqlrite-wasm`) + GitHub Release |
8182
| Desktop app | `sqlrite-desktop-vX.Y.Z` | GitHub Release (unsigned installers) |
82-
| **Meta** | `vX.Y.Z` | GitHub Release (links to the other nine; acts as the "this was release 0.2.0" anchor) |
83+
| **Meta** | `vX.Y.Z` | GitHub Release (links to the other ten; acts as the "this was release 0.2.0" anchor) |
8384

84-
All ten tags point at the same commit — the merge commit of the
85+
All eleven tags point at the same commit — the merge commit of the
8586
release PR. The meta tag is the umbrella release users can link to
86-
in announcements; the nine per-product tags are for tooling
87+
in announcements; the ten per-product tags are for tooling
8788
(crates.io, Go module proxy, npm dist-tags, etc.) that expects a
8889
specific format.
8990

91+
> **`sqlrite-notes` joined the lockstep wave in v0.10.2 (SQLR-64).** Pure-JS
92+
> CLI on top of `@joaoh82/sqlrite` + `sqlrite-mcp`; published unscoped on
93+
> npm so `npx sqlrite-notes init <dir>` works on a fresh machine.
94+
> `publish-notes-example` runs after `publish-nodejs` because the example
95+
> resolves its `@joaoh82/sqlrite` pin against the version that
96+
> publish-nodejs just put on npm.
97+
9098
> **`sqlrite-ask` joined the lockstep wave in v0.1.17 (Phase 7g.1).** Gets
9199
> its own tag and crates.io publish but ships in lockstep with everything
92100
> else — same version every wave. `publish-ask` runs after `publish-crate`
@@ -120,6 +128,7 @@ matching new value:
120128
| `desktop/src-tauri/Cargo.toml` | `[package].version` |
121129
| `desktop/src-tauri/tauri.conf.json` | `"version"` (top-level — Tauri reads this for installer names) |
122130
| `desktop/package.json` | `"version"` (top-level) |
131+
| `examples/nodejs-notes/package.json` | `"version"` + `"dependencies"."@joaoh82/sqlrite"` pin (caret) |
123132
| `Cargo.lock` | auto-updated by `cargo build` after the above |
124133

125134
**Go** is not in this list — `sdk/go/go.mod` has no version field.

docs/release-secrets.md

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,14 @@ release, status flips to "active".
102102

103103
---
104104

105-
## 3. npm trusted publishers (two packages)
105+
## 3. npm trusted publishers (three packages)
106106

107-
**Why two:** we publish `@joaoh82/sqlrite` (Node.js bindings from
108-
`sdk/nodejs/`) and `@joaoh82/sqlrite-wasm` (browser bindings from
109-
`sdk/wasm/`) as separate npm packages. Each needs its own
110-
trusted-publisher record.
107+
**Why three:** we publish `@joaoh82/sqlrite` (Node.js bindings from
108+
`sdk/nodejs/`), `@joaoh82/sqlrite-wasm` (browser bindings from
109+
`sdk/wasm/`), and `sqlrite-notes` (the chat-with-your-notes example
110+
from `examples/nodejs-notes/`) as separate npm packages. Each needs
111+
its own trusted-publisher record — set up §3a + §3b for the first
112+
two scoped packages and §3c for the unscoped example.
111113

112114
**Why both are scoped:** npm's registry rejects unscoped names
113115
that are too similar to existing popular packages — `sqlrite` is
@@ -184,6 +186,53 @@ claims". Burned us once on v0.1.7 (typo'd repo name in the
184186
form); kept the form field reference here so the next person
185187
doesn't have to re-debug.
186188

189+
### 3c. `sqlrite-notes` example — third npm package (SQLR-64)
190+
191+
The `examples/nodejs-notes/` example ships as a third npm package
192+
so users can `npx sqlrite-notes init <dir>` on a fresh machine.
193+
The `publish-notes-example` job in `release.yml` handles it
194+
end-to-end with the same OIDC pattern as `publish-nodejs`.
195+
196+
**Why unscoped:** unlike `sqlrite` (rejected as too similar to
197+
`sqlite`), `sqlrite-notes` is far enough from any existing npm
198+
package that the similarity check shouldn't fire. If the
199+
placeholder publish in step 1 below is rejected, fall back to the
200+
scoped form `@joaoh82/sqlrite-notes` — update both
201+
`examples/nodejs-notes/package.json`'s `name` field and the
202+
`npm publish` step / GitHub Release body in `release.yml`.
203+
204+
**Bootstrap (one-time, with your local credentials):**
205+
206+
```bash
207+
mkdir /tmp/sqlrite-notes-placeholder && cd /tmp/sqlrite-notes-placeholder
208+
cat > package.json <<'JSON'
209+
{
210+
"name": "sqlrite-notes",
211+
"version": "0.0.0",
212+
"description": "Placeholder — real package ships from rust_sqlite CI",
213+
"license": "MIT"
214+
}
215+
JSON
216+
npm login # if not already
217+
npm publish
218+
```
219+
220+
If the unscoped name is rejected, retry with `@joaoh82/sqlrite-notes`
221+
and amend the repo per the note above.
222+
223+
**Trusted publisher:**
224+
225+
1. Go to <https://www.npmjs.com/package/sqlrite-notes/access> (or
226+
`…/package/@joaoh82/sqlrite-notes/access` if you fell back to
227+
the scoped name).
228+
2. **Add publisher** with the same field values as `@joaoh82/sqlrite`
229+
above — Organization `joaoh82`, Repository `rust_sqlite`,
230+
Workflow filename `release.yml`, Environment `release`.
231+
3. Save.
232+
233+
**Verify**: status flips from "pending" to "active" after the
234+
first successful CI publish.
235+
187236
---
188237

189238
## 4. GitHub `release` environment
@@ -286,10 +335,10 @@ Run through this once everything above is done:
286335
- [ ] PyPI trusted-publisher page shows `rust_sqlite` /
287336
`release.yml` / `release` pending for the `sqlrite`
288337
project.
289-
- [ ] npm trusted-publisher page shows the same for both
290-
`@joaoh82/sqlrite` and `@joaoh82/sqlrite-wasm` (assuming
291-
the placeholders are published per §3a — if not, section
292-
3a applies).
338+
- [ ] npm trusted-publisher page shows the same for all three of
339+
`@joaoh82/sqlrite`, `@joaoh82/sqlrite-wasm`, and
340+
`sqlrite-notes` (assuming the placeholders are published per
341+
§3a / §3c — if not, those sections apply).
293342
- [ ] Branch protection on `main` requires 14 status checks + 1
294343
review.
295344
- [ ] Open a dummy PR — the "Merge" button is greyed out until

examples/nodejs-notes/README.md

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,22 +48,17 @@ straight from the inverted index).
4848

4949
## Install
5050

51-
The example lives inside the SQLRite monorepo for now (the umbrella
52-
ticket SQLR-38 will lift it into its own repo once we've shipped a
53-
few more).
54-
5551
```bash
56-
git clone https://github.com/joaoh82/rust_sqlite
57-
cd rust_sqlite/examples/nodejs-notes
58-
npm install
52+
npx sqlrite-notes init ~/Documents/notes
5953
```
6054

61-
`npm install` pulls **`@joaoh82/sqlrite`** (pinned to `^0.10.0`) with
62-
prebuilt napi-rs binaries for macOS-arm64, Linux x64/arm64, and
63-
Windows x64 — no Rust toolchain required for the Node side.
55+
That's it for the Node side — `npx` downloads `sqlrite-notes`, which
56+
pulls **`@joaoh82/sqlrite`** with prebuilt napi-rs binaries for
57+
macOS-arm64, Linux x64/arm64, and Windows x64. No clone, no
58+
`npm install`, no Rust toolchain required.
6459

65-
`sqlrite-mcp` is a separate Rust binary. Install it once, anywhere
66-
on your `PATH`:
60+
`sqlrite-mcp` is a separate Rust binary used by the `serve`
61+
subcommand. Install it once, anywhere on your `PATH`:
6762

6863
```bash
6964
# from crates.io (~30s):
@@ -80,19 +75,24 @@ absolute path — `sqlrite-notes serve` will pick it up.
8075

8176
```bash
8277
# 1. Ingest a folder of markdown into a notes.sqlrite database.
83-
node bin/sqlrite-notes.mjs init ~/Documents/notes
78+
npx sqlrite-notes init ~/Documents/notes
8479

8580
# 2. Confirm it works locally — same retrieval shape Claude will see.
86-
node bin/sqlrite-notes.mjs search "what did I learn about CRDTs?"
81+
npx sqlrite-notes search "what did I learn about CRDTs?"
8782

8883
# 3. Wire up Claude Desktop using the snippet printed by `init`
89-
# (also available any time via `sqlrite-notes config`).
84+
# (also available any time via `npx sqlrite-notes config`).
9085

9186
# 4. Open Claude Desktop. The sqlrite-mcp tools appear in the
9287
# tool picker — `bm25_search`, `vector_search`, `query`, `ask`,
9388
# plus `list_tables` / `describe_table` / `schema_dump`.
9489
```
9590

91+
> **Pinning a version.** `npx sqlrite-notes` pulls the latest; pass
92+
> `npx sqlrite-notes@0.10.1 …` (or whichever tag) to lock to a
93+
> specific release. The package ships in lockstep with the SQLRite
94+
> engine, so the version number matches `@joaoh82/sqlrite`'s.
95+
9696
Once you've added the snippet to `claude_desktop_config.json` and
9797
restarted Claude Desktop, run a chat like:
9898

@@ -275,9 +275,16 @@ Default is 0.5.
275275

276276
## Development
277277

278+
Hacking on the example itself — running tests, editing the CLI,
279+
iterating against a local engine binding — uses the clone path:
280+
278281
```bash
282+
git clone https://github.com/joaoh82/rust_sqlite
283+
cd rust_sqlite/examples/nodejs-notes
279284
npm install
280285
npm test # offline; runs all 40 unit + integration tests
286+
# Iterate against the local sources:
287+
node bin/sqlrite-notes.mjs init ~/Documents/notes
281288
```
282289

283290
The test suite uses `node:test` and exercises:
@@ -297,7 +304,7 @@ they skip cleanly (with a message) if it isn't.
297304

298305
```
299306
examples/nodejs-notes/
300-
├── package.json # @joaoh82/sqlrite pinned to ^0.10.0
307+
├── package.json # @joaoh82/sqlrite pinned in lockstep with the engine release
301308
├── README.md # this file
302309
├── bin/
303310
│ └── sqlrite-notes.mjs # entry — calls src/cli.mjs

examples/nodejs-notes/package-lock.json

Lines changed: 6 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)