Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
165 changes: 161 additions & 4 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
# Phase 6e adds publish-desktop.
# Phase 6f adds build-python-wheels + publish-python.
# Phase 6g adds build-nodejs-binaries + publish-nodejs.
# Phases 6h–6i add publish-wasm / publish-go as separate jobs
# to this same file.
# Phase 6h adds publish-wasm.
# Phase 6i adds publish-go.
#
# Design doc: docs/release-plan.md.
# One-time registry / branch-protection setup: docs/release-secrets.md.
Expand Down Expand Up @@ -127,6 +127,7 @@ jobs:
"sqlrite-desktop-v$V"
"sqlrite-py-v$V"
"sqlrite-node-v$V"
"sqlrite-wasm-v$V"
"v$V"
)
for tag in "${TAGS[@]}"; do
Expand Down Expand Up @@ -918,6 +919,161 @@ jobs:
See the umbrella release [v${{ needs.detect.outputs.version }}](../../releases/tag/v${{ needs.detect.outputs.version }}) for the full changelog.
generate_release_notes: true

# ---------------------------------------------------------------------------
# Step 3h: build the WASM package via wasm-pack and publish to
# npm as @joaoh82/sqlrite-wasm. (Phase 6h.)
#
# Single job — unlike the Python / Node SDKs there's no per-OS
# binary matrix, because WebAssembly is one universal artifact
# that runs on any wasm32-capable host (browsers, Deno, modern
# bundlers). One build, one upload.
#
# **Why scoped (`@joaoh82/sqlrite-wasm`) preemptively:** the
# unscoped `sqlrite-wasm` is currently free on npm but the
# similarity check that rejected `sqlrite` (vs `sqlite`) might
# also reject `sqlrite-wasm` (vs `sqlite-wasm` — distance 1).
# Going scoped from day one matches the Node SDK's
# `@joaoh82/sqlrite` decision and avoids the rename dance we
# did in PR #30. Free to revisit if the ecosystem demands an
# unscoped name.
#
# **Build target = `bundler`:** webpack/vite/rollup users get
# JS modules + .wasm without needing additional config. `web`
# / `nodejs` / `deno` targets can be added as siblings later
# if there's demand; one target per package is the simpler
# MVP shape.
#
# `--scope joaoh82` on `wasm-pack build` makes wasm-pack emit
# an auto-generated package.json with `name: "@joaoh82/sqlrite-wasm"`
# in the `pkg/` output directory — saves us from managing two
# package.json files (the auto-generated one and a hand-written
# override).
publish-wasm:
name: Publish WASM package to npm
needs: [detect, tag-all]
if: needs.detect.outputs.should_release == 'true'
runs-on: ubuntu-latest
environment: release
permissions:
# OIDC: required for npm trusted-publisher token exchange.
# Same flow proven in publish-nodejs after the v0.1.5–0.1.7
# debugging adventure.
id-token: write
contents: write
steps:
- uses: actions/checkout@v4

- uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-unknown-unknown

- uses: Swatinem/rust-cache@v2
with:
shared-key: publish-wasm
workspaces: 'sdk/wasm -> target'

# Install wasm-pack — the canonical tool for building +
# packaging Rust crates as npm-publishable WASM modules.
# `cargo binstall` would be faster than `cargo install`
# (downloads a prebuilt binary) but binstall isn't
# preinstalled on `ubuntu-latest`; the curl|sh installer
# does the same thing in one step without bootstrapping
# binstall first.
- name: Install wasm-pack
run: |
curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh

# See publish-nodejs for the long-form rationale of this
# whole setup-node + npm-upgrade dance. Short version:
# NO `registry-url:` (would force token-auth via .npmrc),
# then explicitly upgrade npm to 11.5+ so trusted
# publishing is supported.
- uses: actions/setup-node@v4
with:
node-version: '20'

- name: Upgrade npm to latest (need 11.5+ for trusted publishing)
run: npm install -g npm@latest

# Build the WASM package. `--target bundler` produces
# ES modules + .wasm that webpack/vite/rollup can consume
# directly. `--scope joaoh82` makes the auto-generated
# package.json's name `@joaoh82/sqlrite-wasm`. `--release`
# picks up the size-optimized profile from sdk/wasm/
# Cargo.toml ([profile.release] opt-level = "z" + LTO).
- name: Build WASM package
working-directory: sdk/wasm
run: |
wasm-pack build --release --target bundler --scope joaoh82
echo "--- generated pkg/ contents ---"
ls -la pkg/
echo "--- generated package.json ---"
cat pkg/package.json
echo "--- WASM binary size ---"
ls -la pkg/*.wasm

# OIDC env diagnostics — same defensive logging that paid
# off when publish-nodejs hit the trusted-publisher subject
# mismatch in v0.1.7.
- name: OIDC env diagnostics
working-directory: sdk/wasm/pkg
run: |
npm --version
echo "ACTIONS_ID_TOKEN_REQUEST_URL is set: ${ACTIONS_ID_TOKEN_REQUEST_URL:+yes}${ACTIONS_ID_TOKEN_REQUEST_URL:-NO}"
echo "ACTIONS_ID_TOKEN_REQUEST_TOKEN is set: ${ACTIONS_ID_TOKEN_REQUEST_TOKEN:+yes}${ACTIONS_ID_TOKEN_REQUEST_TOKEN:-NO}"
npm pack --dry-run

# Atomic OIDC publish. Same flag combo proven in
# publish-nodejs: `--provenance` to trigger OIDC code path,
# `--access public` because scoped packages default to
# private, `--loglevel verbose` to keep error logs
# diagnosable.
- name: Publish to npm
working-directory: sdk/wasm/pkg
run: npm publish --access public --provenance --loglevel verbose

- name: GitHub Release
uses: softprops/action-gh-release@v2
with:
tag_name: sqlrite-wasm-v${{ needs.detect.outputs.version }}
name: WASM v${{ needs.detect.outputs.version }}
body: |
Published to npm: https://www.npmjs.com/package/@joaoh82/sqlrite-wasm/v/${{ needs.detect.outputs.version }}

```bash
npm install @joaoh82/sqlrite-wasm@${{ needs.detect.outputs.version }}
```

```javascript
// Bundler target — works with webpack, vite, rollup, parcel
import init, { Database } from '@joaoh82/sqlrite-wasm';

await init();
const db = new Database();
db.exec("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT)");
db.exec("INSERT INTO users (name) VALUES ('alice')");
const rows = db.query("SELECT id, name FROM users");
// → [{ id: 1, name: 'alice' }]
```

**What's in the package:**
- `sqlrite_wasm_bg.wasm` — the WebAssembly engine binary
- `sqlrite_wasm.js` — auto-generated JS glue (wasm-bindgen)
- `sqlrite_wasm.d.ts` — TypeScript types
- `package.json` — bundler-target metadata

**Build target:** `bundler` (webpack/vite/rollup-friendly).
For `web` / `nodejs` / `deno` targets, build from source via `wasm-pack build sdk/wasm --target <target>`.

Verify package provenance:
```bash
npm audit signatures
```

See the umbrella release [v${{ needs.detect.outputs.version }}](../../releases/tag/v${{ needs.detect.outputs.version }}) for the full changelog.
files: sdk/wasm/pkg/*.wasm
generate_release_notes: true

# ---------------------------------------------------------------------------
# Step 4: create the umbrella GitHub Release. Runs after all
# publish-* jobs succeed. Uses GitHub's native auto-generated
Expand All @@ -926,7 +1082,7 @@ jobs:
# config if we add one later.
finalize:
name: Finalize umbrella release
needs: [detect, publish-crate, publish-ffi, publish-desktop, publish-python, publish-nodejs]
needs: [detect, publish-crate, publish-ffi, publish-desktop, publish-python, publish-nodejs, publish-wasm]
if: needs.detect.outputs.should_release == 'true'
runs-on: ubuntu-latest
steps:
Expand All @@ -949,8 +1105,9 @@ jobs:
- 🖥️ [Desktop](../../releases/tag/sqlrite-desktop-v${{ needs.detect.outputs.version }}) — unsigned installers for Linux (AppImage + deb), macOS (dmg aarch64), Windows (msi)
- 🐍 [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
- 🟢 [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
- 🌐 [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

_WASM / Go SDKs land as their publish jobs come online (Phases 6h–6i)._
_Go SDK lands as its publish job comes online (Phase 6i)._

---

Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,12 +224,12 @@ Lockstep versioning — one dispatch bumps every product to the same `vX.Y.Z`. T

- [x] **6a — Bump script**: `scripts/bump-version.sh` rewrites the version string in ten manifests (7 TOML, 3 JSON) in a single pass; semver-validated, idempotent, cross-platform (BSD + GNU sed). Runnable locally for rehearsing a release: `./scripts/bump-version.sh 0.2.0 && cargo build && git diff`.
- [x] **6b — CI**: `.github/workflows/ci.yml` runs on every PR + push to main. Seven parallel jobs: `rust-build-and-test` (Linux/macOS/Windows × cargo build + test), `rust-lint` (fmt + clippy + doc), `python-sdk` (Linux/macOS/Windows × maturin develop + pytest in a venv), `nodejs-sdk` (Linux/macOS/Windows × napi build + node --test), `go-sdk` (Linux/macOS × cargo build sqlrite-ffi + go test), `wasm-build` (wasm-pack + size report), `desktop-build` (npm ci + Tauri Rust compile). Cargo / npm / pip caching for fast PR turnaround.
- [x] **6c — Trusted publisher setup + branch protection runbook**: [`docs/release-secrets.md`](docs/release-secrets.md) captures the one-time web-UI setup — crates.io token in the `release` environment, OIDC trusted publishers on PyPI (`sqlrite`) and npm (`@joaoh82/sqlrite` + `sqlrite-wasm` — Node binding is scoped because npm's similarity check rejects the unscoped name against `sqlite`/`sqlite3`), GitHub `release` environment with required reviewer, branch protection on `main` requiring 14 CI jobs + 1 review. No code changes — executable as-is, ready to run through in the GitHub + registry UIs.
- [x] **6c — Trusted publisher setup + branch protection runbook**: [`docs/release-secrets.md`](docs/release-secrets.md) captures the one-time web-UI setup — crates.io token in the `release` environment, OIDC trusted publishers on PyPI (`sqlrite`) and npm (`@joaoh82/sqlrite` + `@joaoh82/sqlrite-wasm` — both scoped because npm's similarity check rejects the unscoped names against `sqlite`/`sqlite3`/`sqlite-wasm`), GitHub `release` environment with required reviewer, branch protection on `main` requiring 14 CI jobs + 1 review. No code changes — executable as-is, ready to run through in the GitHub + registry UIs.
- [x] **6d — Release PR + skeleton publish**: two workflows under `.github/workflows/`. `release-pr.yml` (manual dispatch with version input → bump-version.sh → PR), `release.yml` (fires on `release: v<semver>` merge commit → `tag-all` + `publish-crate` + `publish-ffi` matrix [linux x86_64/aarch64, macOS aarch64, windows x86_64] + umbrella release). Idempotent tag creation so "Re-run failed jobs" works after partial failures. `cargo publish` gated by the `release` environment's required-reviewer rule. First canary: `v0.1.1`.
- [ ] **6e — Desktop publish**: add `publish-desktop` to `release.yml` — Tauri build matrix → unsigned `.AppImage` / `.deb` / `.dmg` / `.msi` → GitHub Release
- [ ] **6f — Python SDK publish**: `maturin-action` → abi3 wheels for manylinux x86_64/aarch64 + macOS universal + Windows x86_64 → PyPI via OIDC
- [ ] **6g — Node.js SDK publish**: `@napi-rs/cli` → `.node` binaries per platform → npm via OIDC
- [ ] **6h — WASM publish**: `wasm-pack publish` → `sqlrite-wasm` on npm
- [x] **6h — WASM publish**: `wasm-pack build --target bundler --scope joaoh82` + `npm publish --provenance` (OIDC) → `@joaoh82/sqlrite-wasm` on npm. Single job, no matrix (WebAssembly is universal). `.wasm` also attached to the `sqlrite-wasm-v<V>` GitHub Release.
- [ ] **6i — Go SDK publish**: `sdk/go/vX.Y.Z` git tag + attach FFI tarballs to the Go GitHub Release for `go get` users who want prebuilt `libsqlrite_c`

**Phase 6.1 — Code signing** *(follow-up)*
Expand Down
6 changes: 3 additions & 3 deletions docs/embedding.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ Full API tour: [`sdk/go/README.md`](../sdk/go/README.md); runnable walkthrough:
`sdk/wasm/` — `wasm-bindgen` compiles the Rust engine directly to `wasm32-unknown-unknown`. The whole database runs in a browser tab:

```js
import init, { Database } from 'sqlrite-wasm';
import init, { Database } from '@joaoh82/sqlrite-wasm';
await init();

const db = new Database();
Expand All @@ -201,7 +201,7 @@ const rows = db.query("SELECT id, name FROM users");

**In-memory only** in the MVP — file-backed mode needs OS file locks and a `-wal` sidecar that don't exist in a tab's sandbox. OPFS-backed persistence is a natural follow-up.

Build locally via `wasm-pack build --target web --release` (or `bundler` / `nodejs`). Phase 6e publishes `sqlrite-wasm` to npm via `wasm-pack publish` on `v*` tag push.
Build locally via `wasm-pack build --target web --release` (or `bundler` / `nodejs`). Phase 6h publishes `@joaoh82/sqlrite-wasm` (bundler target) to npm via `wasm-pack build` + `npm publish` (OIDC trusted publisher) on every release.

The root engine crate is feature-gated (`cli` for rustyline/clap/env_logger; `file-locks` for fs2) so `default-features = false` strips out everything that wouldn't compile on `wasm32-unknown-unknown`.

Expand All @@ -217,7 +217,7 @@ Phase 6 lands GitHub Actions CI + release automation:

- **crates.io** — `sqlrite-engine` crate (published under a different name from the `sqlrite` lib target because the short name was already taken; users `cargo add sqlrite-engine` but still write `use sqlrite::…`)
- **PyPI** — `sqlrite` wheels (manylinux x86_64/aarch64, macOS universal, Windows x86_64)
- **npm** — `@joaoh82/sqlrite` (Node) + `sqlrite-wasm` (browser) packages
- **npm** — `@joaoh82/sqlrite` (Node) + `@joaoh82/sqlrite-wasm` (browser) packages
- **Go modules** — `sdk/go/v*` git tags
- **GitHub Releases** — Tauri desktop builds + C FFI prebuilt libraries

Expand Down
7 changes: 4 additions & 3 deletions docs/release-plan.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ GitHub Releases by product ("show me every Python release").
| Python SDK | `sqlrite-py-vX.Y.Z` | PyPI + GitHub Release |
| Node.js SDK | `sqlrite-node-vX.Y.Z` | npm (`@joaoh82/sqlrite`) + GitHub Release |
| Go SDK | `sdk/go/vX.Y.Z` | Git tag (no registry) + GitHub Release assets |
| WASM | `sqlrite-wasm-vX.Y.Z` | npm (`sqlrite-wasm`) + GitHub Release |
| WASM | `sqlrite-wasm-vX.Y.Z` | npm (`@joaoh82/sqlrite-wasm`) + GitHub Release |
| Desktop app | `sqlrite-desktop-vX.Y.Z` | GitHub Release (unsigned installers) |
| **Meta** | `vX.Y.Z` | GitHub Release (links to the other seven; acts as the "this was release 0.2.0" anchor) |

Expand Down Expand Up @@ -290,8 +290,9 @@ from now.
TestPyPI (for dry-runs) if we decide we want that later.
3. **npm trusted publishing** — available via npm's newer "OIDC
trusted publishing" system. One-time config on npm's web UI
for the `sqlrite` and `sqlrite-wasm` packages. No `NPM_TOKEN`
needed.
for the `@joaoh82/sqlrite` and `@joaoh82/sqlrite-wasm`
packages. No `NPM_TOKEN` needed (after a one-time placeholder
publish per `docs/release-secrets.md` §3a).
4. **GitHub Environments** — create one called `release` in repo
settings → Environments. Add `joaoh82` as a required reviewer
on the `release` environment. The publish jobs reference
Expand Down
Loading
Loading