webspresso 0.0.91 → 0.0.94
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 +103 -2864
- package/bin/commands/admin-password.js +8 -2
- package/bin/commands/api.js +7 -1
- package/bin/commands/favicon-generate.js +6 -4
- package/bin/commands/mcp.js +162 -0
- package/bin/commands/new.js +7 -1
- package/bin/commands/page.js +7 -1
- package/bin/commands/polar-migrate.js +50 -0
- package/bin/commands/seed.js +7 -1
- package/bin/commands/service.js +8 -2
- package/bin/commands/skill.js +7 -1
- package/bin/webspresso.js +4 -0
- package/core/auth/tokens.js +16 -0
- package/core/compileSchema.js +1 -5
- package/core/compression/compressible.js +17 -5
- package/core/compression/compression-stream.js +1 -1
- package/core/compression/middleware.js +9 -0
- package/core/compression/negotiate.js +23 -11
- package/core/kernel/app.js +2 -1
- package/core/kernel/index.js +5 -1
- package/core/orm/cache/fingerprint.js +23 -5
- package/core/orm/cache/layer.js +1 -1
- package/core/orm/eager-loader.js +54 -9
- package/core/orm/index.js +42 -3
- package/core/orm/model.js +11 -2
- package/core/orm/transaction.js +3 -1
- package/core/queue/adapters/database.js +46 -13
- package/core/queue/adapters/memory.js +21 -0
- package/core/queue/adapters/redis.js +21 -0
- package/core/queue/manager.js +46 -20
- package/core/ssr/stream.js +58 -14
- package/core/validation/index.js +70 -0
- package/index.d.ts +99 -5
- package/index.js +7 -1
- package/package.json +9 -1
- package/plugins/admin-panel/auth.js +10 -0
- package/plugins/admin-panel/client/parts/01-state-api-breadcrumb.js +6 -1
- package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +18 -8
- package/plugins/admin-panel/client/parts/07-model-list.js +9 -4
- package/plugins/admin-panel/client/parts/08-record-list.js +20 -2
- package/plugins/admin-panel/index.js +65 -6
- package/plugins/admin-panel/modules/bulk-actions.js +9 -2
- package/plugins/admin-panel/modules/dashboard.js +8 -1
- package/plugins/content/index.js +5 -3
- package/plugins/data-exchange/export-xlsx.js +28 -6
- package/plugins/data-exchange/import.js +120 -58
- package/plugins/data-exchange/index.js +5 -0
- package/plugins/data-exchange/parse-table.js +14 -5
- package/plugins/data-exchange/record-selection.js +2 -0
- package/plugins/index.js +6 -0
- package/plugins/mcp/auth.js +104 -0
- package/plugins/mcp/discovery.js +88 -0
- package/plugins/mcp/index.js +208 -0
- package/plugins/mcp/prompts.js +149 -0
- package/plugins/mcp/providers/orm.js +325 -0
- package/plugins/mcp/providers/services.js +190 -0
- package/plugins/mcp/providers/system.js +87 -0
- package/plugins/mcp/server.js +472 -0
- package/plugins/mcp/transports/sse.js +156 -0
- package/plugins/mcp/transports/stdio.js +108 -0
- package/plugins/polar/.env.example +12 -0
- package/plugins/polar/CHANGELOG.md +38 -0
- package/plugins/polar/README.md +158 -0
- package/plugins/polar/index.js +144 -0
- package/plugins/polar/src/api.js +54 -0
- package/plugins/polar/src/checkout.js +111 -0
- package/plugins/polar/src/config.js +88 -0
- package/plugins/polar/src/env.schema.js +36 -0
- package/plugins/polar/src/middleware.js +37 -0
- package/plugins/polar/src/migration.js +58 -0
- package/plugins/polar/src/nunjucks-filters.js +56 -0
- package/plugins/polar/src/portal.js +51 -0
- package/plugins/polar/src/rate-limit.js +70 -0
- package/plugins/polar/src/routes.js +212 -0
- package/plugins/polar/src/sync.js +138 -0
- package/plugins/polar/src/urls.js +117 -0
- package/plugins/polar/src/user-resolver.js +195 -0
- package/plugins/polar/src/webhooks.js +248 -0
- package/src/file-router.js +203 -125
- package/src/helpers.js +60 -13
- package/src/njk-frontmatter.js +24 -14
- package/src/server.js +30 -12
- package/src/services/discovery.js +2 -1
- package/src/services/registry.js +2 -0
- package/src/services/validator.js +2 -53
- package/templates/skills/webspresso-usage/REFERENCE-framework.md +7 -4
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
const fs = require('fs');
|
|
8
8
|
const path = require('path');
|
|
9
|
+
const { trimUrlPathSlashes } = require('../../core/url-path-normalize');
|
|
9
10
|
|
|
10
11
|
const VALID_EXTENSIONS = new Set(['.js', '.mjs', '.cjs']);
|
|
11
12
|
|
|
@@ -50,7 +51,7 @@ function filePathToServiceName(relativePath) {
|
|
|
50
51
|
}
|
|
51
52
|
|
|
52
53
|
// Cross-platform slash normalization (Windows \ to Unix /)
|
|
53
|
-
const normalized = relativePath.replace(/\\/g, '/')
|
|
54
|
+
const normalized = trimUrlPathSlashes(relativePath.replace(/\\/g, '/'));
|
|
54
55
|
const ext = path.extname(normalized);
|
|
55
56
|
const withoutExt = ext ? normalized.slice(0, -ext.length) : normalized;
|
|
56
57
|
const segments = withoutExt.split('/').filter(Boolean);
|
package/src/services/registry.js
CHANGED
|
@@ -102,6 +102,7 @@ class ServiceRegistry {
|
|
|
102
102
|
rawHandler: definition.handler,
|
|
103
103
|
memoize: memoizeFn,
|
|
104
104
|
metadata: definition.metadata || {},
|
|
105
|
+
description: definition.description || definition.metadata?.description || '',
|
|
105
106
|
auth: definition.auth,
|
|
106
107
|
cache: definition.cache,
|
|
107
108
|
timeout: definition.timeout,
|
|
@@ -158,6 +159,7 @@ class ServiceRegistry {
|
|
|
158
159
|
rawHandler: def.handler,
|
|
159
160
|
memoize: memoizeFn,
|
|
160
161
|
metadata: def.metadata || {},
|
|
162
|
+
description: def.description || def.metadata?.description || '',
|
|
161
163
|
auth: def.auth,
|
|
162
164
|
cache: def.cache,
|
|
163
165
|
timeout: def.timeout,
|
|
@@ -4,60 +4,9 @@
|
|
|
4
4
|
* @module src/services/validator
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
const z = require('zod');
|
|
8
7
|
const { ValidationError } = require('../../core/errors');
|
|
9
|
-
const {
|
|
10
|
-
|
|
11
|
-
/** Zod instance extended with z.nanoid() */
|
|
12
|
-
const zForServices = extendZ(z);
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Check if object contains dangerous prototype pollution keys
|
|
16
|
-
* @param {*} obj
|
|
17
|
-
* @returns {boolean}
|
|
18
|
-
*/
|
|
19
|
-
function hasDangerousKeys(obj) {
|
|
20
|
-
if (obj === null || typeof obj !== 'object') {
|
|
21
|
-
return false;
|
|
22
|
-
}
|
|
23
|
-
if (Array.isArray(obj)) {
|
|
24
|
-
return obj.some(item => hasDangerousKeys(item));
|
|
25
|
-
}
|
|
26
|
-
for (const key of Object.keys(obj)) {
|
|
27
|
-
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
28
|
-
return true;
|
|
29
|
-
}
|
|
30
|
-
if (typeof obj[key] === 'object' && obj[key] !== null && hasDangerousKeys(obj[key])) {
|
|
31
|
-
return true;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Sanitize input against prototype pollution
|
|
39
|
-
* @param {*} input
|
|
40
|
-
* @returns {*} Sanitized input
|
|
41
|
-
*/
|
|
42
|
-
function sanitizeInput(input) {
|
|
43
|
-
if (input === null || typeof input !== 'object') {
|
|
44
|
-
return input;
|
|
45
|
-
}
|
|
46
|
-
if (!hasDangerousKeys(input)) {
|
|
47
|
-
return input;
|
|
48
|
-
}
|
|
49
|
-
if (Array.isArray(input)) {
|
|
50
|
-
return input.map(item => sanitizeInput(item));
|
|
51
|
-
}
|
|
52
|
-
const clean = {};
|
|
53
|
-
for (const key of Object.keys(input)) {
|
|
54
|
-
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
clean[key] = sanitizeInput(input[key]);
|
|
58
|
-
}
|
|
59
|
-
return clean;
|
|
60
|
-
}
|
|
8
|
+
const { z: zForServices, sanitizeInput, hasDangerousKeys } = require('../../core/validation');
|
|
9
|
+
const z = zForServices;
|
|
61
10
|
|
|
62
11
|
/**
|
|
63
12
|
* Compile a concise type string descriptor into a Zod schema
|
|
@@ -4,8 +4,10 @@ Sections follow the source repo layout (`index.js`, `src/`, `core/orm`, `doc/ind
|
|
|
4
4
|
|
|
5
5
|
## 1. What this framework is
|
|
6
6
|
|
|
7
|
-
- **
|
|
8
|
-
- **
|
|
7
|
+
- **Architecture**: Modern full-stack Node.js framework with Next.js/Nuxt-style file-based routing.
|
|
8
|
+
- **SSR**: Native server-side rendering with **Nunjucks**; URLs map directly to files under `pages/`.
|
|
9
|
+
- **API**: 100% file-based handlers under `pages/api/` with HTTP method suffixes (`.get.js`, `.post.js`, `[id].delete.js`) and declarative **Zod** validation (`req.input`).
|
|
10
|
+
- ⚠️ **CRITICAL ANTI-PATTERN**: **NEVER** create a `routes/` or `src/routes/` directory. **NEVER** use `app.get()`, `app.post()`, or `express.Router()`. All application routes must live under `pages/` and `pages/api/`.
|
|
9
11
|
- **i18n**: JSON locales; `t('key')` in templates.
|
|
10
12
|
- **ORM**: Knex-backed layer in `core/orm` — `defineModel`, `zdb` schema helpers, repositories, query builder, migrations.
|
|
11
13
|
- **Plugins**: Register in `createApp({ plugins })`; optional `db` passed as `ctx.db`.
|
|
@@ -60,7 +62,7 @@ project/
|
|
|
60
62
|
| `pageAssets` | Opt-in **`true`** or **`{ enabled?, stylesheets?, scripts? }`**. When on, route **`load()`** may return reserved keys **`stylesheets`** (string or list; also `{ href, media? }` objects) and **`scripts`** (string, `{ src, defer?, async?, type? }`, or list). They are removed from the root Nunjucks context and passed as **`pageHead`** with **`pageAssets: true`**. The app layout must print them (see [`views/layout.njk`](../../../views/layout.njk) in the package). Default **off** — `stylesheets` / `scripts` in **`load()`** behave as normal data keys. |
|
|
61
63
|
| `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. |
|
|
62
64
|
| `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). |
|
|
63
|
-
| `setupRoutes(app, ctx)` |
|
|
65
|
+
| `setupRoutes(app, ctx)` | Low-level server extension hook (e.g. mounting third-party sub-apps or raw middleware). ⚠️ **NEVER** use `setupRoutes` to define application domain or API routes. All application endpoints **MUST** live under `pages/` and `pages/api/`. |
|
|
64
66
|
|
|
65
67
|
**Returns:** `{ app, nunjucksEnv, pluginManager, authMiddleware }` — `authMiddleware` is **`null`** when `auth` was not configured.
|
|
66
68
|
|
|
@@ -211,6 +213,7 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
|
|
|
211
213
|
| `auditLogPlugin` | Admin mutation audit trail |
|
|
212
214
|
| `recaptchaPlugin` | v2/v3 + middleware |
|
|
213
215
|
| `emailPlugin` | MJML + Nodemailer sending with optional admin UI and auth bridge |
|
|
216
|
+
| `polarPlugin` | Polar.sh billing: checkout, portal, webhooks, tier sync (`webspresso polar:migrate`) |
|
|
214
217
|
| `seoCheckerPlugin` | Dev SEO panel |
|
|
215
218
|
| `restResourcePlugin` | Opt-in REST CRUD from models; `?include=` uses ORM eager load (single-level relations only) |
|
|
216
219
|
| `ormCacheAdminPlugin` | Admin page for ORM cache metrics / purge / invalidate (`db.cache` required) |
|
|
@@ -267,7 +270,7 @@ Pass **`db`** into **`createApp({ db })`** so **`ctx.db`** works in pages and pl
|
|
|
267
270
|
|
|
268
271
|
## 14. Pitfalls (for agents)
|
|
269
272
|
|
|
270
|
-
1. **
|
|
273
|
+
1. **NEVER use Express routes (`app.get` / `routes/`)** — Webspresso is 100% file-based. Never create `routes/` or call `app.get()`. All routes must live in `pages/` and `pages/api/`.
|
|
271
274
|
2. **File-router order** — understand precedence vs manual routes.
|
|
272
275
|
3. **`ctx.db`** — only when `createApp({ db })` is set.
|
|
273
276
|
4. **ORM hidden fields** — never expose to clients unintentionally.
|