webspresso 0.0.66 → 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 +74 -1
- 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 +36 -0
- package/index.js +19 -1
- package/package.json +11 -4
- 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/src/client-runtime/bootstrap-alpine-swup.js +34 -0
- package/src/client-runtime/bootstrap-swup.js +26 -0
- package/src/client-runtime/mount.js +65 -0
- package/src/client-runtime/resolve.js +40 -0
- package/src/file-router.js +16 -2
- package/src/server.js +11 -2
- package/templates/skills/webspresso-usage/SKILL.md +54 -21
- package/views/partials/webspresso-client-runtime.njk +15 -0
|
@@ -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,10 +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
|
-
| `
|
|
70
|
-
| `
|
|
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)). |
|
|
71
74
|
|
|
72
|
-
**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)**.
|
|
73
96
|
|
|
74
97
|
---
|
|
75
98
|
|
|
@@ -84,7 +107,7 @@ project/
|
|
|
84
107
|
|
|
85
108
|
**Route config** — sibling `.js` file (e.g. `pages/tools/index.js`):
|
|
86
109
|
|
|
87
|
-
- `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.
|
|
88
111
|
- `load(req, ctx)` — async; return object merged into template context; use **`ctx.db`** when `createApp({ db })` is set.
|
|
89
112
|
- `meta(req, ctx)` — title, description, etc.
|
|
90
113
|
- `hooks` — `beforeLoad`, `afterRender`, etc. (see hook order below).
|
|
@@ -102,7 +125,7 @@ project/
|
|
|
102
125
|
**Shapes**
|
|
103
126
|
|
|
104
127
|
1. **Function** — `module.exports = async (req, res) => { ... }`
|
|
105
|
-
2. **Object** — **`handler`**, optional **`middleware`** (names
|
|
128
|
+
2. **Object** — **`handler`**, optional **`middleware`** (names, functions, or **`['name', options]`** tuples with factory registry entries), optional **`schema`**
|
|
106
129
|
|
|
107
130
|
**Order:** `req.db` (if any) → **Zod** `schema` → **`middleware`** → **`handler`**.
|
|
108
131
|
|
|
@@ -145,14 +168,14 @@ Analytics plugin adds `fsy.analyticsHead`, `fsy.verificationTags`, etc., when co
|
|
|
145
168
|
|
|
146
169
|
## 9. ORM overview
|
|
147
170
|
|
|
148
|
-
**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`, …).
|
|
149
172
|
|
|
150
173
|
**Define model** with **`defineModel({ name, table, schema, relations, scopes, hidden, admin })`**.
|
|
151
174
|
|
|
152
175
|
- **Relations:** `belongsTo`, `hasMany`, `hasOne` with `model: () => OtherModel`.
|
|
153
176
|
- **Scopes:** `softDelete`, `timestamps`, optional `tenant` column.
|
|
154
177
|
- **`hidden`:** columns never exposed in admin/API (e.g. `password_hash`).
|
|
155
|
-
- **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.
|
|
156
179
|
|
|
157
180
|
**Database:** `createDatabase({ client, connection, models: './models' })` — auto-loads `models/*.js` (ignore `_prefix`).
|
|
158
181
|
|
|
@@ -177,13 +200,17 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
|
|
|
177
200
|
| `dashboardPlugin` | Dev route `/_webspresso` — route list |
|
|
178
201
|
| `sitemapPlugin` | `/sitemap.xml`, robots; optional DB-driven URLs |
|
|
179
202
|
| `analyticsPlugin` | GA / GTM / Yandex / Bing / Facebook — `fsy` helpers |
|
|
180
|
-
| `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 |
|
|
181
205
|
| `siteAnalyticsPlugin` | Self-hosted page views + admin charts |
|
|
182
206
|
| `auditLogPlugin` | Admin mutation audit trail |
|
|
183
207
|
| `recaptchaPlugin` | v2/v3 + middleware |
|
|
184
208
|
| `seoCheckerPlugin` | Dev SEO panel |
|
|
209
|
+
| `restResourcePlugin` | Opt-in REST CRUD from models; `?include=` uses ORM eager load (single-level relations only) |
|
|
185
210
|
| `ormCacheAdminPlugin` | Admin page for ORM cache metrics / purge / invalidate (`db.cache` required) |
|
|
186
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
|
+
|
|
187
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.
|
|
188
215
|
|
|
189
216
|
---
|
|
@@ -192,12 +219,12 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
|
|
|
192
219
|
|
|
193
220
|
| Command | Role |
|
|
194
221
|
|---------|------|
|
|
195
|
-
| `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`** |
|
|
196
223
|
| `webspresso dev` / `start` | Servers |
|
|
197
224
|
| `webspresso page` / `api` | Interactive scaffolding |
|
|
198
225
|
| `webspresso db:*` | migrate, rollback, status, make |
|
|
199
226
|
| `webspresso seed` | Seed data |
|
|
200
|
-
| `webspresso doctor` | Env / layout / optional `--db` check |
|
|
227
|
+
| `webspresso doctor` | Env / layout / `.env` vs `.env.example` / `config/load-env.js` / optional `--db` check |
|
|
201
228
|
| `webspresso skill` | Cursor `SKILL.md` scaffold |
|
|
202
229
|
| `webspresso skill --preset webspresso` | Copy bundled **Webspresso agent reference** skill |
|
|
203
230
|
| `webspresso add tailwind` | Tailwind setup |
|
|
@@ -216,15 +243,18 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
|
|
|
216
243
|
| `SUPPORTED_LOCALES` | Comma-separated |
|
|
217
244
|
| `BASE_URL` | Canonical / links |
|
|
218
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). |
|
|
219
249
|
|
|
220
250
|
---
|
|
221
251
|
|
|
222
252
|
## 13. Testing
|
|
223
253
|
|
|
224
254
|
- **Unit / integration:** `npm test` (Vitest).
|
|
225
|
-
- **E2E:** `npm run test:e2e` (Playwright).
|
|
255
|
+
- **E2E:** `npm run test:e2e` (Playwright), including **`tests/e2e/swup.spec.js`** for **`clientRuntime`** (Alpine + swup).
|
|
226
256
|
|
|
227
|
-
Touching **CLI**, **ORM**,
|
|
257
|
+
Touching **CLI**, **ORM**, **server routing**, or **client runtime** — run the relevant suite.
|
|
228
258
|
|
|
229
259
|
---
|
|
230
260
|
|
|
@@ -235,13 +265,16 @@ Touching **CLI**, **ORM**, or **server routing** — run the relevant suite.
|
|
|
235
265
|
3. **`ctx.db` is undefined** unless `createApp({ db })` receives a `createDatabase()` instance.
|
|
236
266
|
4. **ORM hidden fields** — never return `hidden` columns to clients; use explicit selects if needed.
|
|
237
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.
|
|
238
271
|
|
|
239
272
|
---
|
|
240
273
|
|
|
241
274
|
## 15. When to load this skill
|
|
242
275
|
|
|
243
|
-
- 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).
|
|
244
277
|
- Explaining **Webspresso** behavior vs plain Express.
|
|
245
|
-
- 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).
|
|
246
279
|
|
|
247
|
-
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.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{# Served by createApp when clientRuntime.alpine / .swup are enabled. See src/client-runtime/. #}
|
|
2
|
+
{% if clientRuntime and clientRuntime.alpine %}
|
|
3
|
+
<style>[x-cloak] { display: none !important; }</style>
|
|
4
|
+
<script defer src="/__webspresso/client-runtime/alpine.min.js"></script>
|
|
5
|
+
{% endif %}
|
|
6
|
+
{% if clientRuntime and clientRuntime.swup %}
|
|
7
|
+
<script defer src="/__webspresso/client-runtime/swup.umd.js"></script>
|
|
8
|
+
<script defer src="/__webspresso/client-runtime/swup-head-plugin.umd.js"></script>
|
|
9
|
+
<script defer src="/__webspresso/client-runtime/swup-scripts-plugin.umd.js"></script>
|
|
10
|
+
{% if clientRuntime.alpine %}
|
|
11
|
+
<script defer src="/__webspresso/client-runtime/bootstrap-alpine-swup.js"></script>
|
|
12
|
+
{% else %}
|
|
13
|
+
<script defer src="/__webspresso/client-runtime/bootstrap-swup.js"></script>
|
|
14
|
+
{% endif %}
|
|
15
|
+
{% endif %}
|