@webstir-io/webstir-backend 0.1.15 → 0.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -79
- package/dist/add.d.ts +59 -0
- package/dist/add.js +626 -0
- package/dist/build/artifacts.d.ts +115 -1
- package/dist/build/artifacts.js +4 -4
- package/dist/build/entries.js +1 -1
- package/dist/build/pipeline.d.ts +33 -1
- package/dist/build/pipeline.js +307 -65
- package/dist/cache/diff.js +9 -8
- package/dist/cache/reporters.js +1 -1
- package/dist/deploy-cli.d.ts +2 -0
- package/dist/deploy-cli.js +86 -0
- package/dist/diagnostics/summary.js +2 -2
- package/dist/index.d.ts +6 -0
- package/dist/index.js +4 -0
- package/dist/manifest/pipeline.js +103 -32
- package/dist/provider.js +35 -17
- package/dist/runtime/bun.d.ts +51 -0
- package/dist/runtime/bun.js +499 -0
- package/dist/runtime/core.d.ts +141 -0
- package/dist/runtime/core.js +316 -0
- package/dist/runtime/deploy-backend.d.ts +20 -0
- package/dist/runtime/deploy-backend.js +175 -0
- package/dist/runtime/deploy-shared.d.ts +43 -0
- package/dist/runtime/deploy-shared.js +75 -0
- package/dist/runtime/deploy-static.d.ts +2 -0
- package/dist/runtime/deploy-static.js +161 -0
- package/dist/runtime/deploy.d.ts +3 -0
- package/dist/runtime/deploy.js +91 -0
- package/dist/runtime/forms.d.ts +73 -0
- package/dist/runtime/forms.js +236 -0
- package/dist/runtime/request-hooks.d.ts +47 -0
- package/dist/runtime/request-hooks.js +102 -0
- package/dist/runtime/session-metadata.d.ts +13 -0
- package/dist/runtime/session-metadata.js +98 -0
- package/dist/runtime/session-runtime.d.ts +28 -0
- package/dist/runtime/session-runtime.js +180 -0
- package/dist/runtime/session.d.ts +83 -0
- package/dist/runtime/session.js +396 -0
- package/dist/runtime/views.d.ts +74 -0
- package/dist/runtime/views.js +221 -0
- package/dist/scaffold/assets.js +25 -21
- package/dist/testing/context.js +1 -1
- package/dist/testing/index.d.ts +1 -1
- package/dist/testing/index.js +100 -56
- package/dist/utils/bun.d.ts +2 -0
- package/dist/utils/bun.js +13 -0
- package/dist/watch.d.ts +13 -1
- package/dist/watch.js +345 -97
- package/dist/workspace.d.ts +8 -0
- package/dist/workspace.js +44 -3
- package/package.json +49 -14
- package/scripts/publish.sh +2 -92
- package/scripts/smoke.mjs +282 -107
- package/scripts/update-contract.sh +12 -10
- package/src/add.ts +964 -0
- package/src/build/artifacts.ts +49 -46
- package/src/build/entries.ts +12 -12
- package/src/build/pipeline.ts +779 -403
- package/src/cache/diff.ts +111 -105
- package/src/cache/reporters.ts +26 -26
- package/src/deploy-cli.ts +111 -0
- package/src/diagnostics/summary.ts +28 -22
- package/src/index.ts +11 -0
- package/src/manifest/pipeline.ts +328 -215
- package/src/provider.ts +115 -98
- package/src/runtime/bun.ts +793 -0
- package/src/runtime/core.ts +598 -0
- package/src/runtime/deploy-backend.ts +239 -0
- package/src/runtime/deploy-shared.ts +136 -0
- package/src/runtime/deploy-static.ts +191 -0
- package/src/runtime/deploy.ts +143 -0
- package/src/runtime/forms.ts +364 -0
- package/src/runtime/request-hooks.ts +165 -0
- package/src/runtime/session-metadata.ts +135 -0
- package/src/runtime/session-runtime.ts +267 -0
- package/src/runtime/session.ts +642 -0
- package/src/runtime/views.ts +385 -0
- package/src/scaffold/assets.ts +77 -73
- package/src/testing/context.js +8 -9
- package/src/testing/context.ts +9 -9
- package/src/testing/index.d.ts +14 -3
- package/src/testing/index.js +254 -175
- package/src/testing/index.ts +298 -195
- package/src/testing/types.d.ts +18 -19
- package/src/testing/types.ts +18 -18
- package/src/utils/bun.ts +26 -0
- package/src/watch.ts +503 -99
- package/src/workspace.ts +59 -3
- package/templates/backend/.env.example +15 -0
- package/templates/backend/auth/adapter.ts +335 -36
- package/templates/backend/db/connection.ts +190 -65
- package/templates/backend/db/migrate.ts +149 -43
- package/templates/backend/db/types.d.ts +1 -1
- package/templates/backend/env.ts +132 -20
- package/templates/backend/functions/hello/index.ts +1 -2
- package/templates/backend/index.ts +15 -508
- package/templates/backend/jobs/nightly/index.ts +1 -1
- package/templates/backend/jobs/runtime.ts +24 -11
- package/templates/backend/jobs/scheduler.ts +208 -46
- package/templates/backend/module.ts +227 -13
- package/templates/backend/observability/logger.ts +2 -12
- package/templates/backend/observability/metrics.ts +8 -5
- package/templates/backend/session/sqlite.ts +152 -0
- package/templates/backend/session/store.ts +45 -0
- package/templates/backend/tsconfig.json +1 -1
- package/tests/add.test.js +327 -0
- package/tests/authAdapter.test.js +315 -0
- package/tests/bundlerParity.test.js +217 -0
- package/tests/cacheReporter.test.js +10 -10
- package/tests/dbConnection.test.js +209 -0
- package/tests/deploy.test.js +357 -0
- package/tests/envLoader.test.js +271 -17
- package/tests/integration.test.js +2432 -3
- package/tests/jobsScheduler.test.js +253 -0
- package/tests/manifest.test.js +287 -12
- package/tests/migrationRunner.test.js +249 -0
- package/tests/sessionScaffoldStore.test.js +752 -0
- package/tests/sessionStore.test.js +490 -0
- package/tests/testing.test.js +252 -0
- package/tests/watch.test.js +192 -32
- package/tsconfig.json +3 -10
- package/templates/backend/server/fastify.ts +0 -288
package/README.md
CHANGED
|
@@ -1,31 +1,14 @@
|
|
|
1
1
|
# @webstir-io/webstir-backend
|
|
2
2
|
|
|
3
|
-
Backend
|
|
4
|
-
|
|
5
|
-
## Status
|
|
6
|
-
|
|
7
|
-
- Experimental provider for the Webstir ecosystem — APIs, defaults, and behavior may change between releases while things stabilize.
|
|
8
|
-
- Not yet recommended for production workloads; treat it as a learning and exploration tool.
|
|
3
|
+
Backend delivery for Webstir's HTML-first application model. The package type-checks backend workspaces, builds runnable Bun-targeted output, and ships the default request runtime for server-handled forms, fragment responses, sessions, request-time views, and request-time document caching.
|
|
9
4
|
|
|
10
5
|
## Quick Start
|
|
11
6
|
|
|
12
|
-
1. **
|
|
13
|
-
Configure user-level auth (recommended) or set an env var:
|
|
14
|
-
- User config (`~/.npmrc`):
|
|
15
|
-
```ini
|
|
16
|
-
@webstir-io:registry=https://npm.pkg.github.com
|
|
17
|
-
//npm.pkg.github.com/:_authToken=${GH_PACKAGES_TOKEN}
|
|
18
|
-
```
|
|
19
|
-
- Or export a token (CI uses `NODE_AUTH_TOKEN`):
|
|
20
|
-
```bash
|
|
21
|
-
export NODE_AUTH_TOKEN="$GH_PACKAGES_TOKEN"
|
|
22
|
-
```
|
|
23
|
-
Consumers need `read:packages`; publishers also require `write:packages`.
|
|
24
|
-
2. **Install**
|
|
7
|
+
1. **Install**
|
|
25
8
|
```bash
|
|
26
|
-
|
|
9
|
+
bun add @webstir-io/webstir-backend
|
|
27
10
|
```
|
|
28
|
-
|
|
11
|
+
2. **Run a build**
|
|
29
12
|
```ts
|
|
30
13
|
import { backendProvider } from '@webstir-io/webstir-backend';
|
|
31
14
|
|
|
@@ -38,7 +21,33 @@ Backend build orchestration for Webstir workspaces. The package exposes a `Modul
|
|
|
38
21
|
console.log(manifest.entryPoints);
|
|
39
22
|
```
|
|
40
23
|
|
|
41
|
-
Requires
|
|
24
|
+
Requires Bun **1.3.11** or newer.
|
|
25
|
+
|
|
26
|
+
## What This Runtime Is Good At
|
|
27
|
+
|
|
28
|
+
- Server-rendered HTML routes and request-time views
|
|
29
|
+
- HTML form workflows that still work without client JavaScript
|
|
30
|
+
- Redirect-after-post and fragment responses from the same backend handlers
|
|
31
|
+
- Session, flash, CSRF, auth, and request hooks in the default scaffold
|
|
32
|
+
- Request-time document caching for view shells plus explicit fragment no-store behavior
|
|
33
|
+
|
|
34
|
+
Canonical proof apps in this repo:
|
|
35
|
+
|
|
36
|
+
- [`examples/demos/auth-crud`](../../../examples/demos/auth-crud) for server-handled sign-in and CRUD forms
|
|
37
|
+
- [`examples/demos/dashboard`](../../../examples/demos/dashboard) for dashboard-style shell and panel refreshes without SPA architecture
|
|
38
|
+
|
|
39
|
+
## Shipped HTML-First Runtime
|
|
40
|
+
|
|
41
|
+
The default `src/backend/index.ts` entry is the supported runtime surface. Older workspaces can keep their explicit Bun shim/runtime wrapper files if they already exist:
|
|
42
|
+
|
|
43
|
+
- Route auto-mounting from compiled `module.ts`
|
|
44
|
+
- Health probes at `/api/health`, `/healthz`, and `/readyz`
|
|
45
|
+
- Structured request logging with `x-request-id`
|
|
46
|
+
- Form parsing for `application/x-www-form-urlencoded`
|
|
47
|
+
- Redirect and fragment responses via `Location` and `x-webstir-fragment-*`
|
|
48
|
+
- Session, flash, and request-hook execution in the scaffold runtime
|
|
49
|
+
- Request-time views with `x-webstir-document-cache: miss|hit|stale`
|
|
50
|
+
- Explicit fragment cache bypass with `Cache-Control: no-store` and `x-webstir-fragment-cache: bypass`
|
|
42
51
|
|
|
43
52
|
## Community & Support
|
|
44
53
|
|
|
@@ -72,41 +81,39 @@ The provider expects a standard workspace layout and performs two steps:
|
|
|
72
81
|
|
|
73
82
|
`backendProvider` implements `ModuleProvider` from `@webstir-io/module-contract`:
|
|
74
83
|
|
|
75
|
-
- `metadata` — package id, version, kind (`backend`), CLI compatibility,
|
|
84
|
+
- `metadata` — package id, version, kind (`backend`), CLI compatibility, and runtime notes.
|
|
76
85
|
- `resolveWorkspace({ workspaceRoot })` — returns canonical source/build/test roots.
|
|
77
86
|
- `build(options)` — type‑checks with `tsc --noEmit`, then runs esbuild. In `build`/`test` mode it transpiles without bundling; in `publish` it bundles workspace code, externalizes `node_modules`, minifies, strips comments, and defines `NODE_ENV=production`. Artifacts are gathered and a manifest describing entry points, diagnostics, and the module contract manifest is returned.
|
|
78
87
|
- `getScaffoldAssets()` — returns starter files to bootstrap a backend workspace:
|
|
79
88
|
- `src/backend/tsconfig.json` (NodeNext, outDir `build/backend`)
|
|
80
|
-
- `src/backend/index.ts` (
|
|
89
|
+
- `src/backend/index.ts` (thin composition entry that boots the package-managed Bun runtime)
|
|
81
90
|
- `src/backend/module.ts` (optional manifest + handler example the server loads automatically)
|
|
82
|
-
- `src/backend/server/fastify.ts` (optional Fastify server scaffold)
|
|
83
91
|
|
|
84
|
-
###
|
|
92
|
+
### Bun Scaffold (default)
|
|
93
|
+
|
|
94
|
+
Fresh scaffolds now boot through the package-managed Bun runtime by default:
|
|
85
95
|
|
|
86
|
-
|
|
96
|
+
- `src/backend/index.ts` composes through `createDefaultBunBackendBootstrap(...)` from `@webstir-io/webstir-backend`, so bootstrap-level fixes can ship through package upgrades instead of template-only copies.
|
|
87
97
|
|
|
88
|
-
-
|
|
98
|
+
- Start the built backend with Bun:
|
|
89
99
|
```bash
|
|
90
|
-
|
|
100
|
+
bun build/backend/index.js
|
|
91
101
|
```
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
start().catch((err) => { console.error(err); process.exit(1); });
|
|
97
|
-
```
|
|
98
|
-
- Or run it directly after a build:
|
|
102
|
+
|
|
103
|
+
Published `api` and `full` workspaces also ship the supported Bun deploy runner:
|
|
104
|
+
|
|
105
|
+
- Start the published workspace through the single-port deploy host:
|
|
99
106
|
```bash
|
|
100
|
-
|
|
107
|
+
bun ./node_modules/.bin/webstir-backend-deploy --workspace "$PWD"
|
|
101
108
|
```
|
|
109
|
+
- `api` workspaces proxy all requests to the published backend runtime.
|
|
110
|
+
- `full` workspaces serve `dist/frontend/**` and proxy `/api/*` to the published backend runtime.
|
|
102
111
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
When present, the Fastify scaffold will also attempt to auto‑mount any compiled module routes it finds under `build/backend/module(.js)`. Export your module definition as `module`, `moduleDefinition`, or the `default` export from `src/backend/module.ts` and build; the server will attach handlers using the route metadata.
|
|
112
|
+
Fresh scaffolds do not copy `src/backend/server/bun.ts` or `src/backend/runtime/*` re-export files. The operational runtime lives in upgradeable package exports instead.
|
|
106
113
|
|
|
107
114
|
### Server runtime baseline
|
|
108
115
|
|
|
109
|
-
The default `src/backend/index.ts` entry
|
|
116
|
+
The default `src/backend/index.ts` entry provides these runtime guarantees:
|
|
110
117
|
|
|
111
118
|
- Route auto-mounting: any `module.ts` routes are compiled, logged, and attached on startup with manifest summaries (name, version, route count, capabilities).
|
|
112
119
|
- Health probes: `/api/health` (for the orchestrator), `/healthz` (generic health), and `/readyz` (status + manifest summary). The CLI still waits for `API server running` before proxying requests.
|
|
@@ -114,20 +121,33 @@ The default `src/backend/index.ts` entry (and the optional Fastify scaffold) sha
|
|
|
114
121
|
- Request context: handlers receive `params`, `query`, `body`, `env`, `logger`, `request`, `reply`, `requestId`, and `now()` helpers that align with the `RequestContext` shape from `@webstir-io/module-contract`.
|
|
115
122
|
- Request IDs: each response sets `x-request-id` and the context/logger include the same identifier so you can correlate logs.
|
|
116
123
|
- Failure safety: handler exceptions are caught and surfaced as `{ error: 'internal_error' }` without tearing down the process.
|
|
124
|
+
- Progressive enhancement responses: handlers can return redirects (`303` by default) or targeted fragment payloads; the scaffold emits `Location` and `x-webstir-fragment-*` headers accordingly.
|
|
125
|
+
- Form handling: JSON bodies still work as before, and the scaffold now parses `application/x-www-form-urlencoded` requests into plain objects for HTML form workflows.
|
|
126
|
+
|
|
127
|
+
Stick with the default Bun entry while exploring the manifest helpers, or import package runtime exports directly when you need an explicit local entry. The readiness + manifest wiring stays the same.
|
|
128
|
+
|
|
129
|
+
### Runtime cache ergonomics
|
|
117
130
|
|
|
118
|
-
|
|
131
|
+
- Request-time views cache the built frontend HTML document shell in process memory, keyed by the resolved built file under `build/frontend/pages/**` (or `dist/frontend/**` when serving published output).
|
|
132
|
+
- The first request for a document is a cache `miss`; unchanged follow-up requests are `hit`; if the built HTML file changes on disk, the next request invalidates the stale entry, reloads it, and reports `stale`.
|
|
133
|
+
- Request-time document responses always send `Cache-Control: no-store` and expose the cache outcome via `x-webstir-document-cache`, so you can verify whether the runtime reused or refreshed the shell.
|
|
134
|
+
- Fragment responses are never reused by the scaffold runtime. They always send `Cache-Control: no-store` plus `x-webstir-fragment-cache: bypass`, because fragment bodies come from live route execution and should reflect current session/auth/request state.
|
|
135
|
+
- Process restarts clear the in-memory document cache. There is no separate persisted request-time HTML cache today; the existing `.webstir` cache files remain build/publish metadata, not response payload storage.
|
|
119
136
|
|
|
120
137
|
### Secrets & auth adapters
|
|
121
138
|
|
|
122
139
|
The backend template now ships a lightweight auth adapter so you can secure routes without wiring a full identity provider on day one:
|
|
123
140
|
|
|
124
|
-
- **Environment-driven secrets** — populate `.env.local`/`.env` with `AUTH_JWT_SECRET`
|
|
125
|
-
- **Bearer verification (HS256)** —
|
|
126
|
-
- **Service tokens** — internal callers can present `X-Service-Token` or `X-API-Key` values that match `AUTH_SERVICE_TOKENS`. Successful matches yield a `ctx.auth` context with the `service` scope so you can distinguish automated jobs from end users.
|
|
141
|
+
- **Environment-driven secrets** — populate `.env.local`/`.env` with one JWT verification input: `AUTH_JWT_SECRET` for shared-secret HS256, `AUTH_JWT_PUBLIC_KEY` or `AUTH_JWT_PUBLIC_KEY_FILE` for RSA public-key verification, or `AUTH_JWKS_URL` for remote JWKS discovery. Optional `AUTH_JWT_ISSUER` / `AUTH_JWT_AUDIENCE` claims and comma/space-delimited `AUTH_SERVICE_TOKENS` still apply. An example lives in `templates/backend/.env.example`.
|
|
142
|
+
- **Bearer verification (HS256 + RS256)** — incoming `Authorization: Bearer <token>` headers validate against HS256 shared secrets, inline/file-backed RSA public keys, or RSA keys discovered from JWKS. Unsupported algorithms, malformed compact segments, bad signatures, wrong issuer/audience, invalid numeric-date claims, and invalid `nbf`/`exp` windows fail closed. On success, `ctx.auth` includes `userId`, `email`, `scopes`, `roles`, and the raw claims payload.
|
|
143
|
+
- **Service tokens** — internal callers can present `X-Service-Token` or `X-API-Key` values that match `AUTH_SERVICE_TOKENS`. Successful matches yield a `ctx.auth` context with the `service` scope so you can distinguish automated jobs from end users. If an invalid bearer token and a valid service token are both present, the service token is still accepted and bearer diagnostics stay redacted.
|
|
127
144
|
- **Route ergonomics** — the module template now demonstrates gating access on `ctx.auth` and sets the `auth` capability in the manifest so downstream tooling knows the module expects identity context.
|
|
128
|
-
-
|
|
145
|
+
- **Session & request-body defaults** — set `SESSION_SECRET` for stable session cookies. In development, the scaffold still falls back to a per-process random secret when unset; in production, `SESSION_SECRET` is now required and startup fails fast when it is missing. Request bodies are capped by `REQUEST_BODY_MAX_BYTES` (default `1048576`) in the supported Bun server template.
|
|
146
|
+
- **Durable session storage (optional)** — the scaffold now defaults to SQLite-backed sessions in production when `SESSION_STORE_DRIVER` is unset, while keeping in-memory storage as the development default. You can still opt into SQLite explicitly with `SESSION_STORE_DRIVER=sqlite` or just configure `SESSION_STORE_URL`; set `SESSION_STORE_DRIVER=memory` only when you intentionally want the non-durable path. `SESSION_STORE_URL` defaults to `file:./data/sessions.sqlite` when the SQLite store is active and resolves from the workspace root, so launch directory changes do not redirect session state into the wrong folder.
|
|
147
|
+
- **Session/form safety rules** — stale or tampered session cookies clear on commit, CSRF tokens are single-use after successful verification, and malformed SQLite session rows fail with a session-row diagnostic. Ordinary session updates keep the same session id; clearing a session and starting a new one creates a new id.
|
|
148
|
+
- Install `pino` in your workspace (`bun add pino`) before running the scaffold; the template server imports it directly.
|
|
129
149
|
|
|
130
|
-
This adapter is intentionally
|
|
150
|
+
This adapter is still intentionally scoped, but it now supports the two most common integration paths: shared-secret HS256 for local/simple deployments and RSA/JWKS verification for third-party IdPs. The scaffold populates `ctx.auth` for every route once one of those verification inputs is configured.
|
|
131
151
|
|
|
132
152
|
### Observability & metrics
|
|
133
153
|
|
|
@@ -139,33 +159,40 @@ Install `pino` (and optionally `pino-pretty` for local formatting) in any worksp
|
|
|
139
159
|
|
|
140
160
|
### Jobs & scheduling
|
|
141
161
|
|
|
142
|
-
- Define jobs via `webstir add-job <name> [--schedule "<cron>"] [--description "..."] [--priority <number|label>]`. The CLI creates `src/backend/jobs/<name>/index.ts` and records metadata in `webstir.moduleManifest.jobs` in `package.json`.
|
|
162
|
+
- Define jobs via `webstir add-job <name> [--schedule "<cron|@macro|rate(...)>"] [--description "..."] [--priority <number|label>]`. The CLI creates `src/backend/jobs/<name>/index.ts` and records metadata in `webstir.moduleManifest.jobs` in `package.json`.
|
|
143
163
|
- The template provides a zero-config job loader (`src/backend/jobs/runtime.ts`) and a lightweight scheduler/runner (`build/backend/jobs/scheduler.js`). Use it to explore your jobs without wiring a full queue:
|
|
144
164
|
|
|
145
165
|
```bash
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
166
|
+
bun add pino # already needed for the server
|
|
167
|
+
bun src/backend/jobs/scheduler.ts --list
|
|
168
|
+
bun src/backend/jobs/scheduler.ts --json
|
|
169
|
+
bun build/backend/jobs/scheduler.js --job nightly
|
|
170
|
+
bun build/backend/jobs/scheduler.js --watch # runs cron expressions, cron nicknames, @reboot, or rate(...) jobs
|
|
150
171
|
```
|
|
151
172
|
|
|
152
|
-
- `/readyz` surfaces manifest job counts, and `
|
|
153
|
-
- Cron expressions recorded in the manifest are left untouched so you can plug them into your real scheduler (Temporal, Quartz, Cloud Scheduler, etc.).
|
|
173
|
+
- `/readyz` surfaces manifest job counts, and `bun build/backend/jobs/<name>/index.js` remains the quickest way to execute a single job in isolation.
|
|
174
|
+
- Cron expressions recorded in the manifest are left untouched so you can plug them into your real scheduler (Temporal, Quartz, Cloud Scheduler, etc.). On Bun `1.3.11+`, the built-in watcher now uses `Bun.cron.parse(...)` for real cron expressions and nicknames such as `0 0 * * *`, `*/15 * * * *`, `@daily`, or `@monthly`, while still preserving `rate(n units)` and `@reboot` for local development loops. Cron-based schedules wait for the next matching wall-clock time; use `--job <name>` or `--all` when you want an immediate run.
|
|
175
|
+
- Local watch mode skips overlapping runs for the same job and disposes scheduled timers on `SIGINT`/`SIGTERM`. Use an external scheduler or queue when you need distributed locking, retries, or durable job state.
|
|
154
176
|
|
|
155
177
|
### Database & migrations
|
|
156
178
|
|
|
157
179
|
- `DATABASE_URL` defaults to `file:./data/dev.sqlite`. Point it at Postgres (`postgres://...`) or another SQLite file as needed. Override the tracking table via `DATABASE_MIGRATIONS_TABLE` (defaults to `_webstir_migrations`).
|
|
158
|
-
- `src/backend/db/connection.ts` exposes a tiny helper
|
|
180
|
+
- `src/backend/db/connection.ts` exposes a tiny helper backed by `Bun.SQL`, so the same Bun-native client now handles SQLite (`file:./data/dev.sqlite`, `sqlite:./data/dev.sqlite`, `:memory:`) and Postgres (`postgres://...`) without a separate `pg` install.
|
|
181
|
+
- `src/backend/session/store.ts` now owns the runtime session-store choice. Development still defaults to the in-memory store for stateless/local flows, while production defaults to SQLite unless you pin `SESSION_STORE_DRIVER=memory`. You can also persist sessions explicitly in SQLite via `src/backend/session/sqlite.ts` by setting `SESSION_STORE_DRIVER=sqlite` or just configuring `SESSION_STORE_URL`. The SQLite adapter creates its table lazily and runs on Bun without any extra SQLite package install.
|
|
159
182
|
- Drop SQL/TypeScript migrations under `src/backend/db/migrations/*.ts`, exporting `id`, `up`, and optional `down`.
|
|
160
183
|
- Run migrations with:
|
|
161
184
|
|
|
162
185
|
```bash
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
186
|
+
bun src/backend/db/migrate.ts --list
|
|
187
|
+
bun src/backend/db/migrate.ts --status
|
|
188
|
+
bun src/backend/db/migrate.ts # apply pending migrations
|
|
189
|
+
bun src/backend/db/migrate.ts --down --steps 1
|
|
166
190
|
```
|
|
167
191
|
|
|
168
|
-
- The runner logs each migration, records history in `DATABASE_MIGRATIONS_TABLE`, and works the same way once compiled (`
|
|
192
|
+
- The runner logs each migration, records history in the validated `DATABASE_MIGRATIONS_TABLE`, and works the same way once compiled (`bun build/backend/db/migrate.js ...`).
|
|
193
|
+
- Each migration runs in a transaction with its history update. A failed `up()` rolls back and is not recorded; a failed `down()` keeps the record so it can be retried. Avoid opening nested transactions inside migration files.
|
|
194
|
+
- For repeatable tests, point `DATABASE_URL` at a throwaway SQLite file and use `--down` without `--steps` to run every available `down()` migration before recreating test state. App seed data should live in explicit app-owned scripts or migrations rather than an implicit runner hook.
|
|
195
|
+
- When you pass migration parameters, use `?` placeholders in your scaffold code. The helper keeps that style working across SQLite and Postgres.
|
|
169
196
|
|
|
170
197
|
### Module Manifest Integration
|
|
171
198
|
|
|
@@ -258,7 +285,7 @@ export const module = createModule({
|
|
|
258
285
|
});
|
|
259
286
|
```
|
|
260
287
|
|
|
261
|
-
When `
|
|
288
|
+
When `bun run build` completes, the provider detects `build/backend/module.js`, hydrates the manifest with the `routes` metadata above, and returns it to the orchestrator alongside the compiled entry points.
|
|
262
289
|
|
|
263
290
|
#### Module Definition Only Example
|
|
264
291
|
|
|
@@ -308,7 +335,7 @@ This keeps your manifest co-located with runtime code while the provider handles
|
|
|
308
335
|
|
|
309
336
|
- `src/backend/env.ts` loads `.env.local` (if present) followed by `.env`, merges values into `process.env`, and exposes a typed `loadEnv()` helper.
|
|
310
337
|
- A `.env.example` file is scaffolded at the workspace root—copy it to `.env`/`.env.local`, fill in secrets (e.g., `API_BASE_URL`, `DATABASE_URL`, `JWT_SECRET`), and adjust `loadEnv()` to require the variables your backend needs.
|
|
311
|
-
- The default
|
|
338
|
+
- The default Bun scaffold calls `loadEnv()` before binding, so the same config is available inside route handlers. Use `ctx.env.require('JWT_SECRET')` to fetch validated values.
|
|
312
339
|
|
|
313
340
|
### Multiple Entry Points
|
|
314
341
|
The provider discovers these entries automatically (all optional):
|
|
@@ -335,29 +362,29 @@ Artifacts are returned as absolute paths so installers can copy or upload them.
|
|
|
335
362
|
|
|
336
363
|
| Script | Description |
|
|
337
364
|
|--------|-------------|
|
|
338
|
-
| `
|
|
339
|
-
| `
|
|
340
|
-
| `
|
|
341
|
-
| `
|
|
365
|
+
| `bun run build` | Compiles provider TypeScript from `src/` into `dist/`. |
|
|
366
|
+
| `bun run test` | Builds and runs Node's test runner over `tests/**/*.test.js`. |
|
|
367
|
+
| `bun run smoke` | Quick end-to-end check: scaffolds a temp workspace and runs build/publish via the provider. |
|
|
368
|
+
| `bun run clean` | Removes `dist/`. |
|
|
342
369
|
|
|
343
370
|
The published package ships prebuilt JavaScript and type definitions in `dist/`.
|
|
344
371
|
|
|
345
372
|
## Maintainer Workflow
|
|
346
373
|
|
|
347
374
|
```bash
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
# Release helper (bumps version
|
|
354
|
-
|
|
375
|
+
bun install
|
|
376
|
+
bun run clean # remove dist artifacts
|
|
377
|
+
bun run build # emits dist/
|
|
378
|
+
bun run test # runs unit/integration tests
|
|
379
|
+
bun run smoke
|
|
380
|
+
# Release helper (bumps version and pushes a package-scoped release tag)
|
|
381
|
+
bun run release -- patch
|
|
355
382
|
```
|
|
356
383
|
|
|
357
|
-
- Add tests under `tests/**/*.test.ts` and wire them into `
|
|
358
|
-
- Ensure CI runs `
|
|
359
|
-
- Publishing targets
|
|
360
|
-
- Use `
|
|
384
|
+
- Add tests under `tests/**/*.test.ts` and wire them into `bun run test` once the backend runtime is ready.
|
|
385
|
+
- Ensure CI runs `bun install --frozen-lockfile`, `bun run clean`, `bun run build`, `bun run test`, and `bun run smoke` before publish.
|
|
386
|
+
- Publishing targets npm via `publishConfig.registry`.
|
|
387
|
+
- Use `bun run release -- <patch|minor|major|x.y.z>` to bump the version, build, test, run the smoke check, and push a package-scoped tag that triggers the monorepo release workflow.
|
|
361
388
|
|
|
362
389
|
## Troubleshooting
|
|
363
390
|
|
|
@@ -383,8 +410,8 @@ MIT © Webstir
|
|
|
383
410
|
Start incremental builds with type-checking in the background:
|
|
384
411
|
|
|
385
412
|
```bash
|
|
386
|
-
|
|
387
|
-
|
|
413
|
+
bun run dev # type-check + transpile on change
|
|
414
|
+
bun run dev:fast # faster DX: skip tsc in watch
|
|
388
415
|
```
|
|
389
416
|
|
|
390
417
|
Notes
|
|
@@ -424,4 +451,4 @@ If you use `getScaffoldAssets()` programmatically, these templates are included
|
|
|
424
451
|
- The backend template listens on `process.env.PORT` (default `4000`) and logs `API server running` when ready.
|
|
425
452
|
- The orchestrator's dev server waits for that readiness line and proxies `/api/*` to your Node server.
|
|
426
453
|
- Health probes: `/api/health` (orchestrator compatibility) mirrors `/healthz`, while `/readyz` exposes the readiness state plus the current manifest summary for external monitors.
|
|
427
|
-
- If you
|
|
454
|
+
- If you replace the default runtime locally, keep the same behavior: listen on `process.env.PORT`, expose the same endpoints, and print `API server running` once the server is listening.
|
package/dist/add.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { FragmentUpdateMode, SessionAccessMode } from '@webstir-io/module-contract';
|
|
2
|
+
export interface AddRouteOptions {
|
|
3
|
+
readonly workspaceRoot: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly method?: string;
|
|
6
|
+
readonly path?: string;
|
|
7
|
+
readonly summary?: string;
|
|
8
|
+
readonly description?: string;
|
|
9
|
+
readonly tags?: readonly string[];
|
|
10
|
+
readonly interaction?: string;
|
|
11
|
+
readonly sessionMode?: string;
|
|
12
|
+
readonly sessionWrite?: boolean;
|
|
13
|
+
readonly formUrlEncoded?: boolean;
|
|
14
|
+
readonly formCsrf?: boolean;
|
|
15
|
+
readonly fragmentTarget?: string;
|
|
16
|
+
readonly fragmentSelector?: string;
|
|
17
|
+
readonly fragmentMode?: string;
|
|
18
|
+
readonly paramsSchema?: string;
|
|
19
|
+
readonly querySchema?: string;
|
|
20
|
+
readonly bodySchema?: string;
|
|
21
|
+
readonly headersSchema?: string;
|
|
22
|
+
readonly responseSchema?: string;
|
|
23
|
+
readonly responseStatus?: string | number;
|
|
24
|
+
readonly responseHeadersSchema?: string;
|
|
25
|
+
}
|
|
26
|
+
export interface AddJobOptions {
|
|
27
|
+
readonly workspaceRoot: string;
|
|
28
|
+
readonly name: string;
|
|
29
|
+
readonly schedule?: string;
|
|
30
|
+
readonly description?: string;
|
|
31
|
+
readonly priority?: string | number;
|
|
32
|
+
}
|
|
33
|
+
export interface UpdateRouteContractOptions {
|
|
34
|
+
readonly workspaceRoot: string;
|
|
35
|
+
readonly method: string;
|
|
36
|
+
readonly path: string;
|
|
37
|
+
readonly sessionMode?: SessionAccessMode | string | null;
|
|
38
|
+
readonly sessionWrite?: boolean | null;
|
|
39
|
+
readonly formUrlEncoded?: boolean | null;
|
|
40
|
+
readonly formCsrf?: boolean | null;
|
|
41
|
+
readonly fragmentTarget?: string | null;
|
|
42
|
+
readonly fragmentSelector?: string | null;
|
|
43
|
+
readonly fragmentMode?: FragmentUpdateMode | string | null;
|
|
44
|
+
readonly paramsSchema?: string | null;
|
|
45
|
+
readonly querySchema?: string | null;
|
|
46
|
+
readonly bodySchema?: string | null;
|
|
47
|
+
readonly headersSchema?: string | null;
|
|
48
|
+
readonly responseSchema?: string | null;
|
|
49
|
+
readonly responseStatus?: string | number | null;
|
|
50
|
+
readonly responseHeadersSchema?: string | null;
|
|
51
|
+
}
|
|
52
|
+
export interface BackendAddResult {
|
|
53
|
+
readonly subject: 'route' | 'job';
|
|
54
|
+
readonly target: string;
|
|
55
|
+
readonly changes: readonly string[];
|
|
56
|
+
}
|
|
57
|
+
export declare function runAddRoute(options: AddRouteOptions): Promise<BackendAddResult>;
|
|
58
|
+
export declare function runAddJob(options: AddJobOptions): Promise<BackendAddResult>;
|
|
59
|
+
export declare function runUpdateRouteContract(options: UpdateRouteContractOptions): Promise<BackendAddResult>;
|