webspresso 0.0.99 → 0.0.100
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/AGENTS.md +2 -2
- package/.agents/AUTH.md +246 -0
- package/.agents/CLI.md +47 -0
- package/.agents/ERRORS.md +59 -0
- package/.agents/ORM.md +90 -0
- package/.agents/PLUGINS.md +44 -7
- package/.agents/QUEUE.md +18 -10
- package/.agents/ROUTING.md +33 -0
- package/.agents/STREAMING.md +35 -0
- package/AGENTS.md +1 -0
- package/README.md +145 -93
- package/bin/commands/add-docker.js +467 -0
- package/bin/commands/deploy-check.js +339 -0
- package/bin/webspresso.js +4 -0
- package/core/auth/index.js +63 -1
- package/core/auth/magic-link.js +170 -0
- package/core/auth/manager.js +343 -3
- package/core/auth/middleware.js +30 -5
- package/core/auth/session-manager.js +255 -0
- package/core/auth/sessions.js +351 -0
- package/core/auth/tokens.js +1 -0
- package/core/auth/totp.js +4 -1
- package/core/auth/user-agent.js +161 -0
- package/core/orm/index.js +2 -1
- package/core/orm/model.js +51 -1
- package/core/orm/repository.js +283 -13
- package/core/orm/scopes.js +3 -2
- package/core/orm/types.js +6 -1
- package/core/queue/cron.js +252 -39
- package/core/queue/manager.js +20 -2
- package/core/queue/scheduler.js +115 -59
- package/core/ssr/stream.js +62 -2
- package/index.d.ts +274 -14
- package/index.js +4 -0
- package/package.json +7 -5
- package/plugins/admin-panel/modules/admin-users.js +1 -1
- package/plugins/audit-log/admin-component.js +54 -54
- package/plugins/audit-log/index.js +2 -2
- package/plugins/content/client/inline-edit.js +2 -46
- package/plugins/cors.js +13 -2
- package/plugins/email/auth-bridge.js +66 -0
- package/plugins/email/bundled-templates.js +15 -0
- package/plugins/email/templates/auth-magic-link.mjml +13 -0
- package/plugins/file-manager/admin-component.js +49 -49
- package/plugins/file-manager/index.js +4 -4
- package/plugins/index.js +2 -0
- package/plugins/webhooks/admin-component.js +608 -0
- package/plugins/webhooks/api-handlers.js +237 -0
- package/plugins/webhooks/crypto.js +144 -0
- package/plugins/webhooks/dispatcher.js +708 -0
- package/plugins/webhooks/index.js +263 -0
- package/plugins/webhooks/matcher.js +113 -0
- package/plugins/webhooks/migration-template.js +75 -0
- package/plugins/webhooks/models.js +98 -0
- package/plugins/webhooks/sender.js +176 -0
- package/src/bundle/index.js +2 -1
- package/src/file-router.js +173 -4
- package/src/helpers.js +7 -1
- package/src/njk-frontmatter.js +3 -0
- package/src/routing/cascading.js +112 -0
package/.agents/ROUTING.md
CHANGED
|
@@ -400,6 +400,39 @@ Pages under `pages/` automatically inherit ancestor layouts:
|
|
|
400
400
|
</div>
|
|
401
401
|
```
|
|
402
402
|
|
|
403
|
+
#### 3. Folder-Level Error Boundaries (`_error.njk` & `_error.js`)
|
|
404
|
+
When an exception occurs during SSR lifecycle execution (in `load()`, template rendering, hooks, or nested layout loaders):
|
|
405
|
+
- **Ancestral Discovery**: Webspresso searches up the directory hierarchy from the route's directory up to `pages/` for the nearest `_error.njk`.
|
|
406
|
+
- **Isolated Layout Preservation**: `_error.njk` is automatically wrapped inside the surrounding ancestor `_layout.njk` chain, keeping the UI intact (e.g. an error in `/dashboard/billing/invoices` renders the error card inside the dashboard sidebar and header).
|
|
407
|
+
- **Companion Loader (`_error.js`)**: Can export `load({ error, req, res, ctx, db })` to attach custom error data or report exceptions.
|
|
408
|
+
- **Status Code Propagation**: HTTP status is set to `error.status || error.statusCode || 500` (e.g., throwing `NotFoundError` returns HTTP 404).
|
|
409
|
+
- **Opt-Out**: Disable layout wrapping with `layout: false` in `_error.js` or frontmatter (`--- layout: false ---`).
|
|
410
|
+
- **Fallback**: If no `_error.njk` exists in any ancestor directory, execution falls through to the global Express error boundary (`app.setErrorHandler` / 500 page).
|
|
411
|
+
|
|
412
|
+
```html
|
|
413
|
+
{# pages/dashboard/_error.njk #}
|
|
414
|
+
<div class="p-6 bg-red-50 dark:bg-red-950/30 rounded-xl border border-red-200">
|
|
415
|
+
<h2 class="text-xl font-bold text-red-700">Error {{ error.status }}</h2>
|
|
416
|
+
<p class="text-red-600 mt-2">{{ error.message }}</p>
|
|
417
|
+
{% if supportEmail %}<p class="mt-4 text-sm">Need help? Email {{ supportEmail }}</p>{% endif %}
|
|
418
|
+
</div>
|
|
419
|
+
```
|
|
420
|
+
|
|
421
|
+
#### 4. Folder-Level Loading Skeletons (`_loading.njk`)
|
|
422
|
+
In SSR streaming mode (`stream: true` or `renderStream`):
|
|
423
|
+
- **Automatic Discovery**: Discovers the nearest `_loading.njk` up the directory chain.
|
|
424
|
+
- **Auto-Populate Slots**: Any empty `<div data-stream-target="slotName"></div>` in the page template is automatically populated with the `_loading.njk` skeleton HTML in the initial flushed shell chunk!
|
|
425
|
+
- **Context Availability**: Exposed as `{{ loadingSkeleton | safe }}` and `{{ loadingHtml | safe }}` in the template context.
|
|
426
|
+
- **Layout Integration**: Cascading `_layout.njk` templates automatically wrap the streaming shell.
|
|
427
|
+
|
|
428
|
+
```html
|
|
429
|
+
{# pages/dashboard/_loading.njk #}
|
|
430
|
+
<div class="animate-pulse space-y-4">
|
|
431
|
+
<div class="h-8 bg-slate-200 dark:bg-slate-800 rounded w-1/4"></div>
|
|
432
|
+
<div class="h-32 bg-slate-200 dark:bg-slate-800 rounded"></div>
|
|
433
|
+
</div>
|
|
434
|
+
```
|
|
435
|
+
|
|
403
436
|
---
|
|
404
437
|
|
|
405
438
|
## 7. Summary Checklist for Agents
|
package/.agents/STREAMING.md
CHANGED
|
@@ -71,3 +71,38 @@ export async function load({ req, db }) {
|
|
|
71
71
|
};
|
|
72
72
|
}
|
|
73
73
|
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## 4. Folder-Based Loading Skeletons (`_loading.njk`)
|
|
78
|
+
|
|
79
|
+
Directory trees under `pages/` support automatic loading skeleton discovery and injection:
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
pages/
|
|
83
|
+
├── _loading.njk # Root fallback skeleton
|
|
84
|
+
└── dashboard/
|
|
85
|
+
├── _loading.njk # Dashboard-specific skeleton
|
|
86
|
+
├── _layout.njk # Cascading layout (wraps streaming shell)
|
|
87
|
+
├── overview.njk
|
|
88
|
+
└── overview.js # Returns { stream: true, defer: { metrics: ... } }
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Automatic Slot Population
|
|
92
|
+
When `_loading.njk` exists in a folder hierarchy, any empty `<div data-stream-target="slotName"></div>` element is automatically populated with the rendered `_loading.njk` template inside the initial flushed HTML shell:
|
|
93
|
+
|
|
94
|
+
```html
|
|
95
|
+
<!-- pages/dashboard/overview.njk -->
|
|
96
|
+
<h1>Dashboard Overview</h1>
|
|
97
|
+
|
|
98
|
+
<!-- Automatically receives _loading.njk skeleton on initial flush! -->
|
|
99
|
+
<div data-stream-target="metrics"></div>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Template Context Availability
|
|
103
|
+
The skeleton HTML is also directly accessible in the template context:
|
|
104
|
+
- `{{ loadingSkeleton | safe }}`
|
|
105
|
+
- `{{ loadingHtml | safe }}`
|
|
106
|
+
|
|
107
|
+
### Nested Layouts with Streaming
|
|
108
|
+
Cascading `_layout.njk` layouts automatically wrap the initial streaming shell chunk, preserving headers, navigation, and sidebars without extra configuration.
|
package/AGENTS.md
CHANGED
|
@@ -143,6 +143,7 @@ Plugins expose `name`, `version`, `dependencies`, and lifecycle hooks (`register
|
|
|
143
143
|
- `xlsxPlugin`: Excel spreadsheet generation, parsing, ORM streaming export (`res.xlsx`), and built-in services (`xlsx.generate`, `xlsx.parse`, `xlsx.exportModel`).
|
|
144
144
|
- `csvPlugin`: RFC 4180 CSV generator, parser, Excel UTF-8 BOM compatibility, formula sanitization, streaming writer (`res.csv`), and built-in services (`csv.generate`, `csv.parse`, `csv.exportModel`).
|
|
145
145
|
- `apiKeyPlugin`: Zero-dependency B2B & Developer API Key Management with SHA-256 secure storage, constant-time verification, granular wildcard scopes, named route middleware (`ctx.middlewares.apiKey`), and non-blocking usage tracking.
|
|
146
|
+
- `webhooksPlugin`: Outgoing Webhook Dispatcher with HMAC-SHA256 cryptographic signatures, wildcard event matching (`*`, `order.*`), automatic retries with exponential backoff, background job queue integration (`core/queue`), built-in services (`webhook.dispatch`, `webhook.ping`, `webhook.retry`), and Mithril.js Admin Panel management UI.
|
|
146
147
|
|
|
147
148
|
---
|
|
148
149
|
|
package/README.md
CHANGED
|
@@ -2,21 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/webspresso)
|
|
4
4
|
[](https://npmx.dev/package/webspresso)
|
|
5
|
+
[](https://nodejs.org)
|
|
5
6
|
[](LICENSE)
|
|
6
7
|
|
|
7
|
-
A
|
|
8
|
+
A batteries-included, full-stack Node.js framework combining Next.js/Nuxt-style file-based routing, server-rendered Nunjucks streaming, a Knex-based ORM with ambient transactions, zero-dependency dual authentication, background queues, and a customizable Mithril.js SPA Admin Panel.
|
|
8
9
|
|
|
9
10
|
---
|
|
10
11
|
|
|
11
|
-
## ⚡ Quick Start
|
|
12
|
+
## ⚡ Quick Start
|
|
12
13
|
|
|
13
|
-
|
|
14
|
+
Create a new Webspresso project in seconds:
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
|
-
#
|
|
17
|
+
# Scaffold a new application interactively
|
|
17
18
|
npx webspresso new my-app --install
|
|
18
19
|
|
|
19
|
-
#
|
|
20
|
+
# Start development server with live reload
|
|
20
21
|
cd my-app
|
|
21
22
|
npm run dev
|
|
22
23
|
```
|
|
@@ -25,132 +26,183 @@ Open **`http://localhost:3000`** in your browser.
|
|
|
25
26
|
|
|
26
27
|
---
|
|
27
28
|
|
|
28
|
-
##
|
|
29
|
+
## 🌟 Core Capabilities
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
31
|
+
| Layer | Capabilities |
|
|
32
|
+
| :--- | :--- |
|
|
33
|
+
| **Routing & SSR** | 100% file-based routing (`pages/`), method suffixes (`.get.js`, `.post.js`), nested layouts (`_layout.njk`), directory-level error boundaries (`_error.njk`), loading skeletons (`_loading.njk`), and out-of-order chunked response streaming (`res.renderStream`). |
|
|
34
|
+
| **Database & ORM** | Built-in Knex ORM with `defineModel`, `zdb` schema builder, Repository pattern (`db.getRepository('Model')`), relations (`belongsTo`, `hasMany`), cascade soft-delete & restore, and ambient transactions via `AsyncLocalStorage`. |
|
|
35
|
+
| **Dual Auth & Sessions** | Stateful cookies for SSR + stateless HS256 JWT rotation for APIs, magic links, active device management & remote session revocation, CSRF protection, and zero external auth dependencies. |
|
|
36
|
+
| **Services & Queues** | File-based auto-discovery in `services/` with declarative Zod validation, role-based access guards, and ACID transaction propagation. Background worker queues in `jobs/`. |
|
|
37
|
+
| **Admin Panel SPA** | Integrated Mithril.js single-page admin panel mounted at `/_admin` with auto-layout wrapping, CRUD views, custom dashboard widgets, and custom field renderers. |
|
|
38
|
+
| **Plugin Ecosystem** | 20+ official plugins: Polar.sh billing, Webhooks dispatcher with HMAC signatures, Realtime (WebSocket/SSE), Site Analytics, API Keys, File Manager, CSV/Excel generation, and more. |
|
|
39
|
+
| **DevOps & Production** | Built-in streaming zlib compression (`brotli`/`gzip`), socket connection draining & graceful shutdown, `webspresso deploy:check` production readiness auditor, and Docker scaffolding. |
|
|
39
40
|
|
|
40
41
|
---
|
|
41
42
|
|
|
42
|
-
## 🛠️
|
|
43
|
+
## 🛠️ Code at a Glance
|
|
43
44
|
|
|
44
|
-
### 1.
|
|
45
|
-
```javascript
|
|
46
|
-
const path = require('path');
|
|
47
|
-
require('./config/load-env');
|
|
48
|
-
const { createApp, createDatabase } = require('webspresso');
|
|
49
|
-
|
|
50
|
-
const db = createDatabase(require('./webspresso.db'));
|
|
51
|
-
|
|
52
|
-
const { app } = createApp({
|
|
53
|
-
db,
|
|
54
|
-
pagesDir: path.join(__dirname, 'pages'),
|
|
55
|
-
viewsDir: path.join(__dirname, 'views'),
|
|
56
|
-
server: {
|
|
57
|
-
shutdown: { enabled: true, timeout: 10000 },
|
|
58
|
-
compression: true,
|
|
59
|
-
},
|
|
60
|
-
});
|
|
45
|
+
### 1. File-Based Page Route (`pages/notes.njk` + `pages/notes.js`)
|
|
61
46
|
|
|
62
|
-
|
|
63
|
-
app.listen(PORT, () => {
|
|
64
|
-
console.log(`Server listening at http://localhost:${PORT}`);
|
|
65
|
-
});
|
|
66
|
-
```
|
|
47
|
+
Companion `.js` loaders fetch data server-side before template rendering:
|
|
67
48
|
|
|
68
|
-
### 2. Server-Rendered Page (`pages/index.njk` + `pages/index.js`)
|
|
69
49
|
```html
|
|
70
|
-
<!-- pages/
|
|
50
|
+
<!-- pages/notes.njk -->
|
|
71
51
|
{% extends "views/layout.njk" %}
|
|
72
52
|
|
|
73
53
|
{% block content %}
|
|
74
|
-
<div class="max-w-
|
|
75
|
-
<h1 class="text-
|
|
76
|
-
<
|
|
54
|
+
<div class="max-w-3xl mx-auto py-8">
|
|
55
|
+
<h1 class="text-2xl font-bold mb-4">My Notes</h1>
|
|
56
|
+
<ul class="space-y-2">
|
|
57
|
+
{% for note in notes %}
|
|
58
|
+
<li class="p-4 bg-white rounded border shadow-sm">{{ note.title }}</li>
|
|
59
|
+
{% else %}
|
|
60
|
+
<p class="text-slate-500">No notes yet.</p>
|
|
61
|
+
{% endfor %}
|
|
62
|
+
</ul>
|
|
77
63
|
</div>
|
|
78
64
|
{% endblock %}
|
|
79
65
|
```
|
|
80
66
|
|
|
81
67
|
```javascript
|
|
82
|
-
// pages/
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
user: req.user || null,
|
|
90
|
-
};
|
|
68
|
+
// pages/notes.js
|
|
69
|
+
module.exports = {
|
|
70
|
+
async load({ req, db }) {
|
|
71
|
+
const notes = await db.getRepository('Note').find({
|
|
72
|
+
userId: req.user?.id,
|
|
73
|
+
});
|
|
74
|
+
return { notes };
|
|
91
75
|
},
|
|
92
|
-
}
|
|
76
|
+
};
|
|
93
77
|
```
|
|
94
78
|
|
|
95
|
-
###
|
|
79
|
+
### 2. Method-Suffixed API Route (`pages/api/notes.post.js`)
|
|
80
|
+
|
|
81
|
+
Export `{ schema, middleware, handler }` or `defineApi()` with declarative Zod validation:
|
|
82
|
+
|
|
96
83
|
```javascript
|
|
97
|
-
|
|
84
|
+
// pages/api/notes.post.js
|
|
85
|
+
const { defineApi } = require('webspresso');
|
|
98
86
|
|
|
99
87
|
module.exports = defineApi({
|
|
100
|
-
schema: {
|
|
88
|
+
schema: ({ z }) => ({
|
|
101
89
|
body: z.object({
|
|
102
|
-
|
|
90
|
+
title: z.string().min(1, 'Title is required').max(200),
|
|
91
|
+
content: z.string().min(1),
|
|
103
92
|
}),
|
|
93
|
+
}),
|
|
94
|
+
middleware: ['auth'], // Built-in session or JWT guard
|
|
95
|
+
async handler(req, res) {
|
|
96
|
+
// req.input.body is validated and typed
|
|
97
|
+
const note = await req.db.getRepository('Note').create({
|
|
98
|
+
...req.input.body,
|
|
99
|
+
userId: req.user.id,
|
|
100
|
+
});
|
|
101
|
+
return res.status(201).json(note);
|
|
102
|
+
},
|
|
103
|
+
});
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 3. ORM Model Definition (`models/Note.js`)
|
|
107
|
+
|
|
108
|
+
Define models with `defineModel` and the expressive `zdb` schema builder:
|
|
109
|
+
|
|
110
|
+
```javascript
|
|
111
|
+
// models/Note.js
|
|
112
|
+
const { defineModel, zdb } = require('webspresso');
|
|
113
|
+
|
|
114
|
+
module.exports = defineModel({
|
|
115
|
+
name: 'Note',
|
|
116
|
+
table: 'notes',
|
|
117
|
+
schema: {
|
|
118
|
+
id: zdb.id(),
|
|
119
|
+
title: zdb.string(200),
|
|
120
|
+
content: zdb.text(),
|
|
121
|
+
userId: zdb.integer(),
|
|
122
|
+
...zdb.timestamps(),
|
|
123
|
+
...zdb.softDeletes(),
|
|
104
124
|
},
|
|
125
|
+
relations: {
|
|
126
|
+
user: { type: 'belongsTo', model: 'User', foreignKey: 'userId' },
|
|
127
|
+
},
|
|
128
|
+
});
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### 4. Application Server (`server.js`)
|
|
105
132
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
133
|
+
```javascript
|
|
134
|
+
const path = require('path');
|
|
135
|
+
const { createApp, createDatabase } = require('webspresso');
|
|
136
|
+
|
|
137
|
+
const db = createDatabase(require('./webspresso.db'));
|
|
138
|
+
|
|
139
|
+
const { app } = createApp({
|
|
140
|
+
db,
|
|
141
|
+
pagesDir: path.join(__dirname, 'pages'),
|
|
142
|
+
viewsDir: path.join(__dirname, 'views'),
|
|
143
|
+
server: {
|
|
144
|
+
compression: true,
|
|
145
|
+
shutdown: { enabled: true, timeout: 10000 },
|
|
110
146
|
},
|
|
111
147
|
});
|
|
148
|
+
|
|
149
|
+
const PORT = process.env.PORT || 3000;
|
|
150
|
+
app.listen(PORT, () => {
|
|
151
|
+
console.log(`Server running at http://localhost:${PORT}`);
|
|
152
|
+
});
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
---
|
|
156
|
+
|
|
157
|
+
## 🧰 Essential CLI Commands
|
|
158
|
+
|
|
159
|
+
```bash
|
|
160
|
+
# Development & Builds
|
|
161
|
+
npx webspresso dev # Start dev server with watch & live reload
|
|
162
|
+
npx webspresso build # Compile production assets
|
|
163
|
+
npx webspresso start # Run production server
|
|
164
|
+
|
|
165
|
+
# Database & Migrations
|
|
166
|
+
npx webspresso db:migrate # Run pending database migrations
|
|
167
|
+
npx webspresso db:rollback # Roll back latest migration batch
|
|
168
|
+
npx webspresso db:status # Inspect migration status
|
|
169
|
+
npx webspresso seed # Run seed files
|
|
170
|
+
|
|
171
|
+
# Code Generation
|
|
172
|
+
npx webspresso page <path> # Scaffold a new SSR page + loader
|
|
173
|
+
npx webspresso api <path> # Scaffold a new method-suffixed API route
|
|
174
|
+
npx webspresso make:model <name> # Generate a new ORM model
|
|
175
|
+
npx webspresso make:job <name> # Generate a background queue job
|
|
176
|
+
|
|
177
|
+
# DevOps & Production Readiness
|
|
178
|
+
npx webspresso doctor # Run project health & configuration check
|
|
179
|
+
npx webspresso deploy:check # Pre-flight production readiness inspection
|
|
180
|
+
npx webspresso add:docker # Scaffold Dockerfile & docker-compose.yml
|
|
181
|
+
npx webspresso add:tailwind # Configure TailwindCSS integration
|
|
112
182
|
```
|
|
113
183
|
|
|
114
184
|
---
|
|
115
185
|
|
|
116
186
|
## 📚 Documentation
|
|
117
187
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
- **[
|
|
122
|
-
- **[
|
|
123
|
-
- **[
|
|
124
|
-
- **[
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
- **[
|
|
128
|
-
- **[SSR & Templates](docs/guides/ssr-and-templates.md)** — Nunjucks layouts, `load()` loaders, `fsy` helper catalog, and chunked streaming.
|
|
129
|
-
- **[Services Layer](docs/guides/services.md)** — Defining services, Zod validation, auth role guards, and ACID transactions.
|
|
130
|
-
- **[Database & ORM](docs/guides/database-and-orm.md)** — Model definitions (`defineModel`), `zdb` schema builder, and Knex migrations.
|
|
131
|
-
- **[Dual Authentication](docs/guides/authentication.md)** — Stateful Session cookies for SSR and stateless JWT rotation for REST APIs.
|
|
132
|
-
- **[Admin Panel Customization](docs/guides/admin-panel.md)** — Custom Mithril.js SPA pages, KPI widgets, and custom field renderers.
|
|
133
|
-
|
|
134
|
-
### 🧠 Concepts & Architecture ("How does it work and why?")
|
|
135
|
-
- **[System Architecture](docs/concepts/architecture.md)** — Layered architecture, subsystem boundaries, and design principles.
|
|
136
|
-
- **[Request Lifecycle](docs/concepts/request-lifecycle.md)** — End-to-end trace from TCP socket to template render and response stream.
|
|
137
|
-
- **[Service Execution Pipeline](docs/concepts/service-execution-pipeline.md)** — Sanitization, Zod validation, auth guards, ambient transactions, and caching.
|
|
138
|
-
- **[Ambient Transaction Propagation](docs/concepts/transaction-propagation.md)** — How `AsyncLocalStorage` manages ACID database transactions across nested services.
|
|
139
|
-
|
|
140
|
-
### 📚 API Reference ("What is the exact contract?")
|
|
141
|
-
- **[`createApp()` Configuration](docs/reference/create-app.md)** — Full `CreateAppOptions` parameter reference.
|
|
142
|
-
- **[CLI Reference](docs/reference/cli.md)** — Complete `webspresso` CLI command manual.
|
|
143
|
-
- **[Service Definition Spec](docs/reference/service-definition.md)** — `defineService` options and `ServiceContext` properties.
|
|
144
|
-
- **[Model Definition Spec](docs/reference/model-definition.md)** — `defineModel` options, `zdb` column types, and `Repository` query methods.
|
|
145
|
-
- **[Exceptions Catalog](docs/reference/exceptions.md)** — Built-in framework exception classes and HTTP status codes.
|
|
188
|
+
Detailed topic guides are available in the repository:
|
|
189
|
+
|
|
190
|
+
- **[Installation & First App](docs/getting-started/installation.md)** — Node.js requirements, setup, and first steps.
|
|
191
|
+
- **[File-Based Routing & API Routes](.agents/ROUTING.md)** — Routing conventions, parameters, and cascading layouts.
|
|
192
|
+
- **[SSR Streaming & Chunked Transfer](.agents/STREAMING.md)** — Out-of-order slots, `_loading.njk` skeletons, and TTFB optimization.
|
|
193
|
+
- **[Database & ORM Guide](.agents/ORM.md)** — Repositories, relations, soft deletes, and ambient transactions.
|
|
194
|
+
- **[Dual Authentication System](.agents/AUTH.md)** — Sessions, JWT rotation, magic links, and device management.
|
|
195
|
+
- **[Plugin Ecosystem Reference](.agents/PLUGINS.md)** — Polar billing, webhooks, analytics, realtime, and more.
|
|
196
|
+
- **[Admin Panel Customization](.agents/ADMIN.md)** — Extending the Mithril.js SPA admin panel.
|
|
197
|
+
- **[Full TypeScript Reference](index.d.ts)** — Canonical framework types and signatures.
|
|
146
198
|
|
|
147
199
|
---
|
|
148
200
|
|
|
149
|
-
## 🤖 For AI Coding
|
|
201
|
+
## 🤖 For AI Coding Assistants
|
|
150
202
|
|
|
151
|
-
If you are an autonomous coding
|
|
152
|
-
- Read **[`AGENTS.md`](AGENTS.md)** for
|
|
153
|
-
-
|
|
203
|
+
If you are an autonomous coding agent working in a Webspresso codebase:
|
|
204
|
+
- Read **[`AGENTS.md`](AGENTS.md)** for mandatory architectural rules, zero-regression policies, and code contracts.
|
|
205
|
+
- Check **[`llms.txt`](llms.txt)** for a machine-readable directory map of all documentation.
|
|
154
206
|
|
|
155
207
|
---
|
|
156
208
|
|