webspresso 0.0.94 → 0.0.96
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/.agents/ADMIN.md +225 -0
- package/.agents/AGENTS.md +72 -0
- package/.agents/ARCHITECTURE.md +119 -0
- package/.agents/AUTH.md +103 -0
- package/.agents/CLI.md +115 -0
- package/.agents/COMPRESSION.md +59 -0
- package/.agents/CONVENTIONS.md +46 -0
- package/.agents/EMAIL.md +141 -0
- package/.agents/ERRORS.md +201 -0
- package/.agents/MCP.md +103 -0
- package/.agents/ORM.md +230 -0
- package/.agents/PLUGINS.md +419 -0
- package/.agents/QUEUE.md +113 -0
- package/.agents/REALTIME.md +213 -0
- package/.agents/ROUTING.md +292 -0
- package/.agents/SERVICES.md +341 -0
- package/.agents/SHUTDOWN.md +67 -0
- package/.agents/STREAMING.md +73 -0
- package/.agents/WORKFLOW.md +27 -0
- package/.agents/internal/DOCUMENTATION_REVIEW.md +485 -0
- package/.agents/internal/TECHNICAL_REVIEW.md +428 -0
- package/.cursorrules +14 -0
- package/AGENTS.md +175 -0
- package/CLAUDE.md +54 -0
- package/README.md +18 -14
- package/bin/commands/agents-init.js +169 -0
- package/bin/commands/api.js +114 -48
- package/bin/commands/doctor.js +35 -0
- package/bin/commands/new.js +13 -2
- package/bin/commands/page.js +75 -89
- package/bin/commands/service.js +77 -0
- package/bin/webspresso.js +2 -2
- package/core/compileSchema.js +1 -1
- package/core/errors/middleware.js +22 -2
- package/core/errors/normalize.js +29 -2
- package/{utils/schemaCache.js → core/schema-cache.js} +2 -3
- package/index.d.ts +306 -0
- package/index.js +35 -1
- package/package.json +19 -6
- package/plugins/admin-panel/client/parts/05-rich-text-file-helpers.js +22 -1
- package/plugins/csrf/index.js +3 -2
- package/plugins/csv/engine.js +447 -0
- package/plugins/csv/index.js +94 -0
- package/plugins/csv/middleware.js +80 -0
- package/plugins/csv/services.js +138 -0
- package/plugins/file-manager/admin-component.js +613 -0
- package/plugins/file-manager/api-handlers.js +261 -0
- package/plugins/file-manager/core.js +601 -0
- package/plugins/file-manager/index.js +139 -0
- package/plugins/file-manager/security.js +207 -0
- package/plugins/index.js +8 -0
- package/plugins/polar/CHANGELOG.md +18 -0
- package/plugins/polar/README.md +30 -7
- package/plugins/polar/index.js +6 -1
- package/plugins/polar/src/billing-hooks.js +51 -0
- package/plugins/polar/src/config.js +2 -0
- package/plugins/polar/src/rate-limit.js +96 -28
- package/plugins/polar/src/routes.js +3 -2
- package/plugins/polar/src/urls.js +26 -2
- package/plugins/polar/src/user-resolver.js +5 -1
- package/plugins/rate-limit/index.js +5 -1
- package/plugins/xlsx/engine.js +397 -0
- package/plugins/xlsx/index.js +91 -0
- package/plugins/xlsx/middleware.js +87 -0
- package/plugins/xlsx/services.js +118 -0
- package/src/api/api-loader.js +233 -0
- package/src/api/define-api.js +35 -0
- package/src/discovery/file-route-parser.js +201 -0
- package/src/discovery/scan-routes.js +265 -0
- package/src/file-router.js +6 -0
- package/src/modules/define-module.js +99 -0
- package/src/modules/module-discovery.js +117 -0
- package/src/pages/define-page.js +36 -0
- package/src/pages/page-loader.js +214 -0
- package/src/routing/mount-discovered-routes.js +78 -0
- package/src/routing/route-table.js +191 -0
- package/src/server.js +112 -15
- package/src/services/builtins/file-manager.js +178 -0
- package/src/services/index.js +2 -0
- package/bin/commands/skill.js +0 -187
- package/templates/skills/webspresso-usage/REFERENCE-framework.md +0 -289
- package/templates/skills/webspresso-usage/REFERENCE-kernel.md +0 -93
- package/templates/skills/webspresso-usage/SKILL.md +0 -48
package/.agents/ADMIN.md
ADDED
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# Mithril.js Admin Panel Customization & Extension Guide
|
|
2
|
+
|
|
3
|
+
Webspresso includes a customizable, zero-build Mithril.js Single Page Application (SPA) Admin Panel (`plugins/admin-panel`). It provides automatic CRUD interfaces for ORM models and supports extension points for custom pages, widgets, custom field renderers, actions, and client-side component injections.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Architecture & Session Isolation
|
|
8
|
+
|
|
9
|
+
The Admin Panel operates as a self-contained Mithril.js SPA mounted at `/_admin`.
|
|
10
|
+
|
|
11
|
+
- **Isolated Auth Session**: Admin staff authentication uses a dedicated session key (`req.session.adminUser`), isolated from public site user sessions (`req.user`).
|
|
12
|
+
- **Auth Endpoints**:
|
|
13
|
+
- `POST /_admin/api/auth/setup` — Initial staff account setup (disabled once first admin exists).
|
|
14
|
+
- `POST /_admin/api/auth/login` — Staff authentication.
|
|
15
|
+
- `POST /_admin/api/auth/logout` — Terminate admin session.
|
|
16
|
+
- `GET /_admin/api/auth/me` — Current authenticated staff user details.
|
|
17
|
+
- `GET /_admin/api/auth/check` — Check if admin setup is required.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## 2. Model Admin Metadata (`defineModel`)
|
|
22
|
+
|
|
23
|
+
Configure model behavior in the Admin Panel using the `admin` property when calling `defineModel`:
|
|
24
|
+
|
|
25
|
+
```js
|
|
26
|
+
import { defineModel, zdb } from 'webspresso';
|
|
27
|
+
|
|
28
|
+
export default defineModel({
|
|
29
|
+
name: 'Product',
|
|
30
|
+
table: 'products',
|
|
31
|
+
schema: zdb.schema({
|
|
32
|
+
id: zdb.id(),
|
|
33
|
+
name: zdb.string(),
|
|
34
|
+
slug: zdb.string(),
|
|
35
|
+
price: zdb.number(),
|
|
36
|
+
status: zdb.string({ default: 'active' }),
|
|
37
|
+
}),
|
|
38
|
+
admin: {
|
|
39
|
+
enabled: true, // Expose in Admin navigation
|
|
40
|
+
label: 'Products', // Display label
|
|
41
|
+
icon: '📦', // Navigation icon
|
|
42
|
+
displayField: 'name', // Field used for title/representation
|
|
43
|
+
searchFields: ['name', 'slug'], // Fields searched by table search input
|
|
44
|
+
filterable: ['status'], // Column filters enabled in table header
|
|
45
|
+
defaultSort: { column: 'id', order: 'desc' },
|
|
46
|
+
sortableColumns: ['name', 'price'], // Optional whitelist of sortable columns
|
|
47
|
+
sortable: true, // Set false to disable table sorting completely
|
|
48
|
+
readOnly: false, // Disable create/edit/delete actions
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### 3-State Table Column Sorting
|
|
54
|
+
Table column headers support interactive 3-state cycling:
|
|
55
|
+
1. `Unsorted` (default, `↕` icon)
|
|
56
|
+
2. `ASC` (1st click, `▲` icon)
|
|
57
|
+
3. `DESC` (2nd click, `▼` icon)
|
|
58
|
+
4. `Unsorted` (3rd click, reverts to default primary key order)
|
|
59
|
+
|
|
60
|
+
Column sortability can be configured per-column:
|
|
61
|
+
- `zdb.string({ sortable: true })` / `zdb.text({ sortable: false })`
|
|
62
|
+
- `zdb.string().config({ sortable: false })`
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## 3. Admin REST API (`/_admin/api/*`)
|
|
67
|
+
|
|
68
|
+
The Admin SPA communicates with the backend via JSON REST endpoints:
|
|
69
|
+
|
|
70
|
+
- `GET /_admin/api/models` — List all models exposed to admin with schemas & metadata.
|
|
71
|
+
- `GET /_admin/api/models/:modelName/records` — List paginated records (query params: `page`, `limit`, `search`, `filter`, `sort`).
|
|
72
|
+
- `GET /_admin/api/models/:modelName/records/:id` — Retrieve single record details.
|
|
73
|
+
- `POST /_admin/api/models/:modelName/records` — Create new record.
|
|
74
|
+
- `PUT /_admin/api/models/:modelName/records/:id` — Update existing record.
|
|
75
|
+
- `DELETE /_admin/api/models/:modelName/records/:id` — Delete record (soft or hard delete).
|
|
76
|
+
- `POST /_admin/api/models/:modelName/records/:id/restore` — Restore soft-deleted record.
|
|
77
|
+
|
|
78
|
+
---
|
|
79
|
+
|
|
80
|
+
## 4. Custom Pages (`registerModule` / `registerPageDir`)
|
|
81
|
+
|
|
82
|
+
Custom Admin pages support:
|
|
83
|
+
1. **Clean Mithril.js Component Files** (`componentFile` / `component`)
|
|
84
|
+
2. **Native Custom HTML Pages** (`html` / `htmlFile`) — e.g. EUIX Engine, Vue, Alpine apps rendered directly in the DOM with full Tailwind CSS styling.
|
|
85
|
+
3. **External URL Pages** (`url` / `iframeUrl`) — Embedded in clean `<iframe>` containers.
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
const { registry } = adminPanelPlugin({ db });
|
|
89
|
+
|
|
90
|
+
// Example 1: Mithril Component
|
|
91
|
+
registry.registerModule('analytics-report', {
|
|
92
|
+
label: 'Analytics Report',
|
|
93
|
+
icon: '📊',
|
|
94
|
+
category: 'Reports',
|
|
95
|
+
componentFile: path.join(__dirname, 'admin-pages/analytics/component.js'),
|
|
96
|
+
layout: true, // Auto-wrap inside Admin layout header & sidebar (set false for full-screen view)
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
// Example 2: EUIX Engine / Native HTML Page
|
|
100
|
+
registry.registerModule('euix-module', {
|
|
101
|
+
id: 'euix-module',
|
|
102
|
+
scripts: ['https://unpkg.com/euixjs@latest/dist/EUIXEngine.umd.js'],
|
|
103
|
+
pages: [
|
|
104
|
+
{
|
|
105
|
+
id: 'euix-counter',
|
|
106
|
+
title: 'EUIX Counter',
|
|
107
|
+
path: '/euix-counter',
|
|
108
|
+
htmlFile: path.join(__dirname, 'admin-pages/euix-counter.html') // Rendered directly into DOM with Tailwind & scripts
|
|
109
|
+
}
|
|
110
|
+
],
|
|
111
|
+
menu: [
|
|
112
|
+
{ id: 'euix-counter', label: 'EUIX Counter', path: '/euix-counter', icon: 'zap' }
|
|
113
|
+
]
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### Automatic Directory Discovery (`registerPageDir`)
|
|
118
|
+
Directories containing page folders with `page.json` and `component.js` (or `index.html`) are auto-discovered:
|
|
119
|
+
|
|
120
|
+
```text
|
|
121
|
+
admin-pages/
|
|
122
|
+
├── analytics/
|
|
123
|
+
│ ├── page.json # { "id": "analytics", "label": "Analytics", "icon": "📊", "layout": true }
|
|
124
|
+
│ └── component.js # clean Mithril component (export default { view() { return m('div', 'Content'); } })
|
|
125
|
+
└── custom-tool/
|
|
126
|
+
├── page.json # { "id": "custom-tool", "label": "Custom Tool", "icon": "⚡" }
|
|
127
|
+
└── index.html # Native HTML file
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
registry.registerPageDir(path.join(__dirname, 'admin-pages'));
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## 5. Custom Field Renderers (`registerFieldRenderer`)
|
|
137
|
+
|
|
138
|
+
Register custom display and edit renderers for specific column types:
|
|
139
|
+
|
|
140
|
+
```js
|
|
141
|
+
registry.registerFieldRenderer('color-picker', {
|
|
142
|
+
// 1. Table & detail view display
|
|
143
|
+
display: (value) => m('span.color-badge', { style: { backgroundColor: value } }, value),
|
|
144
|
+
|
|
145
|
+
// 2. Form input editor
|
|
146
|
+
edit: (value, onChange, fieldConfig) => m('input[type=color]', {
|
|
147
|
+
value: value || '#000000',
|
|
148
|
+
oninput: (e) => onChange(e.target.value),
|
|
149
|
+
}),
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 6. Dashboard Widgets (`registerWidget`)
|
|
156
|
+
|
|
157
|
+
Register dashboard widgets for the Admin overview screen:
|
|
158
|
+
|
|
159
|
+
```js
|
|
160
|
+
registry.registerWidget('recent-orders', {
|
|
161
|
+
title: 'Recent Orders',
|
|
162
|
+
width: 'half', // 'full' | 'half' | 'third'
|
|
163
|
+
componentFile: path.join(__dirname, 'widgets/recent-orders.js'),
|
|
164
|
+
});
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## 7. Single Record & Bulk Table Actions
|
|
170
|
+
|
|
171
|
+
Add custom action buttons to model table views:
|
|
172
|
+
|
|
173
|
+
```js
|
|
174
|
+
// Single record button action
|
|
175
|
+
registry.registerAction('Product', {
|
|
176
|
+
id: 'duplicate',
|
|
177
|
+
label: 'Duplicate',
|
|
178
|
+
icon: '📋',
|
|
179
|
+
handler: async (record, { request, reload }) => {
|
|
180
|
+
await request.post(`/api/products/${record.id}/duplicate`);
|
|
181
|
+
reload();
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
// Bulk multi-select table action
|
|
186
|
+
registry.registerBulkAction('Product', {
|
|
187
|
+
id: 'bulk-archive',
|
|
188
|
+
label: 'Archive Selected',
|
|
189
|
+
icon: '📦',
|
|
190
|
+
handler: async (selectedIds, { request, reload }) => {
|
|
191
|
+
await request.post('/api/products/bulk-archive', { ids: selectedIds });
|
|
192
|
+
reload();
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
---
|
|
198
|
+
|
|
199
|
+
## 8. Client Components & Custom Client Script Injections
|
|
200
|
+
|
|
201
|
+
Inject custom client-side JavaScript / Mithril components into the Admin SPA runtime:
|
|
202
|
+
|
|
203
|
+
```js
|
|
204
|
+
registry.registerClientComponent('custom-banner', `
|
|
205
|
+
window.AdminRegistry.registerWidget('custom-banner', {
|
|
206
|
+
title: 'Custom Banner',
|
|
207
|
+
view: function() {
|
|
208
|
+
return m('.banner', 'Welcome to Custom Admin!');
|
|
209
|
+
}
|
|
210
|
+
});
|
|
211
|
+
`);
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
---
|
|
215
|
+
|
|
216
|
+
## 9. Offline & Zero-CDN Architecture
|
|
217
|
+
|
|
218
|
+
The Admin Panel is 100% self-contained and operates completely offline without external CDN dependencies (`unpkg.com`, `cdn.jsdelivr.net`, or `cdn.tailwindcss.com`):
|
|
219
|
+
- **Vendored Static Assets (`plugins/admin-panel/vendor/`)**:
|
|
220
|
+
- `mithril.min.js` — Client SPA runtime (~28 KB).
|
|
221
|
+
- `tailwind.min.js` — Client utility compiler & style runtime (~412 KB).
|
|
222
|
+
- `quill.min.js` & `quill.snow.min.css` — Rich-text WYSIWYG editor.
|
|
223
|
+
- **Local Asset Serving**: Served locally at `GET /_admin/vendor/:file` with proper MIME types, path traversal protections, and `Cache-Control: public, max-age=86400` caching.
|
|
224
|
+
- **Hardened CSP**: Works in air-gapped / intranet environments with strict `'self'` Content Security Policy without leaking third-party network requests.
|
|
225
|
+
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Webspresso Project Guidelines & Rules
|
|
2
|
+
|
|
3
|
+
Webspresso is a modern, lightweight, zero-dependency-sprawl full-stack Node.js SSR & API framework featuring Next.js/Nuxt-style file-based routing, an intuitive Knex-based ORM, a modular plugin ecosystem, zero-dependency Dual Authentication (Session + JWT), Graceful Shutdown & Force Close, HTTP Response Compression, Centralized Framework Exceptions, and a customizable Mithril.js SPA Admin Panel.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🎯 Agent Intent Triage Matrix (Quick Guide Selection)
|
|
8
|
+
|
|
9
|
+
When tasked with a feature or bugfix, **immediately consult the corresponding topic guide** before writing code:
|
|
10
|
+
|
|
11
|
+
| Intent / Task | Canonical Topic Guide | Primary Directory / Ground Truth |
|
|
12
|
+
| :--- | :--- | :--- |
|
|
13
|
+
| **New API Route / Endpoint** | [`.agents/ROUTING.md`](ROUTING.md) | `pages/api/...` |
|
|
14
|
+
| **SSR HTML Page / Layout / Loader** | [`.agents/ROUTING.md`](ROUTING.md) & [`.agents/STREAMING.md`](STREAMING.md) | `pages/*.njk`, `pages/*.js`, `views/` |
|
|
15
|
+
| **Database Model / Migration / Query** | [`.agents/ORM.md`](ORM.md) | `models/*.js`, `core/orm`, `migrations/` |
|
|
16
|
+
| **Business Logic / Transaction / Service** | [`.agents/SERVICES.md`](SERVICES.md) | `services/` |
|
|
17
|
+
| **Admin Panel (Page, Widget, Action, UI)** | [`.agents/ADMIN.md`](ADMIN.md) | `plugins/admin-panel/` |
|
|
18
|
+
| **Authentication (Session / JWT / Guard)** | [`.agents/AUTH.md`](AUTH.md) | `core/auth/` |
|
|
19
|
+
| **Background Jobs & Worker Queue** | [`.agents/QUEUE.md`](QUEUE.md) | `jobs/` |
|
|
20
|
+
| **API Signatures & Types Verification** | [`index.d.ts`](../index.d.ts) | **Canonical Ground Truth** |
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## 🛡️ 4-Step Mandatory Agent Workflow Protocol
|
|
25
|
+
|
|
26
|
+
Every coding agent working on Webspresso **MUST** follow this 4-step execution discipline:
|
|
27
|
+
|
|
28
|
+
1. **Discover & Triage**: Identify the relevant topic guide above and inspect existing similar files in the workspace (e.g. `pages/api/`, `models/`, `services/`).
|
|
29
|
+
2. **Contract Adherence**: Follow the exact module contract exported by the framework (`{ schema, middleware, handler }` for routes, `defineModel` for ORM, `defineService` for services).
|
|
30
|
+
3. **Zero External Dependencies**: Use native Node.js standard modules (`crypto`, `path`, `fs`, `zlib`, `events`) and built-in framework utilities. NEVER install ad-hoc npm packages for auth, jwt, routing, or templating.
|
|
31
|
+
4. **Targeted Verification**: Run the specific Vitest test file (`npx vitest run tests/...`) to confirm zero regressions before marking the task complete.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Agent Guidebook Index
|
|
36
|
+
|
|
37
|
+
This `.agents/` customization root is organized into modular topic guides:
|
|
38
|
+
|
|
39
|
+
1. **[File-Based Routing & API Routes](.agents/ROUTING.md)** — File-based page routes (`pages/`), method-suffixed API routes (`pages/api/*.get.js`, `*.post.js`), parameter brackets (`[id]`), Zod request schemas, and the strict prohibition of manual `routes/` directories or `app.get()`.
|
|
40
|
+
2. **[Architecture & Structure](.agents/ARCHITECTURE.md)** — File-based routing (`pages/`), Asset Management & Versioning (`AssetManager`, `fsy.asset`), ORM models & `zdb` schemas (`core/orm`), Mithril.js Admin Panel SPA (`plugins/admin-panel`), and Plugin Ecosystem.
|
|
41
|
+
3. **[Services Layer](.agents/SERVICES.md)** — File-based auto-discovery (`services/`), Zod validation, declarative `auth` & RBAC guards, automatic ACID transaction propagation (`transaction: true`), timeouts, and memoization.
|
|
42
|
+
4. **[Exceptions & Error Handling](.agents/ERRORS.md)** — Django-inspired framework exception hierarchy (`WebspressoError`, `HttpError`, `ValidationError`, `SecurityError`, `RequestAbortedError`), central error boundary, `app.setErrorHandler()`, and production error masking.
|
|
43
|
+
5. **[Graceful Shutdown & Lifecycle](.agents/SHUTDOWN.md)** — `ShutdownManager`, `NodeHttpAdapter`, connection draining, force close mode, and reverse-order plugin disposer cleanup.
|
|
44
|
+
6. **[HTTP Response Compression](.agents/COMPRESSION.md)** — Native streaming zlib compression (`server.compression`), Brotli/Gzip/Deflate negotiation, threshold handling, and `res.compress(false)` route opt-out.
|
|
45
|
+
7. **[Dual Authentication System](.agents/AUTH.md)** — Stateful Session + Cookie & Stateless HS256 JWT + Refresh Token Rotation, `req.auth` helpers, and `middleware: ['jwt']` guard integrations.
|
|
46
|
+
8. **[ORM & Database Layer](.agents/ORM.md)** — Model definitions with `defineModel`, `zdb` schemas, Repositories API, Query Caching, Relations, Soft Delete, Scopes & Migrations.
|
|
47
|
+
9. **[Plugin Ecosystem Guide](.agents/PLUGINS.md)** — Lifecycle hooks (`register`, `onRoutesReady`), CSP headers, and detailed reference for all 18 built-in official plugins (including `xlsxPlugin`, `csvPlugin`, `fileManagerPlugin`, `realtimePlugin`, and `basicAuthPlugin`).
|
|
48
|
+
10. **[Realtime Layer & Adapters](.agents/REALTIME.md)** — Framework-agnostic realtime layer (`core/realtime`), generic WebSocket, SSE, and Socket.IO adapters, subscription identity, backoff reconnect, and auth lifecycle.
|
|
49
|
+
11. **[Email Plugin Guide](.agents/EMAIL.md)** — MJML template compilation, Nodemailer transport, DB delivery logs, Auth Email bridge, and Admin UI.
|
|
50
|
+
12. **[Admin Panel Customization](.agents/ADMIN.md)** — Extending Mithril.js Admin Panel SPA (Custom pages `component.js`, custom field renderers, widgets, single & bulk actions).
|
|
51
|
+
13. **[CLI Tooling & Commands](.agents/CLI.md)** — `webspresso dev`, `build`, `doctor`, `db:migrate`, `db:seed`, `polar:migrate`, `favicon:generate`, `add:tailwind`, `agents:init`.
|
|
52
|
+
14. **[Development & Testing Workflow](.agents/WORKFLOW.md)** — CLI commands, Vitest unit/integration testing, Playwright E2E tests, TypeScript type checking, and zero regression policy.
|
|
53
|
+
15. **[Coding Standards & Conventions](.agents/CONVENTIONS.md)** — Zero external dependencies policy, strict function signature & schema verification, clean component separation, and log traceback inspection rules.
|
|
54
|
+
16. **[Background Job Queue](.agents/QUEUE.md)** — In-Memory, Knex Database, and Distributed Redis queue adapters, job auto-discovery (`jobs/`), retries, and graceful draining.
|
|
55
|
+
17. **[SSR Streaming & Chunked Transfer](.agents/STREAMING.md)** — Native HTTP chunked streaming (`res.renderStream()`), deferred data loader slots (`defer: { key: promise }`), and TTFB optimization.
|
|
56
|
+
18. **Polar billing production checklist** — [docs/guides/polar-production-checklist.md](../docs/guides/polar-production-checklist.md) (env, webhooks, rate limits, external tier hooks, CSP). Plugin reference: [PLUGINS.md § polarPlugin](PLUGINS.md).
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Essential Rules Summary
|
|
61
|
+
|
|
62
|
+
- **Strict File-Based Routing (NO `routes/` or `app.get()`)**: NEVER create a `routes/` or `src/routes/` directory. NEVER call `app.get()`, `app.post()`, or `express.Router()`. ALL application endpoints MUST be defined inside `pages/` and `pages/api/...` with HTTP method extensions (`.get.js`, `.post.js`, `.delete.js`, `.patch.js`, `.put.js`).
|
|
63
|
+
- **Strict Repository Pattern (NO Raw `db('table')`)**: NEVER write raw Knex table queries in application code. ALWAYS access database models through repositories via `db.getRepository('ModelName')` or `req.db.getRepository('ModelName')` to ensure schema validation, hooks, scopes, and query caching are applied.
|
|
64
|
+
- **Strict Services Layer (NO `controllers/`)**: NEVER create a `controllers/` folder or controller classes. Encapsulate multi-step business logic in `services/domain/action.js` and invoke via `ctx.service('domain.action', input)` to leverage automatic transaction propagation (`transaction: true`) and Zod validation.
|
|
65
|
+
- **Native Dual Auth (NO External JWT/Passport Packages)**: NEVER install `jsonwebtoken`, `passport`, or `express-session`. ALWAYS use native `req.auth` and `webspresso/core/auth` (`middleware: ['jwt']` / `middleware: ['auth']`).
|
|
66
|
+
- **Page Data Loaders (NO Manual `res.render()`)**: NEVER call `res.render()` inside custom handlers for SSR pages. Use companion loaders `pages/*.js` exporting `async function load({ req, res, db, ctx })`.
|
|
67
|
+
- **Semantic Exceptions (NO Generic Errors / Manual Responses)**: NEVER return manual `res.status(404).json(...)` inside services or loaders. ALWAYS throw semantic errors: `NotFoundError`, `ValidationError`, `UnauthorizedError`, `ForbiddenError`.
|
|
68
|
+
- **Background Jobs (NO BullMQ / `setTimeout`)**: NEVER use unmanaged `setTimeout` or external queues. Place job workers in `jobs/` and dispatch via `req.queue.dispatch()`.
|
|
69
|
+
- **Zero External Dependencies**: Core framework functions (Auth, JWT, CORS, Routing, Errors, Compression, Shutdown, Nunjucks helpers) must rely strictly on native Node.js modules (`crypto`, `path`, `fs`, `events`, `zlib`, `async_hooks`).
|
|
70
|
+
- **Zero Regression Policy**: Always run Vitest tests (`npm test` or `npx vitest run`) before declaring any task complete.
|
|
71
|
+
- **Strict Verification**: Inspect authoritative source files for function signatures and schema definitions before writing consuming code.
|
|
72
|
+
- **Log & Traceback Inspection**: Base all bug fixes strictly on exact runtime error log tracebacks and empirical test output.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
# Webspresso Codebase Architecture & Structure
|
|
2
|
+
|
|
3
|
+
[← Back to AGENTS.md](.agents/AGENTS.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Core SSR & Routing (`pages/`, `views/`, `src/`)
|
|
8
|
+
|
|
9
|
+
- **File-based Routing**: Pages located in `pages/` automatically map to URL routes:
|
|
10
|
+
- `pages/index.njk` → `/`
|
|
11
|
+
- `pages/products/[id].njk` → `/products/:id`
|
|
12
|
+
- `pages/api/posts.post.js` → `POST /api/posts`
|
|
13
|
+
- ⚠️ **CRITICAL ANTI-PATTERN: NEVER create a `routes/` or `src/routes/` directory. NEVER use `express.Router()`, `app.get()`, or `app.post()`. All application endpoints must live under `pages/` and `pages/api/`. See [ROUTING.md](ROUTING.md).**
|
|
14
|
+
- **Data Loaders (`load()`)**: Page routes export `async function load({ req, res, db, ctx })` to fetch data server-side before Nunjucks template rendering.
|
|
15
|
+
- **API Endpoints**: Defined as file route modules in `pages/api/...` exporting `{ schema, middleware, handler }`. Input validation via Zod (`schema: ({ z }) => ({ body, query, params })`) assigns validated data to `req.input.body` / `req.input.query`.
|
|
16
|
+
- **Modern Page & API Helpers (`definePage`, `defineApi`)**:
|
|
17
|
+
- `definePage({ middleware, load, head, render, layout })`: Pure JS or Nunjucks-backed page routes with unified execution context (`ctx: { req, res, params, query, service, db, redirect, error, fsy, locale, t }`).
|
|
18
|
+
- `defineApi({ description, tags, schema, middleware, handler })`: REST API endpoints with declarative Zod validation (`req.input`), middleware chain, and automatic JSON response formatting.
|
|
19
|
+
- **Feature Modules (`src/modules/` or `modules/`, `defineModule`)**:
|
|
20
|
+
- Domain-oriented modular architecture bundling pages, APIs, services, and scoped middlewares into standalone units (`defineModule({ name, pages, api, services, middlewares, onInit, onDestroy })`).
|
|
21
|
+
- Automatic service prefixing (`'auth.login'`) and scoped route prefixing (`/auth/*`, `/api/auth/*`).
|
|
22
|
+
- **Deterministic Route Compilation & Introspection (`RouteTable`, `app.routes.list()`)**:
|
|
23
|
+
- Discovered routes are compiled and sorted in deterministic priority order: Static $\to$ Deep Dynamic $\to$ Shallow Dynamic $\to$ Catch-All (`*`).
|
|
24
|
+
- Detects `METHOD + PATH` collision conflicts at startup and throws descriptive errors.
|
|
25
|
+
- Inspectable via `app.routes.list()` for CLI tools, documentation generation, and debugging.
|
|
26
|
+
- **Templating & Helpers**: Nunjucks (`.njk`) templates rendered with layouts (e.g. `views/layout.njk`). Access helpers via `fsy` object in templates.
|
|
27
|
+
- **Asset Management & Cache-Busting (`assets`, `AssetManager`, `fsy`)**:
|
|
28
|
+
- Configured via `createApp({ assets: { version, manifestPath, prefix, publicDir } })` or `configureAssets()`.
|
|
29
|
+
- **Static Query Versioning (`version`)**: Appends `?v=<version>` (or `&v=...`) to asset URLs (e.g. `version: '1.2.3'` or `process.env.APP_VERSION`) for cache busting.
|
|
30
|
+
- **Build Manifests (`manifestPath`)**: Automatically resolves hashed output files from Vite (`.vite/manifest.json` mapping `{ "css/style.css": { "file": "assets/style-abc.css" } }`) or Webpack manifests (`{ "/css/style.css": "/dist/style.abc.css" }`). Falls back gracefully if an asset is not in the manifest.
|
|
31
|
+
- **URL Prefix (`prefix`)**: Prepends CDN or mount path prefixes (e.g. `prefix: 'https://cdn.example.com'` or `'/static'`).
|
|
32
|
+
- **Template Helpers**:
|
|
33
|
+
- `{{ fsy.asset('/css/style.css') }}` → Resolves URL with manifest/versioning.
|
|
34
|
+
- `{{ fsy.css('/css/style.css', { media: 'print' }) | safe }}` → Generates `<link rel="stylesheet" ...>`.
|
|
35
|
+
- `{{ fsy.js('/js/app.js', { defer: true, type: 'module' }) | safe }}` → Generates `<script ...></script>`.
|
|
36
|
+
- `{{ fsy.img('/images/logo.png', 'Logo', { loading: 'lazy' }) | safe }}` → Generates `<img ...>` with escaped attributes.
|
|
37
|
+
- **Page-Level Assets (`pageAssets`)**: Route `load()` can return `stylesheets` and `scripts` arrays, which are promoted to `pageHead` for per-route asset loading.
|
|
38
|
+
- **Framework Exceptions & Central Error Boundary (`core/errors`, `app.setErrorHandler`)**:
|
|
39
|
+
- Django-inspired hierarchy: `WebspressoError`, `HttpError` (400-429), `ValidationError` (422), `SecurityError`, `RequestAbortedError`, `ConfigurationError`, `PluginError`, `RouteNotFoundError`.
|
|
40
|
+
- Automatic async error wrapping: all rejected promises in route handlers pass automatically to `next(err)`.
|
|
41
|
+
- Safe production masking: 500 errors stripped of stack traces and internal messages; exposed strictly in development.
|
|
42
|
+
- **Graceful Shutdown & Lifecycle Management (`core/shutdown`, `ShutdownManager`)**:
|
|
43
|
+
- Configured via `createApp({ server: { shutdown: { enabled: true, mode: 'graceful'|'force', timeout: 10000 } } })`.
|
|
44
|
+
- `NodeHttpAdapter` single-listener socket tracking, request draining with `Connection: close`, and reverse-order plugin disposer cleanup.
|
|
45
|
+
- **HTTP Response Compression (`core/compression`)**:
|
|
46
|
+
- Zero-dependency streaming zlib compression configured via `createApp({ server: { compression: true } })`.
|
|
47
|
+
- Content negotiation for Brotli (`br`), Gzip (`gzip`), Deflate (`deflate`), threshold filtering (1 KB), and `res.compress(false)` route opt-out.
|
|
48
|
+
- **Custom Error & 404 Pages (`errorPages`)**:
|
|
49
|
+
- Configured via `createApp({ errorPages: { notFound, serverError, timeout } })`.
|
|
50
|
+
- **404 Not Found (`notFound`)**: Template path (`'404.njk'`) or handler `(req, res, ctx) => ...`.
|
|
51
|
+
- **500 Server Error (`serverError`)**: Template path (`'errors/500.njk'`) or handler `(err, req, res, ctx) => ...`. Context: `{ fsy, locale, isDev, url, method, error, status }`.
|
|
52
|
+
- **503 Timeout (`timeout`)**: Template path (`'errors/503.njk'`) or handler `(req, res, ctx) => ...` when `timeout` (e.g. `'30s'`) is configured.
|
|
53
|
+
- **i18n & Localization Engine (`loadI18n`, `createTranslator`, `detectLocale`)**:
|
|
54
|
+
- Zero-dependency internationalization built on native Node.js `Intl` APIs (`Intl.PluralRules`, `Intl.NumberFormat`, `Intl.DateTimeFormat`, `Intl.RelativeTimeFormat`).
|
|
55
|
+
- **Hierarchical Dictionaries**: Global `pages/locales/[locale].json` merged with route-specific overrides `pages/[route]/locales/[locale].json` using `mtime` cache.
|
|
56
|
+
- **Pluralization**: Automatic CLDR plural selection (`zero`, `one`, `two`, `few`, `many`, `other`) or exact number mapping (`0`, `1`) via `t('key', { count })` or `t.plural(count, forms)`.
|
|
57
|
+
- **Fallback Chain**: Missing keys fall back to `DEFAULT_LOCALE` (`en`) automatically. Key check via `t.has('key')` or `t.exists('key')`.
|
|
58
|
+
- **Native Formatters on `t`**: `t.number(1234.5)`, `t.currency(199.99, 'TRY')`, `t.date(d)`, `t.relativeTime(-2, 'day')`.
|
|
59
|
+
- **Template Helpers & Filter**: `{{ fsy.localeUrl('tr') }}`, `{{ 'nav.home' | t }}`, `{{ t('key') }}`.
|
|
60
|
+
- **Services Layer (`services/`, `ServiceRegistry`, `defineService`, `ctx.service`, `req.service`)**:
|
|
61
|
+
- Auto-discovered file-based service modules: `services/user/get.js` → `user.get`, `services/post/publish.js` → `post.publish`.
|
|
62
|
+
- **Shared Request Context**: Service-to-service composition (`ctx.service()`) shares the exact same `ctx` (`ctx.db`, `ctx.auth`, `ctx.session`, `ctx.user`).
|
|
63
|
+
- **Circular Call Protection**: Automatically tracks service call stack per request and aborts cycles (`user.get -> profile.get -> user.get`).
|
|
64
|
+
- **Optional Schema Validation**: Validates inputs with simple descriptors (`'number'`, `'string'`, `'email'`, etc.), custom functions, or Zod schemas before handler execution.
|
|
65
|
+
- **HTTP Independence**: Services can be executed without starting an HTTP server via `createServiceRegistry().call(name, input, mockCtx)`.
|
|
66
|
+
- **Middleware & Hooks**: Route lifecycle hooks can be declared per-page (`module.exports = { middleware: ['auth', 'jwt'] }`) or globally via `pages/_hooks.js`.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 2. ORM & Database Layer (`core/orm`, `models/`)
|
|
71
|
+
|
|
72
|
+
- **Model Definition**: Defined in `models/*.js` using `defineModel({ name, table, schema, relations, scopes, hidden, admin, cache })`.
|
|
73
|
+
- **Schema & Types**: Built with `zdb` schema builder:
|
|
74
|
+
- `zdb.id()`, `zdb.uuid()`, `zdb.nanoid()`
|
|
75
|
+
- `zdb.string()`, `zdb.integer()`, `zdb.boolean()`
|
|
76
|
+
- `zdb.file({ maxLength, nullable })` (URL/path string for uploaded assets)
|
|
77
|
+
- `zdb.json()`, `zdb.timestamp()`
|
|
78
|
+
- **Repositories**: Accessed via `db.getRepository(modelName)` or `ctx.db`. Supports `find`, `findById`, `findOne`, `create`, `update`, `delete`, and `query()`.
|
|
79
|
+
- **Query Caching**: Memory/provider query cache configured per database instance or model (`cache: 'auto'|'smart'|true`).
|
|
80
|
+
- **Migrations**: Database schema changes managed via Knex migrations in `migrations/` (`webspresso db:migrate`).
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3. Admin Panel Architecture (`plugins/admin-panel`)
|
|
85
|
+
|
|
86
|
+
- **SPA CRUD Engine**: Modular Mithril.js SPA mounted at `/_admin` powered by `adminPanelPlugin({ db })`.
|
|
87
|
+
- **Admin Module Registration**: Registered using `adminApi.registerModule` or `adminApi.registerPageDir`.
|
|
88
|
+
- **Custom Admin Pages**:
|
|
89
|
+
- Supports clean Mithril component `.js` files (`componentFile`), external URLs (`url` / `iframeUrl`), or custom HTML documents (`html` / `htmlFile`).
|
|
90
|
+
- **Auto Layout Wrapping**: Custom page views are automatically wrapped inside Admin `Layout` and `Breadcrumb` containers unless `layout: false` is configured for full-screen pages.
|
|
91
|
+
- **SSR Scripts & Styles**: `registerScript(url)` and `registerStyle(url)` inject external CSS/JS dependencies into Admin SPA markup.
|
|
92
|
+
- **Session Isolation**: Admin staff authentication uses a separate session (`req.session.adminUser` / `/_admin/api/auth/*`), isolated from public site auth (`req.user`).
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 4. Plugin Ecosystem (`plugins/`)
|
|
97
|
+
|
|
98
|
+
Plugins expose `name`, `version`, `dependencies`, and lifecycle hooks (`register(ctx)`, `onRoutesReady(ctx)`):
|
|
99
|
+
|
|
100
|
+
| Plugin | Feature set | One-line purpose |
|
|
101
|
+
|--------|-------------|------------------|
|
|
102
|
+
| `basicAuthPlugin` | Security / HTTP | Zero-dependency RFC 7617 HTTP Basic Authentication with timing-safe comparison |
|
|
103
|
+
| `realtimePlugin` | Realtime | Framework-agnostic realtime layer (`core/realtime`) with WebSocket, SSE, Socket.IO, and Redis adapters |
|
|
104
|
+
| `adminPanelPlugin` | Admin / SPA | ORM-backed CRUD SPA with user management & custom pages |
|
|
105
|
+
| `fileManagerPlugin` | Admin / Media | Media library, directory tree, file preview, and drag-and-drop uploads |
|
|
106
|
+
| `contentPlugin` | Admin / CMS | Schema-driven CMS with inline editing and public REST API |
|
|
107
|
+
| `uploadPlugin` | HTTP / Admin | Multipart upload endpoint + pluggable storage providers |
|
|
108
|
+
| `redirectPlugin` | HTTP | Configurable HTTP 301–308 redirects before file routes |
|
|
109
|
+
| `rateLimitPlugin` | HTTP | Named rate-limit middleware + optional global limiter |
|
|
110
|
+
| `siteAnalyticsPlugin` | Analytics | Self-hosted page view analytics and client JS error tracking |
|
|
111
|
+
| `emailPlugin` | Email | MJML template compilation & Nodemailer integration |
|
|
112
|
+
| `csrfPlugin` | Security | Session & cookie double-submit CSRF protection + helpers |
|
|
113
|
+
| `auditLogPlugin` | Security | Admin mutation audit logging |
|
|
114
|
+
| `ormCacheAdminPlugin` | Admin / ORM | Cache inspection and invalidation dashboard |
|
|
115
|
+
| `restResourcePlugin` | ORM / REST API | Auto RESTful CRUD endpoints from models with eager loading & sanitization |
|
|
116
|
+
| `xlsxPlugin` | Excel / Export | Excel spreadsheet generation, parsing, ORM streaming export (`res.xlsx`), and services |
|
|
117
|
+
| `csvPlugin` | CSV / Export | RFC 4180 CSV generator, parser, Excel UTF-8 BOM, streaming writer (`res.csv`), and services |
|
|
118
|
+
|
|
119
|
+
|
package/.agents/AUTH.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# Webspresso Dual Authentication Architecture
|
|
2
|
+
|
|
3
|
+
[← Back to AGENTS.md](.agents/AGENTS.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Overview
|
|
8
|
+
|
|
9
|
+
Webspresso provides a zero-dependency **Dual Authentication** system (`webspresso/core/auth` — resolved via package exports, no `/index.js` suffix required):
|
|
10
|
+
- **Stateful Session + Cookie**: Used for browser SSR routes and Admin Panel (`/`, `/_admin`).
|
|
11
|
+
- **Stateless HS256 JWT + Refresh Tokens**: Used for REST APIs, Mobile Apps, and SPAs (`/api/*`).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## ⚠️ STRICT RULE: Use Native Dual Auth (NO External JWT/Passport Packages)
|
|
16
|
+
|
|
17
|
+
- **NEVER** install `jsonwebtoken`, `bcryptjs`, `passport`, or `express-session`.
|
|
18
|
+
- **ALWAYS** use Webspresso's native `req.auth` and `webspresso/core/auth`:
|
|
19
|
+
- Session login: `await req.auth.attempt(email, password, { remember: true })`
|
|
20
|
+
- Stateless JWT generation: `req.auth.generateUserToken(user)`
|
|
21
|
+
- Refresh Tokens: `req.auth.generateRefreshToken(user)` / `req.auth.refreshAccessToken(token)`
|
|
22
|
+
- Route Guards: `middleware: ['auth']` (web session) or `middleware: ['jwt']` (API Bearer token)
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
## 2. Token Generation & Rotation
|
|
27
|
+
|
|
28
|
+
- **Access Token**: Short-lived HS256 JWT token generated via `req.auth.generateUserToken(user, options)`. Default duration is `15m` (configurable).
|
|
29
|
+
- **Refresh Token**: Long-lived HS256 JWT token generated via `req.auth.generateRefreshToken(user, options)` with cryptographically unique `jti` nonces. Default duration is `30d` (configurable).
|
|
30
|
+
- **Token Rotation**: `req.auth.refreshAccessToken(refreshToken, { rotate: true })` verifies the refresh token and generates a new Access Token alongside a rotated Refresh Token pair.
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 3. Request-Bound Auth Helper (`req.auth`)
|
|
35
|
+
|
|
36
|
+
Attached to Express request during auth middleware execution:
|
|
37
|
+
|
|
38
|
+
| Method | Description |
|
|
39
|
+
|--------|-------------|
|
|
40
|
+
| `req.auth.attempt(identifier, password, { remember })` | Authenticate user with credentials and login |
|
|
41
|
+
| `req.auth.login(user, { remember })` | Log in user and establish session |
|
|
42
|
+
| `req.auth.logout({ everywhere })` | Log out user and destroy session |
|
|
43
|
+
| `req.auth.generateUserToken(user, options)` | Generate short-lived JWT Access Token |
|
|
44
|
+
| `req.auth.generateRefreshToken(user, options)` | Generate long-lived JWT Refresh Token |
|
|
45
|
+
| `req.auth.refreshAccessToken(refreshToken, options)` | Refresh access token & rotate refresh token |
|
|
46
|
+
| `req.auth.check()` / `req.auth.guest()` | Check if user is authenticated or guest |
|
|
47
|
+
| `req.auth.user()` / `req.auth.id()` | Get current user object or ID |
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## 4. File-Based API Route Examples (`pages/api/*`)
|
|
52
|
+
|
|
53
|
+
### 4.1 Login & Token Generation (`pages/api/auth/login.post.js`)
|
|
54
|
+
```javascript
|
|
55
|
+
module.exports = {
|
|
56
|
+
schema: ({ z }) => ({
|
|
57
|
+
body: z.object({
|
|
58
|
+
email: z.string().email(),
|
|
59
|
+
password: z.string().min(1),
|
|
60
|
+
}),
|
|
61
|
+
}),
|
|
62
|
+
async handler(req, res) {
|
|
63
|
+
const { email, password } = req.input.body;
|
|
64
|
+
const user = await req.auth.attempt(email, password);
|
|
65
|
+
if (!user) return res.status(401).json({ error: 'Invalid credentials' });
|
|
66
|
+
|
|
67
|
+
const accessToken = req.auth.generateUserToken(user);
|
|
68
|
+
const refreshToken = req.auth.generateRefreshToken(user);
|
|
69
|
+
|
|
70
|
+
return res.json({ accessToken, refreshToken, user: { id: user.id, email: user.email } });
|
|
71
|
+
},
|
|
72
|
+
};
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 4.2 Token Refresh Endpoint (`pages/api/auth/refresh.post.js`)
|
|
76
|
+
```javascript
|
|
77
|
+
module.exports = {
|
|
78
|
+
schema: ({ z }) => ({
|
|
79
|
+
body: z.object({
|
|
80
|
+
refreshToken: z.string(),
|
|
81
|
+
}),
|
|
82
|
+
}),
|
|
83
|
+
async handler(req, res) {
|
|
84
|
+
const { refreshToken } = req.input.body;
|
|
85
|
+
try {
|
|
86
|
+
const result = await req.auth.refreshAccessToken(refreshToken, { rotate: true });
|
|
87
|
+
return res.json({ accessToken: result.accessToken, refreshToken: result.refreshToken });
|
|
88
|
+
} catch (err) {
|
|
89
|
+
return res.status(401).json({ error: err.message });
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 4.3 Protected API Route (`pages/api/profile.get.js`)
|
|
96
|
+
```javascript
|
|
97
|
+
module.exports = {
|
|
98
|
+
middleware: ['jwt'],
|
|
99
|
+
async handler(req, res) {
|
|
100
|
+
return res.json({ user: req.user, token: req.token });
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
```
|
package/.agents/CLI.md
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
# Webspresso CLI Tooling & Commands Reference
|
|
2
|
+
|
|
3
|
+
The `webspresso` CLI utility (`bin/cli.js`) provides development commands for running local SSR servers, executing database migrations, analyzing project health, and generating favicons.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Development & Build Commands
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
# Start local development server with hot reloading
|
|
11
|
+
npx webspresso dev
|
|
12
|
+
# Flags:
|
|
13
|
+
# --port, -p <number> (default: 3001)
|
|
14
|
+
# --host <string> (default: localhost)
|
|
15
|
+
|
|
16
|
+
# Build production bundle / verify assets
|
|
17
|
+
npx webspresso build
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## 2. Project Health & Sanity Check (`doctor`)
|
|
23
|
+
|
|
24
|
+
Scans routing structure, model definitions, and dynamic sibling collisions:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx webspresso doctor
|
|
28
|
+
|
|
29
|
+
# Strict mode: exits with status 1 if warnings are found
|
|
30
|
+
npx webspresso doctor --strict
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Checks performed:
|
|
34
|
+
- Dynamic sibling collisions (e.g. `pages/[id].njk` vs `pages/[slug].njk`).
|
|
35
|
+
- Naming conventions and lowercase file-based route paths.
|
|
36
|
+
- Missing model schemas or invalid `zdb` column definitions.
|
|
37
|
+
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
## 3. Database Commands (`db:migrate`, `db:seed`)
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Run pending Knex database migrations
|
|
44
|
+
npx webspresso db:migrate
|
|
45
|
+
|
|
46
|
+
# Seed database records
|
|
47
|
+
npx webspresso db:seed
|
|
48
|
+
|
|
49
|
+
# Scaffold initial seed files
|
|
50
|
+
npx webspresso db:seed --setup
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
## 4. Favicon Generator (`favicon:generate`)
|
|
56
|
+
|
|
57
|
+
Generates multi-resolution browser favicons, `manifest.json`, and `favicons.njk` partial from a PNG logo:
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
npx webspresso favicon:generate logo.png
|
|
61
|
+
|
|
62
|
+
# Flags:
|
|
63
|
+
# --theme-color <hex> (default: #ffffff)
|
|
64
|
+
# --output-dir <path> (default: public)
|
|
65
|
+
# --no-layout (do not modify layout.njk auto-include)
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 5. Polar Billing Migration (`polar:migrate`)
|
|
71
|
+
|
|
72
|
+
Generates an idempotent Knex migration adding Polar billing columns to the user table:
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
npx webspresso polar:migrate
|
|
76
|
+
|
|
77
|
+
# Flags:
|
|
78
|
+
# -c, --config <path> Database config file
|
|
79
|
+
# -t, --table <name> User table (default: users)
|
|
80
|
+
# -o, --output <path> Custom migration output path
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Then run `npx webspresso db:migrate`. See [docs/guides/polar-production-checklist.md](../docs/guides/polar-production-checklist.md).
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 6. Interactive Service Runner (`service`, `service:run`)
|
|
88
|
+
|
|
89
|
+
Test and run services interactively without starting the HTTP server:
|
|
90
|
+
|
|
91
|
+
```bash
|
|
92
|
+
# Interactive selection & prompt mode
|
|
93
|
+
npx webspresso service
|
|
94
|
+
|
|
95
|
+
# Run specific service with JSON payload
|
|
96
|
+
npx webspresso service user.get -i '{"id": 42}'
|
|
97
|
+
|
|
98
|
+
# Run with key=value query string
|
|
99
|
+
npx webspresso service payment.refund -i 'transactionId=tx_123 amount=49.99'
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## 7. AI Agent Guidelines Scaffolder (`agents:init`)
|
|
105
|
+
|
|
106
|
+
Scaffolds and synchronizes AI coding agent rules into any Webspresso project:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
# Scaffold full guidelines bundle (.agents/, AGENTS.md, CLAUDE.md, .cursorrules)
|
|
110
|
+
npx webspresso agents:init
|
|
111
|
+
|
|
112
|
+
# Overwrite existing guidelines
|
|
113
|
+
npx webspresso agents:init --force
|
|
114
|
+
```
|
|
115
|
+
|