webspresso 0.0.67 → 0.0.68

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.
@@ -2,11 +2,13 @@
2
2
  name: webspresso-usage
3
3
  description: >-
4
4
  Comprehensive Webspresso framework reference: file-based SSR and API routing,
5
- createApp options, Nunjucks/fsy helpers, i18n, lifecycle hooks, Zod API validation,
6
- ORM (zdb, defineModel, repository, query builder, migrations), plugins (admin,
7
- analytics, sitemap, SEO, audit, recaptcha), CLI, env vars, and testing. Use when
8
- working in this repo or any Webspresso app—adding routes, APIs, models, plugins,
9
- or debugging routing, ctx.db, or templates.
5
+ createApp options including optional clientRuntime (Alpine.js, swup v4, no HTMX),
6
+ session auth (createAuth, quickAuth, webspresso/core/auth), Nunjucks/fsy helpers,
7
+ i18n, lifecycle hooks, Zod API validation, ORM (zdb, defineModel, repository,
8
+ query builder, migrations), plugins (admin, analytics, sitemap, SEO, audit,
9
+ recaptcha, rest resources, file upload), CLI, env vars, and testing. Use when working in this
10
+ repo or any Webspresso app—adding routes, APIs, models, plugins, auth, client-side
11
+ sprinkles or page transitions, or debugging routing, ctx.db, session, or templates.
10
12
  ---
11
13
 
12
14
  # Webspresso — agent reference
@@ -19,7 +21,7 @@ description: >-
19
21
  - **ORM**: Knex-backed layer in `core/orm` — `defineModel`, `zdb` schema helpers, repositories, query builder, migrations.
20
22
  - **Plugins**: Register in `createApp({ plugins })`; optional `db` passed as `ctx.db`.
21
23
 
22
- Public API surface: `require('webspresso')` / [`index.js`](../../../index.js) — `createApp`, file-router utilities, `createHelpers`, plugin manager, ORM exports, built-in plugins.
24
+ Public API surface: `require('webspresso')` / [`index.js`](../../../index.js) — `createApp`, **`resolveClientRuntime`**, **`CLIENT_RUNTIME_BASE`**, file-router utilities, `createHelpers`, plugin manager, ORM exports, built-in plugins. **Session auth** lives in [`core/auth`](../../../core/auth) — import **`require('webspresso/core/auth')`** (`createAuth`, `quickAuth`, `hash`, `verify`, `setupAuthMiddleware`, `createRememberTokensTable`, policy helpers); wire with **`createApp({ auth })`**.
23
25
 
24
26
  ---
25
27
 
@@ -66,11 +68,31 @@ project/
66
68
  | `timeout` | e.g. `'30s'` or `false` |
67
69
  | `helmet` | `true` / `false` / object |
68
70
  | `assets` | `{ version, manifestPath, prefix }` for `fsy.asset` / `fsy.css` / `fsy.js` |
69
- | `clientRuntime` | Opt-in `{ alpine?, swup? }` serves `/__webspresso/client-runtime/*`, template `clientRuntime`, partial `views/partials/webspresso-client-runtime.njk`, `<main id="swup">` when swup on. Env: `WEBSPRESSO_ALPINE`, `WEBSPRESSO_SWUP`. |
70
- | `auth` | Auth manager from `createAuth` (session routes) |
71
- | `setupRoutes(app, ctx)` | **Register custom Express routes here** — runs **after** file routes and plugins’ `onRoutesReady`, **before** 404. `ctx.clientRuntime` included. Do not rely on `app.get` *after* `createApp` returns unless routes are appended before the 404 middleware (see [`src/server.js`](../../../src/server.js)). |
71
+ | `clientRuntime` | Opt-in **`{ alpine?: boolean \| object, swup?: boolean \| object }`**. Serves **`/__webspresso/client-runtime/*`** (Alpine 3, swup 4 + Head + Scripts plugins + bootstrap). Template context **`clientRuntime`**; include [`views/partials/webspresso-client-runtime.njk`](../../../views/partials/webspresso-client-runtime.njk) and set **`<main id="swup">`** when swup is on. Env overrides: **`WEBSPRESSO_ALPINE`**, **`WEBSPRESSO_SWUP`** (`1` or `true`). Admin / dev dashboard HTML is unchanged (Mithril). Use **`data-no-swup`** on links for full page loads. HTMX is not used. |
72
+ | `auth` | `AuthManager` from **`createAuth()`** / **`quickAuth()`** (`webspresso/core/auth`). Mounts cookie parser + **`express-session`** + per-request **`authenticate`**; sets **`req.user`**, **`req.auth`**. Injects named route middleware **`auth`** and **`guest`** (overwrites same keys in `middlewares` if you passed both — avoid reusing those names for custom handlers). |
73
+ | `setupRoutes(app, ctx)` | **Register custom Express routes here** — runs **after** file routes and plugins’ `onRoutesReady`, **before** 404. **`ctx.clientRuntime`** is the resolved flags. **`ctx.authMiddleware`** is set when `auth` was passed (guards: `requireAuth`, `requireGuest`, `requireCan`, `requireVerified`, …). Do not rely on `app.get` *after* `createApp` returns unless routes are appended before the 404 middleware (see [`src/server.js`](../../../src/server.js)). |
72
74
 
73
- **Returns:** `{ app, nunjucksEnv, pluginManager, authMiddleware? }` (and related).
75
+ **Returns:** `{ app, nunjucksEnv, pluginManager, authMiddleware }` `authMiddleware` is **`null`** when `auth` was not configured.
76
+
77
+ ### Client runtime — implementation notes
78
+
79
+ - **Package helpers:** `resolveClientRuntime(options)` merges **`createApp({ clientRuntime })`** with env; **`CLIENT_RUNTIME_BASE`** is **`/__webspresso/client-runtime`** (script URLs under that path).
80
+ - **After swup navigation:** bootstrap runs **`Alpine.initTree`** on **`#swup`** on swup’s **`content:replace`** so new SSR markup gets Alpine bindings.
81
+ - **Default `ignoreVisit` (bootstrap):** links under **`/_admin`**, **`/_webspresso`**, elements with **`data-no-swup`**, plus swup’s usual rules (e.g. `target="_blank"`, other origin).
82
+ - **CSP / Helmet:** production **`script-src 'self'`** works for **`/__webspresso/client-runtime/`**; some Alpine builds may need **`unsafe-eval`** — validate for your version or use a stricter build.
83
+ - **Demo:** repo **[`examples/alpine-swup-demo/`](../../../examples/alpine-swup-demo/)**. Longer doc: **[`doc/index.html#client-runtime`](../../../doc/index.html#client-runtime)** · README **Client runtime**.
84
+
85
+ ### Session authentication — essentials
86
+
87
+ - **Import:** `const { createAuth, quickAuth, hash, verify, createRememberTokensTable } = require('webspresso/core/auth')` (published `core/` tree on npm; **not** re-exported from package root).
88
+ - **`createAuth({ findUserById, findUserByCredentials, session: { secret }, rememberTokens?, ... })`** — adapter pattern; optional **remember-me** via `rememberTokens: { create, find, delete, deleteAllForUser }` + **`createRememberTokensTable(knex)`** for the default table shape.
89
+ - **`quickAuth({ db, userModel, identifierField, passwordField, rememberMe })`** — wires **`getRepository`** + bcrypt **`verify`**; optional Knex **`remember_tokens`** when `rememberMe: true`.
90
+ - **Request API** (after global authenticate): **`req.auth.attempt(id, password, { remember })`**, **`login`**, **`logout`**, **`check`**, **`guest`**, **`user`**, **`id`**, **`can` / `cannot` / `authorize`** (policies: **`auth.definePolicy`**, **`defineGate`**, **`beforePolicy`**).
91
+ - **Route config:** `middleware: ['auth']` (must be logged in) or `['guest']` (logged-out only). For JSON APIs mounted in **`setupRoutes`**, use **`ctx.authMiddleware.requireAuth({ api: true })`** for 401 JSON instead of redirect.
92
+ - **Login page pitfall:** a **`pages/login.njk`** can register **before** `setupRoutes` and bypass **`requireGuest`**. Prefer login GET/POST in **`setupRoutes`** with templates under **`views/`** only, or omit **`pages/login.njk`** — see [`tests/e2e/auth.spec.js`](../../../tests/e2e/auth.spec.js).
93
+ - **Admin panel** uses a **separate** session (`req.session.adminUser`, `/_admin/api/auth/*`); it does **not** replace **`createApp({ auth })`** for site users.
94
+
95
+ Longer narrative: **[`doc/index.html#authentication`](../../../doc/index.html#authentication)** · README **Authentication (session)**.
74
96
 
75
97
  ---
76
98
 
@@ -85,7 +107,7 @@ project/
85
107
 
86
108
  **Route config** — sibling `.js` file (e.g. `pages/tools/index.js`):
87
109
 
88
- - `middleware` — array of functions or **names** from `createApp({ middlewares })`.
110
+ - `middleware` — array of Express functions, **string names** from `createApp({ middlewares })`, or **`['name', options]` tuples** when the registry entry is a **factory** `(options) => (req, res, next) => …` (bare string calls the factory with `{}`). Built-in **`auth`** / **`guest`** (with `createApp({ auth })`) are factories — e.g. **`['auth', { api: true }]`** for JSON 401 on APIs.
89
111
  - `load(req, ctx)` — async; return object merged into template context; use **`ctx.db`** when `createApp({ db })` is set.
90
112
  - `meta(req, ctx)` — title, description, etc.
91
113
  - `hooks` — `beforeLoad`, `afterRender`, etc. (see hook order below).
@@ -103,7 +125,7 @@ project/
103
125
  **Shapes**
104
126
 
105
127
  1. **Function** — `module.exports = async (req, res) => { ... }`
106
- 2. **Object** — **`handler`**, optional **`middleware`** (names from **`createApp({ middlewares })`**), optional **`schema`**
128
+ 2. **Object** — **`handler`**, optional **`middleware`** (names, functions, or **`['name', options]`** tuples with factory registry entries), optional **`schema`**
107
129
 
108
130
  **Order:** `req.db` (if any) → **Zod** `schema` → **`middleware`** → **`handler`**.
109
131
 
@@ -146,14 +168,14 @@ Analytics plugin adds `fsy.analyticsHead`, `fsy.verificationTags`, etc., when co
146
168
 
147
169
  ## 9. ORM overview
148
170
 
149
- **Define schema** with **`zdb`** (`zdb.id()`, `zdb.uuid()`, `zdb.nanoid()`, `zdb.string({...})`, `zdb.foreignKey`, `zdb.foreignUuid`, `zdb.foreignNanoid`, `zdb.timestamp`, `zdb.json`, …).
171
+ **Define schema** with **`zdb`** (`zdb.id()`, `zdb.uuid()`, `zdb.nanoid()`, `zdb.string({...})`, **`zdb.file({ maxLength, nullable })`** — URL/path string for uploaded assets, `zdb.foreignKey`, `zdb.foreignUuid`, `zdb.foreignNanoid`, `zdb.timestamp`, `zdb.json`, …).
150
172
 
151
173
  **Define model** with **`defineModel({ name, table, schema, relations, scopes, hidden, admin })`**.
152
174
 
153
175
  - **Relations:** `belongsTo`, `hasMany`, `hasOne` with `model: () => OtherModel`.
154
176
  - **Scopes:** `softDelete`, `timestamps`, optional `tenant` column.
155
177
  - **`hidden`:** columns never exposed in admin/API (e.g. `password_hash`).
156
- - **Nanoid PK:** `zdb.nanoid()` / `zdb.nanoid({ maxLength: 12 })` — string primary key; migrations use `string(length)`. On **`create()`**, omitting the PK auto-fills a URL-safe id (built-in generator, same alphabet as `nanoid`). Use **`zdb.foreignNanoid('table', { maxLength })`** when the parent uses nanoid PKs; **`generateNanoid`** is exported from `webspresso` for manual ids.
178
+ - **Nanoid PK:** `zdb.nanoid()` / `zdb.nanoid({ maxLength: 12 })` — string primary key; migrations use `string(length)`. On **`create()`**, omitting the PK auto-fills a URL-safe id (built-in generator, same alphabet as `nanoid`). Use **`zdb.foreignNanoid('table', { maxLength })`** when the parent uses nanoid PKs; **`generateNanoid`** is exported from `webspresso` for manual ids. In API **`schema`**, use **`z.nanoid()`** / **`z.nanoid(12)`** / **`z.nanoid({ maxLength })`** (the `z` from `schema: ({ z })` is extended by Webspresso). **`zodNanoid`** / **`extendZ`** are also exported for non-route use.
157
179
 
158
180
  **Database:** `createDatabase({ client, connection, models: './models' })` — auto-loads `models/*.js` (ignore `_prefix`).
159
181
 
@@ -178,13 +200,17 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
178
200
  | `dashboardPlugin` | Dev route `/_webspresso` — route list |
179
201
  | `sitemapPlugin` | `/sitemap.xml`, robots; optional DB-driven URLs |
180
202
  | `analyticsPlugin` | GA / GTM / Yandex / Bing / Facebook — `fsy` helpers |
181
- | `adminPanelPlugin` | SPA admin CRUD — needs `db` |
203
+ | `adminPanelPlugin` | SPA admin CRUD — needs `db`; optional `uploadUrl` or infer from `uploadPlugin` order |
204
+ | `uploadPlugin` | `POST` multipart (`multer`), `createLocalFileProvider` or custom `provider`; set **`mimeAllowlist`** / **`maxBytes`** in production |
182
205
  | `siteAnalyticsPlugin` | Self-hosted page views + admin charts |
183
206
  | `auditLogPlugin` | Admin mutation audit trail |
184
207
  | `recaptchaPlugin` | v2/v3 + middleware |
185
208
  | `seoCheckerPlugin` | Dev SEO panel |
209
+ | `restResourcePlugin` | Opt-in REST CRUD from models; `?include=` uses ORM eager load (single-level relations only) |
186
210
  | `ormCacheAdminPlugin` | Admin page for ORM cache metrics / purge / invalidate (`db.cache` required) |
187
211
 
212
+ **File uploads:** `require('webspresso').uploadPlugin` / `createLocalFileProvider` — response `{ url, publicUrl, key? }`; admin reads **`settings.uploadUrl`** when `uploadPlugin` is registered before `adminPanelPlugin` (or pass **`adminPanelPlugin({ uploadUrl })`**). Docs: README **File upload plugin**, **`doc/index.html#plugins`**.
213
+
188
214
  **Custom plugin:** `name`, `version`, `register(ctx)`, `onRoutesReady(ctx)` — use `ctx.app`, `ctx.db`, `ctx.addHelper`, `ctx.addRoute`, `ctx.usePlugin('other')`. Plugin failures **warn**; app keeps running.
189
215
 
190
216
  ---
@@ -193,12 +219,12 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
193
219
 
194
220
  | Command | Role |
195
221
  |---------|------|
196
- | `webspresso new` | Scaffold project |
222
+ | `webspresso new` | Scaffold project — includes **`config/load-env.js`** (`.env` chain), **`config/env.schema.js`** (Zod), **`config/app.js`** (`createApp` paths + optional `db` if `webspresso.db.js` exists), thin **`server.js`** |
197
223
  | `webspresso dev` / `start` | Servers |
198
224
  | `webspresso page` / `api` | Interactive scaffolding |
199
225
  | `webspresso db:*` | migrate, rollback, status, make |
200
226
  | `webspresso seed` | Seed data |
201
- | `webspresso doctor` | Env / layout / optional `--db` check |
227
+ | `webspresso doctor` | Env / layout / `.env` vs `.env.example` / `config/load-env.js` / optional `--db` check |
202
228
  | `webspresso skill` | Cursor `SKILL.md` scaffold |
203
229
  | `webspresso skill --preset webspresso` | Copy bundled **Webspresso agent reference** skill |
204
230
  | `webspresso add tailwind` | Tailwind setup |
@@ -217,15 +243,18 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
217
243
  | `SUPPORTED_LOCALES` | Comma-separated |
218
244
  | `BASE_URL` | Canonical / links |
219
245
  | `DATABASE_URL` | DB connection |
246
+ | `SESSION_SECRET` | Session cookie signing — set on auth config **`session.secret`** or read from env in app code |
247
+ | `WEBSPRESSO_ALPINE` | If set to **`1`** or **`true`**, forces **`clientRuntime.alpine`** on (overrides `createApp` for that flag). |
248
+ | `WEBSPRESSO_SWUP` | If set to **`1`** or **`true`**, forces **`clientRuntime.swup`** on (overrides `createApp` for that flag). |
220
249
 
221
250
  ---
222
251
 
223
252
  ## 13. Testing
224
253
 
225
254
  - **Unit / integration:** `npm test` (Vitest).
226
- - **E2E:** `npm run test:e2e` (Playwright).
255
+ - **E2E:** `npm run test:e2e` (Playwright), including **`tests/e2e/swup.spec.js`** for **`clientRuntime`** (Alpine + swup).
227
256
 
228
- Touching **CLI**, **ORM**, or **server routing** — run the relevant suite.
257
+ Touching **CLI**, **ORM**, **server routing**, or **client runtime** — run the relevant suite.
229
258
 
230
259
  ---
231
260
 
@@ -236,13 +265,16 @@ Touching **CLI**, **ORM**, or **server routing** — run the relevant suite.
236
265
  3. **`ctx.db` is undefined** unless `createApp({ db })` receives a `createDatabase()` instance.
237
266
  4. **ORM hidden fields** — never return `hidden` columns to clients; use explicit selects if needed.
238
267
  5. **Zod on API** — invalid input surfaces as validation errors; handlers should assume **`req.input`** is validated when schema is set.
268
+ 6. **Built-in `auth` option** — if you pass **`createApp({ auth })`**, do not expect a custom **`middlewares.auth`** to apply; the framework assigns **`auth`** / **`guest`** to the session guards.
269
+ 7. **Login route vs file router** — **`pages/login.njk`** can shadow custom login handlers; align with **`setupRoutes`** + **`views/`** pattern above.
270
+ 8. **Client runtime + swup** — without **`<main id="swup">`** (or matching **`containers`**), transitions will not replace the intended region. Include **`partials/webspresso-client-runtime.njk`** in the layout when flags are on. Tailwind CDN / third-party scripts may require **`helmet: false`** in dev or relaxed **`script-src`** in production.
239
271
 
240
272
  ---
241
273
 
242
274
  ## 15. When to load this skill
243
275
 
244
- - Adding or changing **pages**, **API routes**, **models**, **migrations**, **plugins**, or **locales**.
276
+ - Adding or changing **pages**, **API routes**, **models**, **migrations**, **plugins**, **locales**, **session auth** (`createAuth`, `createApp({ auth })`, policies), or **client runtime** (`createApp({ clientRuntime })`, Alpine, swup, layout partials).
245
277
  - Explaining **Webspresso** behavior vs plain Express.
246
- - Debugging **404 order**, **i18n**, **session/auth**, **ORM**, or **admin** integration.
278
+ - Debugging **404 order**, **i18n**, **session/auth**, **ORM**, **admin** integration, or **swup / Alpine** (e.g. missing **`#swup`**, CSP blocking scripts).
247
279
 
248
- For authoritative long-form detail, see **[README.md](../../../README.md)** in the repo.
280
+ For authoritative long-form detail, see **[README.md](../../../README.md)** and **[`doc/index.html`](../../../doc/index.html)** (e.g. **Authentication**, **[Client runtime](../../../doc/index.html#client-runtime)**) in the repo.