jsgui3-server 0.0.150 → 0.0.152
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/.github/instructions/copilot.instructions.md +1 -0
- package/AGENTS.md +2 -0
- package/README.md +89 -13
- package/admin-ui/v1/controls/admin_shell.js +702 -669
- package/admin-ui/v1/server.js +14 -1
- package/docs/api-reference.md +504 -306
- package/docs/books/creating-a-new-admin-ui/README.md +20 -20
- package/docs/books/website-design/01-introduction.md +73 -0
- package/docs/books/website-design/02-current-state.md +195 -0
- package/docs/books/website-design/03-base-class.md +181 -0
- package/docs/books/website-design/04-webpage.md +307 -0
- package/docs/books/website-design/05-website.md +456 -0
- package/docs/books/website-design/06-pages-storage.md +170 -0
- package/docs/books/website-design/07-api-layer.md +285 -0
- package/docs/books/website-design/08-server-integration.md +271 -0
- package/docs/books/website-design/09-cross-agent-review.md +190 -0
- package/docs/books/website-design/10-open-questions.md +196 -0
- package/docs/books/website-design/11-converged-recommendation.md +205 -0
- package/docs/books/website-design/12-content-model.md +395 -0
- package/docs/books/website-design/13-webpage-module-spec.md +404 -0
- package/docs/books/website-design/14-website-module-spec.md +541 -0
- package/docs/books/website-design/15-multi-repo-plan.md +275 -0
- package/docs/books/website-design/16-minimal-first.md +203 -0
- package/docs/books/website-design/17-implementation-report-codex.md +81 -0
- package/docs/books/website-design/README.md +43 -0
- package/docs/comprehensive-documentation.md +220 -220
- package/docs/configuration-reference.md +281 -204
- package/docs/middleware-guide.md +236 -0
- package/docs/proposals/jsgui3-website-and-webpage-design-jsgui3-server-support.md +257 -0
- package/docs/proposals/jsgui3-website-and-webpage-design-review.md +73 -0
- package/docs/proposals/jsgui3-website-and-webpage-design.md +732 -0
- package/docs/swagger.md +316 -0
- package/docs/system-architecture.md +24 -18
- package/examples/controls/1) window/server.js +6 -1
- package/examples/controls/21) mvvm and declarative api/check.js +94 -0
- package/examples/controls/21) mvvm and declarative api/check_output.txt +25 -0
- package/examples/controls/21) mvvm and declarative api/check_output_2.txt +27 -0
- package/examples/controls/21) mvvm and declarative api/client.js +241 -0
- declarative api/e2e-screenshot-1-name-change.png +0 -0
- declarative api/e2e-screenshot-2-toggled.png +0 -0
- declarative api/e2e-screenshot-3-final.png +0 -0
- declarative api/e2e-screenshot-final.png +0 -0
- package/examples/controls/21) mvvm and declarative api/e2e-test.js +175 -0
- package/examples/controls/21) mvvm and declarative api/out.html +1 -0
- package/examples/controls/21) mvvm and declarative api/page_out.html +1 -0
- package/examples/controls/21) mvvm and declarative api/server.js +18 -0
- package/examples/data-views/01) query-endpoint/server.js +61 -0
- package/labs/website-design/001-base-class-overhead/check.js +162 -0
- package/labs/website-design/002-pages-storage/check.js +244 -0
- package/labs/website-design/002-pages-storage/results.txt +0 -0
- package/labs/website-design/003-type-detection/check.js +193 -0
- package/labs/website-design/003-type-detection/results.txt +0 -0
- package/labs/website-design/004-two-stage-validation/check.js +314 -0
- package/labs/website-design/004-two-stage-validation/results.txt +0 -0
- package/labs/website-design/005-normalize-input/check.js +303 -0
- package/labs/website-design/006-serve-website-spike/check.js +290 -0
- package/labs/website-design/README.md +34 -0
- package/labs/website-design/manifest.json +68 -0
- package/labs/website-design/run-all.js +60 -0
- package/middleware/compression.js +217 -0
- package/middleware/index.js +15 -0
- package/middleware/json-body.js +126 -0
- package/module.js +3 -0
- package/openapi.js +474 -0
- package/package.json +11 -8
- package/publishers/Publishers.js +6 -5
- package/publishers/http-function-publisher.js +135 -126
- package/publishers/http-webpage-publisher.js +89 -11
- package/publishers/query-publisher.js +116 -0
- package/publishers/swagger-publisher.js +203 -0
- package/publishers/swagger-ui.js +578 -0
- package/resources/adapters/array-adapter.js +143 -0
- package/resources/query-resource.js +131 -0
- package/serve-factory.js +756 -18
- package/server.js +502 -123
- package/tests/README.md +23 -1
- package/tests/admin-ui-jsgui-controls.test.js +16 -1
- package/tests/helpers/playwright-e2e-harness.js +326 -0
- package/tests/openapi.test.js +319 -0
- package/tests/playwright-smoke.test.js +134 -0
- package/tests/publish-enhancements.test.js +673 -0
- package/tests/query-publisher.test.js +430 -0
- package/tests/quick-json-body-test.js +169 -0
- package/tests/serve.test.js +425 -122
- package/tests/swagger-publisher.test.js +1076 -0
- package/tests/test-runner.js +1 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# Middleware Guide
|
|
2
|
+
|
|
3
|
+
jsgui3-server includes a lightweight middleware pipeline inspired by Express's `app.use()`. Middleware functions run **before** every request reaches the router, letting you add cross-cutting concerns — compression, CORS, logging, auth — without modifying route handlers.
|
|
4
|
+
|
|
5
|
+
## Quick Start
|
|
6
|
+
|
|
7
|
+
```javascript
|
|
8
|
+
const Server = require('jsgui3-server');
|
|
9
|
+
const { compression } = require('jsgui3-server/middleware');
|
|
10
|
+
|
|
11
|
+
const server = new Server({ Ctrl: My_Control, src_path_client_js: __dirname + '/client.js' });
|
|
12
|
+
|
|
13
|
+
// Enable gzip/deflate/brotli compression for JSON, HTML, CSS, JS responses
|
|
14
|
+
server.use(compression());
|
|
15
|
+
|
|
16
|
+
server.on('ready', () => server.start(8080));
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Or via `Server.serve()`:
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
Server.serve({
|
|
23
|
+
Ctrl: My_Control,
|
|
24
|
+
src_path_client_js: __dirname + '/client.js',
|
|
25
|
+
compression: true, // shorthand: enables compression with defaults
|
|
26
|
+
port: 8080
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
---
|
|
31
|
+
|
|
32
|
+
## API
|
|
33
|
+
|
|
34
|
+
### `server.use(fn)`
|
|
35
|
+
|
|
36
|
+
Register a middleware function. Middleware is executed in registration order before the request reaches the router.
|
|
37
|
+
|
|
38
|
+
| Parameter | Type | Description |
|
|
39
|
+
|-----------|------|-------------|
|
|
40
|
+
| `fn` | `function(req, res, next)` | Middleware function |
|
|
41
|
+
|
|
42
|
+
**Returns:** `this` (chainable)
|
|
43
|
+
|
|
44
|
+
**Middleware signature:**
|
|
45
|
+
```javascript
|
|
46
|
+
function my_middleware(req, res, next) {
|
|
47
|
+
// Do work before routing
|
|
48
|
+
// ...
|
|
49
|
+
next(); // Continue to next middleware / router
|
|
50
|
+
// -- or --
|
|
51
|
+
next(err); // Skip remaining middleware, trigger error handler
|
|
52
|
+
}
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
**Example — request logger:**
|
|
56
|
+
```javascript
|
|
57
|
+
server.use((req, res, next) => {
|
|
58
|
+
console.log(`${req.method} ${req.url}`);
|
|
59
|
+
next();
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**Example — CORS headers:**
|
|
64
|
+
```javascript
|
|
65
|
+
server.use((req, res, next) => {
|
|
66
|
+
res.setHeader('Access-Control-Allow-Origin', '*');
|
|
67
|
+
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
|
|
68
|
+
res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
|
|
69
|
+
if (req.method === 'OPTIONS') {
|
|
70
|
+
res.writeHead(204);
|
|
71
|
+
res.end();
|
|
72
|
+
return; // Don't call next() — request is handled
|
|
73
|
+
}
|
|
74
|
+
next();
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### `Server.serve()` Options
|
|
79
|
+
|
|
80
|
+
| Option | Type | Description |
|
|
81
|
+
|--------|------|-------------|
|
|
82
|
+
| `middleware` | `function \| function[]` | One or more middleware functions to register |
|
|
83
|
+
| `compression` | `boolean \| object` | Enable built-in compression middleware. Pass `true` for defaults or an options object |
|
|
84
|
+
|
|
85
|
+
```javascript
|
|
86
|
+
Server.serve({
|
|
87
|
+
Ctrl: My_Control,
|
|
88
|
+
src_path_client_js: __dirname + '/client.js',
|
|
89
|
+
middleware: [
|
|
90
|
+
(req, res, next) => { console.log(req.url); next(); }
|
|
91
|
+
],
|
|
92
|
+
compression: { threshold: 512 },
|
|
93
|
+
port: 8080
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Built-in Middleware
|
|
100
|
+
|
|
101
|
+
### `compression([options])`
|
|
102
|
+
|
|
103
|
+
Response compression middleware. Transparently compresses response bodies when:
|
|
104
|
+
|
|
105
|
+
1. The client sends an `Accept-Encoding` header matching a supported algorithm
|
|
106
|
+
2. The response `Content-Type` is compressible (JSON, HTML, CSS, JS, XML, SVG, plain text)
|
|
107
|
+
3. The body size meets or exceeds the threshold
|
|
108
|
+
|
|
109
|
+
Streaming responses (SSE, chunked writes via `res.write()`) are passed through uncompressed.
|
|
110
|
+
|
|
111
|
+
```javascript
|
|
112
|
+
const { compression } = require('jsgui3-server/middleware');
|
|
113
|
+
server.use(compression());
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
**Options:**
|
|
117
|
+
|
|
118
|
+
| Option | Type | Default | Description |
|
|
119
|
+
|--------|------|---------|-------------|
|
|
120
|
+
| `threshold` | `number` | `1024` | Minimum body size in bytes to compress |
|
|
121
|
+
| `level` | `number` | `Z_DEFAULT_COMPRESSION` | zlib compression level (1–9, or -1 for default) |
|
|
122
|
+
|
|
123
|
+
**Encoding negotiation priority:** gzip → deflate → brotli
|
|
124
|
+
|
|
125
|
+
gzip is preferred for dynamic content because it offers the best speed/ratio trade-off. Brotli provides better compression ratios but is significantly slower for on-the-fly compression; it's more appropriate for pre-compressed static assets.
|
|
126
|
+
|
|
127
|
+
**Compressible content types:**
|
|
128
|
+
- `application/json`
|
|
129
|
+
- `text/html`, `text/plain`, `text/css`, `text/xml`, `text/csv`
|
|
130
|
+
- `application/javascript`, `text/javascript`
|
|
131
|
+
- `application/xml`, `application/xhtml+xml`, `application/manifest+json`
|
|
132
|
+
- `image/svg+xml`
|
|
133
|
+
|
|
134
|
+
**What is NOT compressed:**
|
|
135
|
+
- Bodies smaller than `threshold`
|
|
136
|
+
- Non-text content types (images, video, binary)
|
|
137
|
+
- Responses with an existing `Content-Encoding` header
|
|
138
|
+
- Streaming responses (where `res.write()` is called before `res.end()`)
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
## How It Works
|
|
143
|
+
|
|
144
|
+
### Execution Order
|
|
145
|
+
|
|
146
|
+
```
|
|
147
|
+
HTTP Request
|
|
148
|
+
│
|
|
149
|
+
▼
|
|
150
|
+
middleware[0](req, res, next) ──next()──►
|
|
151
|
+
middleware[1](req, res, next) ──next()──►
|
|
152
|
+
...
|
|
153
|
+
middleware[n](req, res, next) ──next()──►
|
|
154
|
+
server_router.process(req, res) ◄── routing + publishers
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### Response Wrapping (Compression Pattern)
|
|
158
|
+
|
|
159
|
+
The compression middleware intercepts `res.writeHead()` and `res.end()`:
|
|
160
|
+
|
|
161
|
+
1. **`res.writeHead()`** — Buffers the status code and headers instead of sending them immediately
|
|
162
|
+
2. **`res.end(body)`** — Checks the content type and body size; if compressible, compresses the body, updates `Content-Encoding` and `Content-Length` headers, then sends everything
|
|
163
|
+
3. **`res.write(chunk)`** — If called (streaming), flushes buffered headers and passes writes through unmodified
|
|
164
|
+
|
|
165
|
+
This means compression is transparent to publishers and route handlers — they continue to write responses normally.
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Writing Custom Middleware
|
|
170
|
+
|
|
171
|
+
### Basic Pattern
|
|
172
|
+
|
|
173
|
+
```javascript
|
|
174
|
+
function my_middleware(req, res, next) {
|
|
175
|
+
// 1. Pre-processing (before routing)
|
|
176
|
+
// Modify req, set headers, check auth, etc.
|
|
177
|
+
|
|
178
|
+
// 2. Continue the chain
|
|
179
|
+
next();
|
|
180
|
+
|
|
181
|
+
// 3. Post-processing is NOT supported in this simple model.
|
|
182
|
+
// For response wrapping, intercept res.end() like compression does.
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Response Wrapping Pattern
|
|
187
|
+
|
|
188
|
+
To modify the response body (like compression does), intercept `res.end()`:
|
|
189
|
+
|
|
190
|
+
```javascript
|
|
191
|
+
function response_timer(req, res, next) {
|
|
192
|
+
const start = Date.now();
|
|
193
|
+
const _end = res.end;
|
|
194
|
+
|
|
195
|
+
res.end = function () {
|
|
196
|
+
res.setHeader('X-Response-Time', `${Date.now() - start}ms`);
|
|
197
|
+
_end.apply(res, arguments);
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
next();
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
server.use(response_timer);
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Error Handling
|
|
207
|
+
|
|
208
|
+
If a middleware throws or calls `next(err)`, the error handler sends a 500 response and logs the error. Remaining middleware and routing are skipped.
|
|
209
|
+
|
|
210
|
+
```javascript
|
|
211
|
+
server.use((req, res, next) => {
|
|
212
|
+
try {
|
|
213
|
+
validate_request(req);
|
|
214
|
+
next();
|
|
215
|
+
} catch (err) {
|
|
216
|
+
next(err); // → 500 Internal Server Error
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
---
|
|
222
|
+
|
|
223
|
+
## Access via Module Exports
|
|
224
|
+
|
|
225
|
+
```javascript
|
|
226
|
+
// Direct require
|
|
227
|
+
const { compression } = require('jsgui3-server/middleware');
|
|
228
|
+
|
|
229
|
+
// Via Server class
|
|
230
|
+
const Server = require('jsgui3-server');
|
|
231
|
+
const { compression } = Server.middleware;
|
|
232
|
+
|
|
233
|
+
// Via jsgui module
|
|
234
|
+
const jsgui = require('jsgui3-server');
|
|
235
|
+
const { compression } = jsgui.middleware;
|
|
236
|
+
```
|
|
@@ -0,0 +1,257 @@
|
|
|
1
|
+
# Proposal: jsgui3-server Support for New Website/Webpage Primitives
|
|
2
|
+
|
|
3
|
+
> **Date**: 2026-02-16
|
|
4
|
+
> **Status**: Proposal for review (no implementation)
|
|
5
|
+
> **Companion docs**:
|
|
6
|
+
> `docs/proposals/jsgui3-website-and-webpage-design.md`
|
|
7
|
+
> `docs/proposals/jsgui3-website-and-webpage-design-review.md`
|
|
8
|
+
|
|
9
|
+
## 1. Purpose
|
|
10
|
+
|
|
11
|
+
Define the server-side changes required so `jsgui3-server` can fully support richer `jsgui3-website` / `jsgui3-webpage` primitives and the extra information they encapsulate, while preserving backward compatibility with existing `Server.serve(...)` usage.
|
|
12
|
+
|
|
13
|
+
## 2. Core Integration Principles
|
|
14
|
+
|
|
15
|
+
1. `jsgui3-server` should accept both classic inputs (Ctrl/functions/options) and new primitive objects.
|
|
16
|
+
2. Integration should use capability/shape normalization, not fragile runtime class identity checks.
|
|
17
|
+
3. Primitive metadata should flow into routing, bundling, HTTP headers, and admin introspection.
|
|
18
|
+
4. Static and dynamic page rendering must be first-class, explicit modes.
|
|
19
|
+
5. Existing behavior must remain intact by default.
|
|
20
|
+
|
|
21
|
+
## 3. Current Gaps in jsgui3-server
|
|
22
|
+
|
|
23
|
+
1. `publishers/http-website-publisher.js` depends on `instanceof Website` and `website.pages._arr` internals.
|
|
24
|
+
2. `publishers/http-website-publisher.js` has incomplete multi-page publication code paths (`NYI`).
|
|
25
|
+
3. `serve-factory.js` mainly normalizes function/options inputs, not richer website primitives.
|
|
26
|
+
4. API publishing currently assumes `api` as a plain name→handler map; endpoint metadata is not preserved.
|
|
27
|
+
5. Per-page metadata (render mode, page-level assets, cache hints, tags) is not represented in publication decisions.
|
|
28
|
+
6. Admin/tooling introspection is not using a stable website manifest contract.
|
|
29
|
+
|
|
30
|
+
## 4. Proposed Server Data Contract (Internal)
|
|
31
|
+
|
|
32
|
+
Add an internal, normalized manifest that all publishers consume.
|
|
33
|
+
|
|
34
|
+
### 4.1 `normalized_website_manifest`
|
|
35
|
+
|
|
36
|
+
```js
|
|
37
|
+
{
|
|
38
|
+
name,
|
|
39
|
+
base_path,
|
|
40
|
+
meta,
|
|
41
|
+
assets,
|
|
42
|
+
pages: [normalized_page_manifest],
|
|
43
|
+
api_endpoints: [normalized_api_manifest],
|
|
44
|
+
policies
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### 4.2 `normalized_page_manifest`
|
|
49
|
+
|
|
50
|
+
```js
|
|
51
|
+
{
|
|
52
|
+
id,
|
|
53
|
+
name,
|
|
54
|
+
path,
|
|
55
|
+
title,
|
|
56
|
+
content,
|
|
57
|
+
render_mode, // 'static' | 'dynamic'
|
|
58
|
+
head,
|
|
59
|
+
meta,
|
|
60
|
+
assets,
|
|
61
|
+
scripts,
|
|
62
|
+
stylesheets,
|
|
63
|
+
cache_policy,
|
|
64
|
+
route_priority
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### 4.3 `normalized_api_manifest`
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
{
|
|
72
|
+
name,
|
|
73
|
+
method,
|
|
74
|
+
path,
|
|
75
|
+
handler,
|
|
76
|
+
description,
|
|
77
|
+
auth,
|
|
78
|
+
rate_limit,
|
|
79
|
+
tags
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
The key idea: all incoming forms normalize into this one server contract before routing/bundling begins.
|
|
84
|
+
|
|
85
|
+
## 5. File-by-File Changes in jsgui3-server
|
|
86
|
+
|
|
87
|
+
### 5.1 `serve-factory.js`
|
|
88
|
+
|
|
89
|
+
Add a normalization phase before server startup.
|
|
90
|
+
|
|
91
|
+
1. Add helpers such as `normalize_serve_input`, `normalize_website_input`, `normalize_webpage_input`, `normalize_api_input`.
|
|
92
|
+
2. Accept additional input forms: `new Website(...)`, website-like plain objects with `pages`, `new Webpage(...)`, and webpage-like plain objects with `path` + `content`.
|
|
93
|
+
3. Build `normalized_website_manifest` and attach it to `server_instance`.
|
|
94
|
+
4. Preserve old `ctrl/page/pages/api` options by translating them into the same normalized manifest.
|
|
95
|
+
5. Resolve route conflicts early with deterministic precedence rules.
|
|
96
|
+
|
|
97
|
+
Impact: `serve-factory.js` becomes the single place where compatibility and input variability are handled.
|
|
98
|
+
|
|
99
|
+
### 5.2 `publishers/http-webpageorsite-publisher.js`
|
|
100
|
+
|
|
101
|
+
Refactor this shared base to consume a normalized manifest instead of raw ad hoc shape assumptions.
|
|
102
|
+
|
|
103
|
+
1. Add `prepare_manifest_bundle(manifest, options)` entrypoint.
|
|
104
|
+
2. Split shared logic into clear units such as `prepare_shared_client_bundle`, `prepare_page_static_assets`, and `build_static_route_response_items`.
|
|
105
|
+
3. Keep SSR-only mode supported when no client bundle path exists.
|
|
106
|
+
|
|
107
|
+
Impact: all page/site publishers share one bundling and route-item preparation pipeline.
|
|
108
|
+
|
|
109
|
+
### 5.3 `publishers/http-webpage-publisher.js`
|
|
110
|
+
|
|
111
|
+
Extend single-page publisher to honor encapsulated page metadata.
|
|
112
|
+
|
|
113
|
+
1. Respect `render_mode`.
|
|
114
|
+
2. `static`: pre-render HTML and serve static response items.
|
|
115
|
+
3. `dynamic`: register request-time render handler for that route.
|
|
116
|
+
4. Inject page-level assets/scripts/stylesheets in addition to shared site assets.
|
|
117
|
+
5. Apply page-level response policies (`cache_policy`, optional headers).
|
|
118
|
+
6. Include page manifest details in emitted `ready` payload for introspection.
|
|
119
|
+
|
|
120
|
+
Impact: one-page apps gain parity with multi-page site semantics.
|
|
121
|
+
|
|
122
|
+
### 5.4 `publishers/http-website-publisher.js`
|
|
123
|
+
|
|
124
|
+
This file needs the largest rewrite.
|
|
125
|
+
|
|
126
|
+
1. Remove hard dependency on `instanceof Website` and `website.pages._arr`.
|
|
127
|
+
2. Accept normalized website manifest from `serve-factory.js`.
|
|
128
|
+
3. For each page in `manifest.pages`, route by render mode (static page: pre-render + static route registration, dynamic page: register dynamic render handler).
|
|
129
|
+
4. Register API endpoints from `manifest.api_endpoints` with method/path semantics.
|
|
130
|
+
5. Add support for site-level `base_path` prefixing.
|
|
131
|
+
6. Emit a structured publication summary object (`routes`, `assets`, `api`, `warnings`).
|
|
132
|
+
|
|
133
|
+
Impact: `HTTP_Website_Publisher` becomes complete and deterministic for multi-page websites.
|
|
134
|
+
|
|
135
|
+
### 5.5 `server.js`
|
|
136
|
+
|
|
137
|
+
Add lightweight hooks so publication metadata can be surfaced consistently.
|
|
138
|
+
|
|
139
|
+
1. Add structured route registration helper for static and dynamic routes.
|
|
140
|
+
2. Add endpoint publication helper that accepts method/path metadata.
|
|
141
|
+
3. Preserve existing `publish(name, fn)` API but map it to default endpoint metadata.
|
|
142
|
+
4. Expose `server_instance.website_manifest` and `server_instance.publication_summary` for tooling/admin.
|
|
143
|
+
|
|
144
|
+
Impact: no breaking API change, but much better visibility.
|
|
145
|
+
|
|
146
|
+
### 5.6 `website/website.js` and `website/webpage.js`
|
|
147
|
+
|
|
148
|
+
Keep these wrappers, but add comments and type-guards that describe the normalized contract expected by server internals.
|
|
149
|
+
|
|
150
|
+
Impact: clearer boundaries between primitive packages and server adapters.
|
|
151
|
+
|
|
152
|
+
### 5.7 New helper modules (recommended)
|
|
153
|
+
|
|
154
|
+
Create a dedicated server-side normalization area.
|
|
155
|
+
|
|
156
|
+
1. `website/normalize_website_manifest.js`
|
|
157
|
+
2. `website/normalize_page_manifest.js`
|
|
158
|
+
3. `website/normalize_api_manifest.js`
|
|
159
|
+
4. `website/resolve_route_conflicts.js`
|
|
160
|
+
5. `website/build_publication_summary.js`
|
|
161
|
+
|
|
162
|
+
Impact: removes format-specific logic from publishers and centralizes compatibility policy.
|
|
163
|
+
|
|
164
|
+
## 6. Primitive Field → Server Behavior Mapping
|
|
165
|
+
|
|
166
|
+
| Primitive field | Server subsystem | Required behavior |
|
|
167
|
+
|---|---|---|
|
|
168
|
+
| `page.path` | Router | Normalize leading slash, register route, detect conflicts |
|
|
169
|
+
| `page.render_mode` | Publisher/rendering | Choose static pre-render vs dynamic request-time render |
|
|
170
|
+
| `page.content` | Renderer | Validate constructor/function and render consistently |
|
|
171
|
+
| `page.assets/scripts/stylesheets` | Bundling/publish | Include per-page resources in route item list |
|
|
172
|
+
| `page.cache_policy` | HTTP response | Set cache headers for HTML/assets |
|
|
173
|
+
| `page.meta/head` | HTML generation | Emit tags into rendered document |
|
|
174
|
+
| `website.base_path` | Routing | Prefix all page and API routes deterministically |
|
|
175
|
+
| `website.assets` | Bundling | Register site-wide static assets |
|
|
176
|
+
| `website.api` / endpoint metadata | API publisher | Publish endpoints with method/path/description/auth metadata |
|
|
177
|
+
| `website.meta` | Admin/introspection | Expose in summary and diagnostics APIs |
|
|
178
|
+
|
|
179
|
+
## 7. Backward Compatibility Strategy
|
|
180
|
+
|
|
181
|
+
1. Maintain current `Server.serve(Ctrl)` behavior unchanged.
|
|
182
|
+
2. Maintain current options object behavior (`ctrl`, `page`, `pages`, `api`).
|
|
183
|
+
3. Introduce a compatibility normalization layer that converts old options to manifest format.
|
|
184
|
+
4. Keep `server.publish(name, fn)` valid; internally convert to `{ method: 'GET', path: '/api/:name' }` (or current default route convention).
|
|
185
|
+
5. Log non-breaking warnings when deprecated shapes are detected.
|
|
186
|
+
|
|
187
|
+
## 8. Error Handling and Diagnostics
|
|
188
|
+
|
|
189
|
+
Standardize errors from normalization and publication stages.
|
|
190
|
+
|
|
191
|
+
1. `invalid_page_definition`
|
|
192
|
+
2. `invalid_api_endpoint`
|
|
193
|
+
3. `duplicate_route`
|
|
194
|
+
4. `unsupported_render_mode`
|
|
195
|
+
5. `asset_resolution_failure`
|
|
196
|
+
|
|
197
|
+
Each error should include:
|
|
198
|
+
|
|
199
|
+
1. `code`
|
|
200
|
+
2. `message`
|
|
201
|
+
3. `context` (`page_id`, `route`, `endpoint_name`, `source`)
|
|
202
|
+
|
|
203
|
+
This is necessary for actionable admin UX and debugging.
|
|
204
|
+
|
|
205
|
+
## 9. Testing Changes Required
|
|
206
|
+
|
|
207
|
+
### 9.1 Unit tests
|
|
208
|
+
|
|
209
|
+
1. Normalization from legacy inputs to manifest.
|
|
210
|
+
2. Route conflict detection and precedence.
|
|
211
|
+
3. API endpoint normalization (method/path defaults).
|
|
212
|
+
4. Render mode routing decisions.
|
|
213
|
+
|
|
214
|
+
### 9.2 Integration tests
|
|
215
|
+
|
|
216
|
+
1. Single-page static primitive.
|
|
217
|
+
2. Single-page dynamic primitive.
|
|
218
|
+
3. Multi-page mixed static/dynamic website.
|
|
219
|
+
4. Website with API endpoint metadata.
|
|
220
|
+
5. Base path + asset publication behavior.
|
|
221
|
+
6. Legacy `Server.serve` calls still passing unchanged.
|
|
222
|
+
|
|
223
|
+
### 9.3 Regression tests
|
|
224
|
+
|
|
225
|
+
1. No client JS path still starts server in SSR-only mode.
|
|
226
|
+
2. Admin route still comes up with website manifest present.
|
|
227
|
+
3. Existing compression and middleware pipeline remains intact.
|
|
228
|
+
|
|
229
|
+
## 10. Suggested Delivery Phases
|
|
230
|
+
|
|
231
|
+
1. **Phase 1: normalization + compatibility**
|
|
232
|
+
Implement manifest normalization in `serve-factory.js`, keep existing publishers mostly intact.
|
|
233
|
+
|
|
234
|
+
2. **Phase 2: publisher modernization**
|
|
235
|
+
Refactor `http-webpageorsite-publisher.js`, `http-webpage-publisher.js`, `http-website-publisher.js` to consume normalized manifest and remove `_arr`/`instanceof` coupling.
|
|
236
|
+
|
|
237
|
+
3. **Phase 3: metadata completeness**
|
|
238
|
+
Implement full field mapping (assets, cache policy, endpoint metadata, introspection summary).
|
|
239
|
+
|
|
240
|
+
4. **Phase 4: admin/tooling surface**
|
|
241
|
+
Expose publication summaries and diagnostics for admin views and debugging.
|
|
242
|
+
|
|
243
|
+
## 11. Recommended Initial Scope
|
|
244
|
+
|
|
245
|
+
For a practical first milestone, support this subset end-to-end.
|
|
246
|
+
|
|
247
|
+
1. `website.pages` with explicit `path` + `content`
|
|
248
|
+
2. `page.render_mode` (`static`/`dynamic`)
|
|
249
|
+
3. `website.api` endpoint metadata (`method`, `path`, `handler`)
|
|
250
|
+
4. normalized publication summary
|
|
251
|
+
5. full backward compatibility with current `Server.serve` signatures
|
|
252
|
+
|
|
253
|
+
This gives immediate value without requiring every advanced field on day one.
|
|
254
|
+
|
|
255
|
+
## 12. Outcome
|
|
256
|
+
|
|
257
|
+
With these changes, `jsgui3-server` will be able to serve richer website/webpage primitives as first-class inputs, preserve all encapsulated structure/metadata, and remain backward compatible with existing users.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Review: jsgui3-website-and-webpage-design
|
|
2
|
+
|
|
3
|
+
> **Date**: 2026-02-16
|
|
4
|
+
> **Scope**: Review + design contributions only (no implementation)
|
|
5
|
+
|
|
6
|
+
## Best ideas
|
|
7
|
+
|
|
8
|
+
1. **Keeping `jsgui3-website` / `jsgui3-webpage` optional to `jsgui3-server` is the strongest architectural choice.**
|
|
9
|
+
Reason: this preserves low-friction serving for simple cases while still allowing richer abstractions for apps that want them.
|
|
10
|
+
|
|
11
|
+
2. **Making inspectability a first-class goal (`toJSON()`, metadata exposure) is excellent.**
|
|
12
|
+
Reason: admin tooling, diagnostics, docs generation, and tests all benefit from a stable introspection surface.
|
|
13
|
+
|
|
14
|
+
3. **Supporting multiple page input shapes (`Array` and object-map) is pragmatic.**
|
|
15
|
+
Reason: object-map is concise for route-centric definitions, while arrays are better for ordered or generated page sets.
|
|
16
|
+
|
|
17
|
+
4. **Calling out the `API.js` export bug explicitly is very good proposal hygiene.**
|
|
18
|
+
Reason: the proposal is grounded in reality and identifies a hard runtime blocker.
|
|
19
|
+
|
|
20
|
+
5. **The open-question section is high quality and correctly focused.**
|
|
21
|
+
Reason: it addresses exactly the unknowns that matter for primitives (dynamic rendering, ordering, nesting, server vs page concerns).
|
|
22
|
+
|
|
23
|
+
## Worst ideas
|
|
24
|
+
|
|
25
|
+
1. **Leaning on `Collection` internals (`pages._arr`) is the weakest technical direction.**
|
|
26
|
+
Reason: this bakes internal details into public behavior, increases fragility, and makes future refactors painful.
|
|
27
|
+
|
|
28
|
+
2. **Using `Evented_Class` as a default `Webpage` model is over-engineered for current needs.**
|
|
29
|
+
Reason: it adds boilerplate, coupling, and cognitive load before there is a concrete consumer that needs per-field change events.
|
|
30
|
+
|
|
31
|
+
3. **Hard-coupling primitives to `jsgui3-html` creates unnecessary dependency weight.**
|
|
32
|
+
Reason: website/webpage definitions are mostly domain objects; making them require the full UI/control stack limits reuse (including non-server tooling).
|
|
33
|
+
|
|
34
|
+
4. **`instanceof` as a core integration strategy is brittle across duplicated installs/workspaces.**
|
|
35
|
+
Reason: two copies of a package can fail `instanceof` even when shape-compatible; server boundaries should prefer capability checks and normalization.
|
|
36
|
+
|
|
37
|
+
5. **Defaulting page `path` to `'/'` can silently mask configuration mistakes.**
|
|
38
|
+
Reason: accidental missing routes become root collisions; this should be explicit in multi-page scenarios.
|
|
39
|
+
|
|
40
|
+
## Contributions to the design discussion
|
|
41
|
+
|
|
42
|
+
1. **Use a layered model: core primitives + server adapter layer.**
|
|
43
|
+
Core primitives should be plain and lightweight (`Webpage`, `Website`, `Website_Api`) with minimal runtime dependencies. Server-specific translation can stay in `jsgui3-server`.
|
|
44
|
+
|
|
45
|
+
2. **Define a strict minimal contract for primitives.**
|
|
46
|
+
For `Webpage`: `path`, `title`, `content`, `meta`, `assets`, `render_mode` (`static` / `dynamic`).
|
|
47
|
+
For `Website`: page registry, endpoint registry, metadata, and deterministic serialization.
|
|
48
|
+
|
|
49
|
+
3. **Prefer `Map` semantics for page identity, but expose stable methods, not internals.**
|
|
50
|
+
Use `add_page`, `get_page`, `has_page`, `remove_page`, `list_pages`; do not expose storage internals like `_arr`.
|
|
51
|
+
|
|
52
|
+
4. **Separate endpoint declaration from server publishing.**
|
|
53
|
+
`Website_Api` should store endpoint definitions (`name`, `method`, `path`, `handler`, `description`, `auth`) while `jsgui3-server` decides how to publish them.
|
|
54
|
+
|
|
55
|
+
5. **Normalize and validate early.**
|
|
56
|
+
Route normalization (`/` prefix), duplicate policy, and handler/type checks should happen when constructing primitives, not at publish time.
|
|
57
|
+
|
|
58
|
+
6. **Add lifecycle semantics instead of full reactivity.**
|
|
59
|
+
A simple `finalize()` (or equivalent) model is likely enough: mutable during composition, read-mostly after publish. This gives safety without event-system complexity.
|
|
60
|
+
|
|
61
|
+
7. **Make introspection a formal API contract.**
|
|
62
|
+
Keep `toJSON()` deterministic and tool-friendly so admin UIs and docs generators can rely on it without peeking into implementation details.
|
|
63
|
+
|
|
64
|
+
## Suggested direction
|
|
65
|
+
|
|
66
|
+
A strong near-term path is effectively **Webpage B-lite + Website C-lite**:
|
|
67
|
+
|
|
68
|
+
- Keep property helpers and introspection.
|
|
69
|
+
- Use `Map`-style semantics for routes and endpoint registration.
|
|
70
|
+
- Avoid `Evented_Class` and `Collection._arr` coupling.
|
|
71
|
+
- Keep primitives lightweight and let `jsgui3-server` own serving/bundling mechanics.
|
|
72
|
+
|
|
73
|
+
This keeps the primitives expressive enough for creative website/page design while staying robust for server integration.
|