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,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Swagger_Publisher — publishes interactive API documentation as HTTP endpoints.
|
|
3
|
+
*
|
|
4
|
+
* This publisher extends {@link HTTP_Publisher} and provides two routes:
|
|
5
|
+
*
|
|
6
|
+
* | Route | Method | Content-Type | Purpose |
|
|
7
|
+
* |----------------------|--------|--------------------|----------------------------------|
|
|
8
|
+
* | `/api/openapi.json` | GET | `application/json` | OpenAPI 3.0.3 specification |
|
|
9
|
+
* | `/api/docs` | GET | `text/html` | Interactive Swagger UI page |
|
|
10
|
+
*
|
|
11
|
+
* ## How It Works
|
|
12
|
+
*
|
|
13
|
+
* - The HTML page is generated once at construction time and cached
|
|
14
|
+
* (it's static — the CDN-loaded Swagger UI fetches the spec at runtime).
|
|
15
|
+
* - The OpenAPI spec is regenerated on every request so it always reflects
|
|
16
|
+
* the current set of registered endpoints.
|
|
17
|
+
* - Both the HTML generator ({@link module:publishers/swagger-ui}) and the
|
|
18
|
+
* spec generator ({@link module:openapi}) are zero-dependency utility
|
|
19
|
+
* modules used internally by this publisher.
|
|
20
|
+
*
|
|
21
|
+
* ## Usage
|
|
22
|
+
*
|
|
23
|
+
* ### Automatic (via Server.serve)
|
|
24
|
+
*
|
|
25
|
+
* When `swagger` is enabled (default in development), `Server.serve()` creates
|
|
26
|
+
* a `Swagger_Publisher` automatically and registers it on the router:
|
|
27
|
+
*
|
|
28
|
+
* ```js
|
|
29
|
+
* Server.serve({
|
|
30
|
+
* port: 8080,
|
|
31
|
+
* swagger: true,
|
|
32
|
+
* api: { 'ping': { handler: () => ({ pong: true }), method: 'GET' } }
|
|
33
|
+
* });
|
|
34
|
+
* // → /api/docs and /api/openapi.json are automatically available
|
|
35
|
+
* ```
|
|
36
|
+
*
|
|
37
|
+
* ### Manual (standalone)
|
|
38
|
+
*
|
|
39
|
+
* You can also create and register a `Swagger_Publisher` directly:
|
|
40
|
+
*
|
|
41
|
+
* ```js
|
|
42
|
+
* const Swagger_Publisher = require('jsgui3-server/publishers/swagger-publisher');
|
|
43
|
+
*
|
|
44
|
+
* const pub = new Swagger_Publisher({
|
|
45
|
+
* server: my_server,
|
|
46
|
+
* title: 'My API',
|
|
47
|
+
* version: '2.0.0'
|
|
48
|
+
* });
|
|
49
|
+
*
|
|
50
|
+
* // Register on the server's router:
|
|
51
|
+
* my_server.server_router.set_route('/api/openapi.json', pub, pub.handle_http);
|
|
52
|
+
* my_server.server_router.set_route('/api/docs', pub, pub.handle_http);
|
|
53
|
+
* ```
|
|
54
|
+
*
|
|
55
|
+
* ## Publisher Lifecycle
|
|
56
|
+
*
|
|
57
|
+
* - **Construction** — generates and caches the HTML page, stores spec options.
|
|
58
|
+
* - **ready event** — emitted immediately (no async setup required).
|
|
59
|
+
* - **handle_http** — routes incoming requests to the appropriate handler
|
|
60
|
+
* based on `req.url`.
|
|
61
|
+
*
|
|
62
|
+
* @extends HTTP_Publisher
|
|
63
|
+
* @see {@link module:openapi} — spec generation utility.
|
|
64
|
+
* @see {@link module:publishers/swagger-ui} — HTML page generation utility.
|
|
65
|
+
* @module publishers/swagger-publisher
|
|
66
|
+
*/
|
|
67
|
+
|
|
68
|
+
'use strict';
|
|
69
|
+
|
|
70
|
+
const HTTP_Publisher = require('./http-publisher');
|
|
71
|
+
const { generate_openapi_spec } = require('../openapi');
|
|
72
|
+
const { generate_swagger_html } = require('./swagger-ui');
|
|
73
|
+
|
|
74
|
+
class Swagger_Publisher extends HTTP_Publisher {
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Create a new Swagger_Publisher.
|
|
78
|
+
*
|
|
79
|
+
* @param {Object} spec - Configuration options.
|
|
80
|
+
* @param {Object} spec.server - The JSGUI_Single_Process_Server instance
|
|
81
|
+
* whose API registry will be used to generate the OpenAPI spec.
|
|
82
|
+
* @param {string} [spec.title] - API title for the spec `info.title` field.
|
|
83
|
+
* @param {string} [spec.version] - API version for the spec `info.version` field.
|
|
84
|
+
* @param {string} [spec.description] - API description for the spec `info.description` field.
|
|
85
|
+
* @param {string} [spec.spec_url='/api/openapi.json'] - URL the Swagger UI
|
|
86
|
+
* page uses to fetch the OpenAPI spec. Override if serving from a
|
|
87
|
+
* non-standard path.
|
|
88
|
+
* @param {string} [spec.docs_route='/api/docs'] - Route path for the
|
|
89
|
+
* Swagger UI HTML page. Used to match incoming requests in `handle_http`.
|
|
90
|
+
* @param {string} [spec.spec_route='/api/openapi.json'] - Route path for
|
|
91
|
+
* the OpenAPI JSON endpoint. Used to match incoming requests.
|
|
92
|
+
*/
|
|
93
|
+
constructor(spec = {}) {
|
|
94
|
+
super(spec);
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Reference to the server instance whose APIs are documented.
|
|
98
|
+
* @type {Object}
|
|
99
|
+
*/
|
|
100
|
+
this.server = spec.server;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Route path that serves the OpenAPI JSON spec.
|
|
104
|
+
* @type {string}
|
|
105
|
+
*/
|
|
106
|
+
this.spec_route = spec.spec_route || '/api/openapi.json';
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Route path that serves the Swagger UI HTML page.
|
|
110
|
+
* @type {string}
|
|
111
|
+
*/
|
|
112
|
+
this.docs_route = spec.docs_route || '/api/docs';
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Options passed through to the OpenAPI spec generator.
|
|
116
|
+
* @type {{ title?: string, version?: string, description?: string }}
|
|
117
|
+
*/
|
|
118
|
+
this.spec_options = {
|
|
119
|
+
title: spec.title,
|
|
120
|
+
version: spec.version,
|
|
121
|
+
description: spec.description
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Publisher type identifier (used by the Publishers registry).
|
|
126
|
+
* @type {string}
|
|
127
|
+
*/
|
|
128
|
+
this.type = 'swagger';
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Cached HTML buffer for the Swagger UI page.
|
|
132
|
+
* Generated once at construction time since the page is static
|
|
133
|
+
* (the dynamic spec is fetched by Swagger UI at runtime via XHR).
|
|
134
|
+
* @type {Buffer}
|
|
135
|
+
* @private
|
|
136
|
+
*/
|
|
137
|
+
this._html_buffer = Buffer.from(
|
|
138
|
+
generate_swagger_html({
|
|
139
|
+
spec_url: spec.spec_url || this.spec_route,
|
|
140
|
+
title: spec.title || 'API Documentation'
|
|
141
|
+
}),
|
|
142
|
+
'utf8'
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// Emit ready — this publisher has no async setup.
|
|
146
|
+
const self = this;
|
|
147
|
+
setImmediate(() => self.raise('ready', { _arr: [] }));
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Handle an incoming HTTP request.
|
|
152
|
+
*
|
|
153
|
+
* Routes the request based on `req.url`:
|
|
154
|
+
*
|
|
155
|
+
* - **spec_route** (`/api/openapi.json`) — generates the OpenAPI spec
|
|
156
|
+
* from `this.server` and responds with JSON.
|
|
157
|
+
* - **docs_route** (`/api/docs`) — responds with the cached Swagger UI
|
|
158
|
+
* HTML page.
|
|
159
|
+
* - **Other URLs** — responds with 404.
|
|
160
|
+
*
|
|
161
|
+
* Only GET and HEAD methods are allowed; other methods receive 405.
|
|
162
|
+
*
|
|
163
|
+
* @param {http.IncomingMessage} req - Node.js HTTP request.
|
|
164
|
+
* @param {http.ServerResponse} res - Node.js HTTP response.
|
|
165
|
+
*/
|
|
166
|
+
handle_http(req, res) {
|
|
167
|
+
// Only allow GET / HEAD.
|
|
168
|
+
if (req.method !== 'GET' && req.method !== 'HEAD') {
|
|
169
|
+
res.writeHead(405, { 'Allow': 'GET' });
|
|
170
|
+
res.end('Method Not Allowed');
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Strip query string for route matching.
|
|
175
|
+
const url_path = req.url.split('?')[0];
|
|
176
|
+
|
|
177
|
+
if (url_path === this.spec_route) {
|
|
178
|
+
// ── Serve OpenAPI JSON spec ──
|
|
179
|
+
const spec = generate_openapi_spec(this.server, this.spec_options);
|
|
180
|
+
const json = JSON.stringify(spec, null, 2);
|
|
181
|
+
res.writeHead(200, {
|
|
182
|
+
'Content-Type': 'application/json; charset=utf-8',
|
|
183
|
+
'Cache-Control': 'no-cache'
|
|
184
|
+
});
|
|
185
|
+
res.end(json);
|
|
186
|
+
|
|
187
|
+
} else if (url_path === this.docs_route) {
|
|
188
|
+
// ── Serve Swagger UI HTML ──
|
|
189
|
+
res.writeHead(200, {
|
|
190
|
+
'Content-Type': 'text/html; charset=utf-8',
|
|
191
|
+
'Content-Length': this._html_buffer.length,
|
|
192
|
+
'Cache-Control': 'no-cache'
|
|
193
|
+
});
|
|
194
|
+
res.end(this._html_buffer);
|
|
195
|
+
|
|
196
|
+
} else {
|
|
197
|
+
res.writeHead(404);
|
|
198
|
+
res.end('Not Found');
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
module.exports = Swagger_Publisher;
|