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.
Files changed (86) hide show
  1. package/README.md +103 -2864
  2. package/bin/commands/admin-password.js +8 -2
  3. package/bin/commands/api.js +7 -1
  4. package/bin/commands/favicon-generate.js +6 -4
  5. package/bin/commands/mcp.js +162 -0
  6. package/bin/commands/new.js +7 -1
  7. package/bin/commands/page.js +7 -1
  8. package/bin/commands/polar-migrate.js +50 -0
  9. package/bin/commands/seed.js +7 -1
  10. package/bin/commands/service.js +8 -2
  11. package/bin/commands/skill.js +7 -1
  12. package/bin/webspresso.js +4 -0
  13. package/core/auth/tokens.js +16 -0
  14. package/core/compileSchema.js +1 -5
  15. package/core/compression/compressible.js +17 -5
  16. package/core/compression/compression-stream.js +1 -1
  17. package/core/compression/middleware.js +9 -0
  18. package/core/compression/negotiate.js +23 -11
  19. package/core/kernel/app.js +2 -1
  20. package/core/kernel/index.js +5 -1
  21. package/core/orm/cache/fingerprint.js +23 -5
  22. package/core/orm/cache/layer.js +1 -1
  23. package/core/orm/eager-loader.js +54 -9
  24. package/core/orm/index.js +42 -3
  25. package/core/orm/model.js +11 -2
  26. package/core/orm/transaction.js +3 -1
  27. package/core/queue/adapters/database.js +46 -13
  28. package/core/queue/adapters/memory.js +21 -0
  29. package/core/queue/adapters/redis.js +21 -0
  30. package/core/queue/manager.js +46 -20
  31. package/core/ssr/stream.js +58 -14
  32. package/core/validation/index.js +70 -0
  33. package/index.d.ts +99 -5
  34. package/index.js +7 -1
  35. package/package.json +9 -1
  36. package/plugins/admin-panel/auth.js +10 -0
  37. package/plugins/admin-panel/client/parts/01-state-api-breadcrumb.js +6 -1
  38. package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +18 -8
  39. package/plugins/admin-panel/client/parts/07-model-list.js +9 -4
  40. package/plugins/admin-panel/client/parts/08-record-list.js +20 -2
  41. package/plugins/admin-panel/index.js +65 -6
  42. package/plugins/admin-panel/modules/bulk-actions.js +9 -2
  43. package/plugins/admin-panel/modules/dashboard.js +8 -1
  44. package/plugins/content/index.js +5 -3
  45. package/plugins/data-exchange/export-xlsx.js +28 -6
  46. package/plugins/data-exchange/import.js +120 -58
  47. package/plugins/data-exchange/index.js +5 -0
  48. package/plugins/data-exchange/parse-table.js +14 -5
  49. package/plugins/data-exchange/record-selection.js +2 -0
  50. package/plugins/index.js +6 -0
  51. package/plugins/mcp/auth.js +104 -0
  52. package/plugins/mcp/discovery.js +88 -0
  53. package/plugins/mcp/index.js +208 -0
  54. package/plugins/mcp/prompts.js +149 -0
  55. package/plugins/mcp/providers/orm.js +325 -0
  56. package/plugins/mcp/providers/services.js +190 -0
  57. package/plugins/mcp/providers/system.js +87 -0
  58. package/plugins/mcp/server.js +472 -0
  59. package/plugins/mcp/transports/sse.js +156 -0
  60. package/plugins/mcp/transports/stdio.js +108 -0
  61. package/plugins/polar/.env.example +12 -0
  62. package/plugins/polar/CHANGELOG.md +38 -0
  63. package/plugins/polar/README.md +158 -0
  64. package/plugins/polar/index.js +144 -0
  65. package/plugins/polar/src/api.js +54 -0
  66. package/plugins/polar/src/checkout.js +111 -0
  67. package/plugins/polar/src/config.js +88 -0
  68. package/plugins/polar/src/env.schema.js +36 -0
  69. package/plugins/polar/src/middleware.js +37 -0
  70. package/plugins/polar/src/migration.js +58 -0
  71. package/plugins/polar/src/nunjucks-filters.js +56 -0
  72. package/plugins/polar/src/portal.js +51 -0
  73. package/plugins/polar/src/rate-limit.js +70 -0
  74. package/plugins/polar/src/routes.js +212 -0
  75. package/plugins/polar/src/sync.js +138 -0
  76. package/plugins/polar/src/urls.js +117 -0
  77. package/plugins/polar/src/user-resolver.js +195 -0
  78. package/plugins/polar/src/webhooks.js +248 -0
  79. package/src/file-router.js +203 -125
  80. package/src/helpers.js +60 -13
  81. package/src/njk-frontmatter.js +24 -14
  82. package/src/server.js +30 -12
  83. package/src/services/discovery.js +2 -1
  84. package/src/services/registry.js +2 -0
  85. package/src/services/validator.js +2 -53
  86. 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, '/').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);
@@ -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 { extendZ } = require('../../core/orm/utils/nanoid');
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
- - **SSR**: Express + **Nunjucks**; URLs map to files under `pages/`.
8
- - **API**: File-based handlers under `pages/api/` with method suffixes and optional **Zod** validation (`req.input`).
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)` | **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)). |
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. **Custom Express routes** — use **`setupRoutes`**, not only `app.use` after `createApp` returns.
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.