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.
- package/README.md +50 -0
- package/bin/commands/doctor.js +23 -0
- package/bin/commands/new.js +106 -15
- package/core/orm/migrations/scaffold.js +6 -0
- package/core/orm/schema-helpers.js +19 -0
- package/core/orm/types.js +1 -1
- package/index.d.ts +30 -0
- package/index.js +15 -1
- package/package.json +3 -1
- package/plugins/admin-panel/api.js +5 -5
- package/plugins/admin-panel/components.js +184 -0
- package/plugins/admin-panel/core/registry.js +1 -0
- package/plugins/admin-panel/field-renderers/file-upload.js +135 -66
- package/plugins/admin-panel/field-renderers/index.js +1 -0
- package/plugins/admin-panel/index.js +8 -0
- package/plugins/index.js +3 -0
- package/plugins/upload/index.js +188 -0
- package/plugins/upload/local-file-provider.js +122 -0
- package/templates/skills/webspresso-usage/SKILL.md +54 -22
|
@@ -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
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
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
|
|
70
|
-
| `auth` |
|
|
71
|
-
| `setupRoutes(app, ctx)` | **Register custom Express routes here** — runs **after** file routes and plugins’ `onRoutesReady`, **before** 404.
|
|
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
|
|
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
|
|
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
|
|
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**,
|
|
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 **
|
|
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 **
|
|
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.
|