webspresso 0.0.108 → 0.0.110

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 (184) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +3 -3
  3. package/bin/commands/add-esbuild.js +7 -3
  4. package/bin/commands/add-tailwind.js +9 -5
  5. package/bin/commands/build.js +20 -4
  6. package/bin/commands/dev.js +57 -7
  7. package/bin/commands/doctor.js +42 -1
  8. package/bin/commands/favicon-generate.js +10 -3
  9. package/bin/commands/new.js +8 -3
  10. package/bin/commands/start.js +3 -1
  11. package/bin/utils/add-command.js +16 -0
  12. package/core/app.js +45 -3
  13. package/core/auth/authenticate.js +3 -3
  14. package/core/auth/hash.js +167 -43
  15. package/core/auth/index.js +13 -1
  16. package/core/auth/jwt.js +21 -2
  17. package/core/auth/manager.js +63 -14
  18. package/core/auth/middleware.js +4 -2
  19. package/core/auth/oauth.js +5 -1
  20. package/core/auth/tokens.js +7 -2
  21. package/core/auth/totp.js +42 -6
  22. package/core/auth/user-agent.js +2 -0
  23. package/core/client/adapter/datastar.js +1401 -0
  24. package/core/client/api.js +1337 -0
  25. package/core/client/controller.js +1706 -0
  26. package/core/client/debug.js +367 -0
  27. package/core/client/devtool.js +1134 -0
  28. package/core/client/forms.js +1164 -0
  29. package/core/client/fragments.js +894 -0
  30. package/core/client/index.d.ts +59 -0
  31. package/core/client/index.js +391 -0
  32. package/core/client/lite.js +175 -0
  33. package/core/client/server-fragments.js +868 -0
  34. package/core/client/storage.js +339 -0
  35. package/core/client/utils.js +281 -0
  36. package/core/compression/middleware.js +277 -26
  37. package/core/context/app-context.js +25 -3
  38. package/core/context/request.js +32 -4
  39. package/core/errors/middleware.js +14 -0
  40. package/core/events/dispatcher.js +33 -0
  41. package/core/forms/flash.js +136 -102
  42. package/core/health/middleware.js +36 -6
  43. package/core/http/pipeline.js +45 -6
  44. package/core/index.js +25 -7
  45. package/core/kernel/view.js +41 -10
  46. package/core/metrics/middleware.js +30 -6
  47. package/core/metrics/registry.js +13 -5
  48. package/core/orm/cache/fingerprint.js +32 -11
  49. package/core/orm/cache/layer.js +19 -2
  50. package/core/orm/hidden.js +145 -0
  51. package/core/orm/model.js +48 -2
  52. package/core/orm/query-builder.js +343 -6
  53. package/core/orm/query-filters.js +14 -2
  54. package/core/orm/repository.js +64 -13
  55. package/core/orm/schema-helpers.js +9 -6
  56. package/core/orm/transaction.js +50 -6
  57. package/core/orm/types.js +4 -0
  58. package/core/queue/adapters/database.js +184 -2
  59. package/core/queue/adapters/memory.js +153 -5
  60. package/core/queue/adapters/redis.js +59 -4
  61. package/core/queue/job.js +14 -1
  62. package/core/queue/manager.js +115 -0
  63. package/core/resilience/circuit-breaker.js +27 -8
  64. package/core/services/builtins/exchange.js +174 -7
  65. package/core/services/builtins/file-manager.js +36 -0
  66. package/core/services/builtins/mail.js +27 -0
  67. package/core/services/builtins/queue.js +144 -0
  68. package/core/services/builtins/security.js +118 -0
  69. package/core/services/builtins/webhook.js +110 -0
  70. package/core/services/executor.js +38 -16
  71. package/core/services/index.js +4 -1
  72. package/core/sse/stream.js +28 -5
  73. package/core/utils/timeout.js +8 -1
  74. package/core/validation/compiler.js +10 -7
  75. package/index.d.ts +1320 -74
  76. package/index.js +128 -8
  77. package/package.json +75 -27
  78. package/plugins/admin-panel/client/parts/08-record-list.js +717 -70
  79. package/plugins/admin-panel/index.js +19 -8
  80. package/plugins/csrf/index.js +3 -3
  81. package/plugins/data-exchange/export.js +214 -0
  82. package/plugins/data-exchange/import.js +48 -5
  83. package/plugins/data-exchange/index.js +70 -28
  84. package/plugins/data-exchange/preview.js +266 -0
  85. package/plugins/data-exchange/template.js +242 -0
  86. package/plugins/email/admin-component.js +783 -141
  87. package/plugins/email/api-handlers.js +51 -1
  88. package/plugins/email/index.js +5 -0
  89. package/plugins/email/service.js +48 -0
  90. package/plugins/file-manager/admin-component.js +1546 -70
  91. package/plugins/file-manager/api-handlers.js +166 -1
  92. package/plugins/file-manager/core.js +598 -8
  93. package/plugins/file-manager/index.js +8 -0
  94. package/plugins/index.js +7 -0
  95. package/plugins/mcp/auth.js +3 -3
  96. package/plugins/oauth/index.js +36 -3
  97. package/plugins/queue/admin-component.js +1092 -0
  98. package/plugins/queue/api-handlers.js +248 -0
  99. package/plugins/queue/index.js +69 -0
  100. package/plugins/rest-resources/index.js +7 -2
  101. package/plugins/security/admin-component.js +689 -0
  102. package/plugins/security/api-handlers.js +169 -0
  103. package/plugins/security/audit.js +153 -0
  104. package/plugins/security/bruteforce.js +244 -0
  105. package/plugins/security/firewall.js +459 -0
  106. package/plugins/security/headers.js +214 -0
  107. package/plugins/security/honeypot.js +234 -0
  108. package/plugins/security/incident-recorder.js +137 -0
  109. package/plugins/security/index.js +211 -0
  110. package/plugins/seo-checker/analyzer.js +20 -7
  111. package/plugins/upload/index.js +36 -0
  112. package/plugins/webhooks/admin-component.js +702 -175
  113. package/plugins/webhooks/api-handlers.js +75 -1
  114. package/plugins/webhooks/dispatcher.js +290 -11
  115. package/plugins/webhooks/index.js +37 -2
  116. package/plugins/webhooks/sender.js +56 -0
  117. package/plugins/xlsx/engine.js +19 -4
  118. package/src/api/api-loader.js +19 -1
  119. package/src/bundle/index.js +443 -17
  120. package/src/client-runtime/bootstrap-swup.js +9 -0
  121. package/src/client-runtime/mount.js +15 -20
  122. package/src/client-runtime/resolve.js +3 -2
  123. package/src/dev/api-typegen.js +1300 -0
  124. package/src/dev/banner.js +10 -1
  125. package/src/dev/colors.js +1 -1
  126. package/src/dev/index.js +7 -1
  127. package/src/dev/typegen.js +173 -17
  128. package/src/dev-reload/index.js +1 -1
  129. package/src/discovery/file-route-parser.js +17 -3
  130. package/src/discovery/scan-routes.js +4 -1
  131. package/src/file-router.js +253 -69
  132. package/src/helpers.js +46 -26
  133. package/src/njk-frontmatter.js +30 -4
  134. package/src/routing/cascading.js +26 -8
  135. package/src/routing/mount-discovered-routes.js +76 -0
  136. package/src/server.js +231 -70
  137. package/views/partials/webspresso-client-runtime.njk +1 -9
  138. package/.agents/ADMIN.md +0 -426
  139. package/.agents/AGENTS.md +0 -96
  140. package/.agents/ARCHITECTURE.md +0 -163
  141. package/.agents/AUTH.md +0 -581
  142. package/.agents/CACHE.md +0 -148
  143. package/.agents/CLI.md +0 -649
  144. package/.agents/COMPRESSION.md +0 -59
  145. package/.agents/CONTEXT.md +0 -152
  146. package/.agents/CONVENTIONS.md +0 -50
  147. package/.agents/EARLY_HINTS.md +0 -120
  148. package/.agents/EMAIL.md +0 -223
  149. package/.agents/ERRORS.md +0 -260
  150. package/.agents/EVENTS.md +0 -179
  151. package/.agents/FLAGS.md +0 -118
  152. package/.agents/HEALTH.md +0 -118
  153. package/.agents/LIMITS.md +0 -109
  154. package/.agents/LOGGING.md +0 -93
  155. package/.agents/MCP.md +0 -103
  156. package/.agents/METRICS.md +0 -127
  157. package/.agents/MIGRATION_JOBS.md +0 -95
  158. package/.agents/ORM.md +0 -700
  159. package/.agents/PLUGINS.md +0 -729
  160. package/.agents/QUEUE.md +0 -290
  161. package/.agents/RATE_LIMIT.md +0 -147
  162. package/.agents/REALTIME.md +0 -213
  163. package/.agents/RESILIENCE.md +0 -235
  164. package/.agents/ROUTING.md +0 -605
  165. package/.agents/SCALE_OUT.md +0 -109
  166. package/.agents/SECRETS.md +0 -117
  167. package/.agents/SERVICES.md +0 -341
  168. package/.agents/SHUTDOWN.md +0 -74
  169. package/.agents/STREAMING.md +0 -108
  170. package/.agents/WORKFLOW.md +0 -27
  171. package/.agents/internal/DOCUMENTATION_REVIEW.md +0 -485
  172. package/.agents/internal/TECHNICAL_REVIEW.md +0 -428
  173. package/.agents/skills/webspresso-admin-and-plugins/SKILL.md +0 -122
  174. package/.agents/skills/webspresso-framework/SKILL.md +0 -89
  175. package/.agents/skills/webspresso-orm-and-database/SKILL.md +0 -127
  176. package/.agents/skills/webspresso-routing-and-api/SKILL.md +0 -130
  177. package/.agents/skills/webspresso-services/SKILL.md +0 -134
  178. package/.cursorrules +0 -14
  179. package/AGENTS.md +0 -203
  180. package/CLAUDE.md +0 -54
  181. package/core/kernel/run-demo.js +0 -58
  182. package/plugins/admin-panel/styles.js +0 -9
  183. package/plugins/data-exchange/export-xlsx.js +0 -119
  184. package/src/client-runtime/bootstrap-alpine-swup.js +0 -34
package/CLAUDE.md DELETED
@@ -1,54 +0,0 @@
1
- # Webspresso — Claude Code Assistant Guide
2
-
3
- Webspresso is a lightweight, zero-dependency-sprawl full-stack Node.js SSR & API framework.
4
-
5
- > [!IMPORTANT]
6
- > **Authoritative Rules & Architecture**: Always follow [AGENTS.md](AGENTS.md) and the modular topic guides in [.agents/](.agents/AGENTS.md).
7
- > **API & Types Ground Truth**: Inspect [index.d.ts](index.d.ts) for exact method signatures.
8
-
9
- ---
10
-
11
- ## ⚡ Essential Commands
12
-
13
- ```bash
14
- # Run test suite (Node >= 20 required)
15
- npm test
16
- npx vitest run tests/unit/
17
- npx vitest run tests/integration/
18
- npx vitest run tests/security/
19
-
20
- # Development & diagnostics
21
- npm run dev
22
- npx webspresso doctor
23
- npx webspresso db:migrate
24
- ```
25
-
26
- ---
27
-
28
- ## 🛡️ Critical Architecture Rules
29
-
30
- 1. **100% File-Based Routing (NO `routes/` or `app.get()`)**:
31
- - All endpoints live in `pages/api/...` with HTTP method extensions:
32
- - `pages/api/notes.get.js` → `GET /api/notes`
33
- - `pages/api/notes.post.js` → `POST /api/notes`
34
- - `pages/api/notes/[id].get.js` → `GET /api/notes/:id`
35
- - `pages/api/notes/[id].delete.js` → `DELETE /api/notes/:id`
36
- - Contract: `module.exports = { schema: ({ z }) => ({ body, query, params }), middleware: ['auth'], handler: async (req, res) => ... }`
37
-
38
- 2. **Strict Repository Pattern (NO Raw `db('table')`)**:
39
- - Never run raw Knex queries (`req.db('table')`).
40
- - Always use `req.db.getRepository('ModelName')` to ensure schema validation, hooks, scopes, and query caching.
41
-
42
- 3. **Services Layer (NO `controllers/`)**:
43
- - Place business logic in `services/domain/action.js` and invoke via `ctx.service('domain.action', input)`.
44
-
45
- 4. **Zero-Dependency Native Dual Auth**:
46
- - Never install `jsonwebtoken`, `passport`, or `express-session`.
47
- - Use built-in `req.auth` and `webspresso/core/auth`.
48
-
49
- 5. **Semantic Exceptions & Page Loaders**:
50
- - Throw `NotFoundError`, `ValidationError`, `UnauthorizedError`, `ForbiddenError`.
51
- - For SSR pages (`pages/name.njk`), use companion loaders `pages/name.js` exporting `async function load({ req, res, db, ctx })`. Never call `res.render()` manually.
52
-
53
- 6. **Zero Regression Policy**:
54
- - Always run the relevant Vitest tests before declaring any task complete.
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env node
2
- /**
3
- * Demo: PostRepository + plugin + flow. Run: node core/kernel/run-demo.js
4
- */
5
-
6
- const { createApp, defineFlow, BaseRepository } = require('./app');
7
- const sampleSeo = require('./plugins/sample-seo');
8
-
9
- class PostRepository extends BaseRepository {
10
- constructor(events) {
11
- super(events, { resource: 'post', source: 'orm' });
12
- }
13
- }
14
-
15
- async function main() {
16
- const app = createApp();
17
-
18
- app.events.on('orm.post.beforeCreate', async () => {
19
- console.log('[beforeCreate]');
20
- });
21
- app.events.on('orm.post.afterCreate', async () => {
22
- console.log('[afterCreate]');
23
- });
24
-
25
- app.registerPlugin(sampleSeo);
26
-
27
- app.registerFlow(
28
- defineFlow({
29
- id: 'sitemap-on-publish',
30
- trigger: 'orm.post.afterCreate',
31
- when: (ctx) => ctx.payload.record?.status === 'published',
32
- actions: [
33
- async () => {
34
- console.log('[flow] Run sitemap update');
35
- },
36
- ],
37
- }),
38
- );
39
-
40
- const posts = new PostRepository(app.events);
41
-
42
- console.log('--- create post (published) ---');
43
- await posts.create({ title: 'Hello', status: 'published' });
44
-
45
- console.log('\n--- view render (inline plugin template) ---');
46
- const html = app.view.renderView('seo::home', { title: 'Kernel' }, {
47
- layout: 'seo::main',
48
- });
49
- console.log(html.slice(0, 120).replace(/\s+/g, ' ') + '...');
50
-
51
- console.log('\n--- partial ---');
52
- console.log(app.view.renderPartial('seo::badge', { label: 'new' }));
53
- }
54
-
55
- main().catch((err) => {
56
- console.error(err);
57
- process.exit(1);
58
- });
@@ -1,9 +0,0 @@
1
- /**
2
- * Admin Panel Styles
3
- * Additional Tailwind CSS styles for admin panel
4
- */
5
-
6
- module.exports = `
7
- /* Additional styles can be added here if needed */
8
- /* Most styling is handled by Tailwind CSS classes */
9
- `;
@@ -1,119 +0,0 @@
1
- /**
2
- * Excel (.xlsx) export using exceljs
3
- * @module plugins/data-exchange/export-xlsx
4
- */
5
-
6
- let ExcelJS = null;
7
- function getExcelJS() {
8
- if (!ExcelJS) {
9
- ExcelJS = require('exceljs');
10
- }
11
- return ExcelJS;
12
- }
13
- const { sanitizeForOutput } = require('../../core/orm/utils');
14
- const { resolveExportRecords } = require('./record-selection');
15
-
16
- /**
17
- * @param {import('../../core/orm/types').ModelDefinition} model
18
- * @param {object[]} records
19
- * @returns {Promise<Buffer>}
20
- */
21
- function getModelExportColumns(model, cleanRecords = []) {
22
- const hiddenSet = new Set(model.hidden || []);
23
- const colSet = new Set();
24
- if (model.columns && typeof model.columns.keys === 'function') {
25
- for (const c of model.columns.keys()) {
26
- if (!hiddenSet.has(c)) colSet.add(c);
27
- }
28
- }
29
- if (model.schema?.shape) {
30
- for (const c of Object.keys(model.schema.shape)) {
31
- if (!hiddenSet.has(c)) colSet.add(c);
32
- }
33
- }
34
- if (colSet.size === 0 && cleanRecords.length > 0) {
35
- for (const c of Object.keys(cleanRecords[0])) {
36
- if (!hiddenSet.has(c)) colSet.add(c);
37
- }
38
- }
39
- return Array.from(colSet);
40
- }
41
-
42
- /**
43
- * @param {import('../../core/orm/types').ModelDefinition} model
44
- * @param {object[]} records
45
- * @returns {Promise<Buffer>}
46
- */
47
- async function buildXlsxBuffer(model, records) {
48
- const clean = sanitizeForOutput(records, model);
49
- const columns = getModelExportColumns(model, clean);
50
-
51
- const ExcelLib = getExcelJS();
52
- const wb = new ExcelLib.Workbook();
53
- const ws = wb.addWorksheet('Export', {
54
- views: [{ state: 'frozen', ySplit: 1 }],
55
- });
56
-
57
- ws.addRow(columns);
58
- const headerRow = ws.getRow(1);
59
- headerRow.font = { bold: true };
60
-
61
- for (const rec of clean) {
62
- const rowValues = columns.map((c) => {
63
- let v = rec[c];
64
- if (v === null || v === undefined) return '';
65
- if (typeof v === 'bigint') return v.toString();
66
- if (v instanceof Date) return v.toISOString();
67
- if (Buffer.isBuffer(v)) return v.toString('base64');
68
- if (typeof v === 'object') v = JSON.stringify(v);
69
- if (typeof v === 'string' && /^[=+\-@]/.test(v)) return ` ${v}`;
70
- return v;
71
- });
72
- ws.addRow(rowValues);
73
- }
74
-
75
- const buf = await wb.xlsx.writeBuffer();
76
- return Buffer.isBuffer(buf) ? buf : Buffer.from(buf);
77
- }
78
-
79
- /**
80
- * @param {object} opts
81
- * @param {import('../../core/orm/database').Database} opts.db
82
- * @param {number} opts.maxRows
83
- */
84
- function createExportXlsxHandler(opts) {
85
- const { db, maxRows } = opts;
86
-
87
- return async function exportXlsxHandler(req, res) {
88
- try {
89
- const modelName = req.params.model || req.query.model;
90
- const result = await resolveExportRecords(db, modelName, req);
91
- if (result.error) {
92
- return res.status(result.error).json({ error: result.message });
93
- }
94
- const { model, records } = result;
95
- if (records.length > maxRows) {
96
- return res.status(400).json({
97
- error: `Too many rows to export (${records.length}). Limit is ${maxRows}.`,
98
- });
99
- }
100
- const buffer = await buildXlsxBuffer(model, records);
101
- const safeName = String(model.name).replace(/[^\w.-]+/g, '_');
102
- res.setHeader(
103
- 'Content-Type',
104
- 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
105
- );
106
- res.setHeader('Content-Disposition', `attachment; filename="${safeName}_export.xlsx"`);
107
- res.send(buffer);
108
- } catch (err) {
109
- console.error('[data-exchange] export xlsx:', err);
110
- res.status(500).json({ error: err.message || 'Export failed' });
111
- }
112
- };
113
- }
114
-
115
- module.exports = {
116
- buildXlsxBuffer,
117
- createExportXlsxHandler,
118
- getModelExportColumns,
119
- };
@@ -1,34 +0,0 @@
1
- /* global Swup, SwupHeadPlugin, SwupScriptsPlugin, Alpine */
2
- (function () {
3
- if (typeof Swup === 'undefined' || typeof SwupHeadPlugin === 'undefined' || typeof SwupScriptsPlugin === 'undefined' || typeof Alpine === 'undefined') {
4
- return;
5
- }
6
-
7
- function ignoreVisit(url, ctx) {
8
- var el = ctx && ctx.el;
9
- if (el && el.closest && el.closest('[data-no-swup]')) return true;
10
- try {
11
- var u = new URL(url, window.location.origin);
12
- var p = u.pathname;
13
- if (p.indexOf('/_admin') === 0 || p.indexOf('/_webspresso') === 0) return true;
14
- } catch (e) {
15
- /* ignore */
16
- }
17
- return false;
18
- }
19
-
20
- var swup = new Swup({
21
- containers: ['#swup'],
22
- plugins: [new SwupHeadPlugin(), new SwupScriptsPlugin()],
23
- ignoreVisit: ignoreVisit,
24
- });
25
-
26
- swup.hooks.on('content:replace', function () {
27
- var root = document.querySelector('#swup');
28
- if (root && typeof Alpine.initTree === 'function') {
29
- Alpine.initTree(root);
30
- }
31
- });
32
-
33
- window.__webspressoSwup = swup;
34
- })();