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.
Files changed (86) hide show
  1. package/.github/instructions/copilot.instructions.md +1 -0
  2. package/AGENTS.md +2 -0
  3. package/README.md +89 -13
  4. package/admin-ui/v1/controls/admin_shell.js +702 -669
  5. package/admin-ui/v1/server.js +14 -1
  6. package/docs/api-reference.md +504 -306
  7. package/docs/books/creating-a-new-admin-ui/README.md +20 -20
  8. package/docs/books/website-design/01-introduction.md +73 -0
  9. package/docs/books/website-design/02-current-state.md +195 -0
  10. package/docs/books/website-design/03-base-class.md +181 -0
  11. package/docs/books/website-design/04-webpage.md +307 -0
  12. package/docs/books/website-design/05-website.md +456 -0
  13. package/docs/books/website-design/06-pages-storage.md +170 -0
  14. package/docs/books/website-design/07-api-layer.md +285 -0
  15. package/docs/books/website-design/08-server-integration.md +271 -0
  16. package/docs/books/website-design/09-cross-agent-review.md +190 -0
  17. package/docs/books/website-design/10-open-questions.md +196 -0
  18. package/docs/books/website-design/11-converged-recommendation.md +205 -0
  19. package/docs/books/website-design/12-content-model.md +395 -0
  20. package/docs/books/website-design/13-webpage-module-spec.md +404 -0
  21. package/docs/books/website-design/14-website-module-spec.md +541 -0
  22. package/docs/books/website-design/15-multi-repo-plan.md +275 -0
  23. package/docs/books/website-design/16-minimal-first.md +203 -0
  24. package/docs/books/website-design/17-implementation-report-codex.md +81 -0
  25. package/docs/books/website-design/README.md +43 -0
  26. package/docs/comprehensive-documentation.md +220 -220
  27. package/docs/configuration-reference.md +281 -204
  28. package/docs/middleware-guide.md +236 -0
  29. package/docs/proposals/jsgui3-website-and-webpage-design-jsgui3-server-support.md +257 -0
  30. package/docs/proposals/jsgui3-website-and-webpage-design-review.md +73 -0
  31. package/docs/proposals/jsgui3-website-and-webpage-design.md +732 -0
  32. package/docs/swagger.md +316 -0
  33. package/docs/system-architecture.md +24 -18
  34. package/examples/controls/1) window/server.js +6 -1
  35. package/examples/controls/21) mvvm and declarative api/check.js +94 -0
  36. package/examples/controls/21) mvvm and declarative api/check_output.txt +25 -0
  37. package/examples/controls/21) mvvm and declarative api/check_output_2.txt +27 -0
  38. package/examples/controls/21) mvvm and declarative api/client.js +241 -0
  39. declarative api/e2e-screenshot-1-name-change.png +0 -0
  40. declarative api/e2e-screenshot-2-toggled.png +0 -0
  41. declarative api/e2e-screenshot-3-final.png +0 -0
  42. declarative api/e2e-screenshot-final.png +0 -0
  43. package/examples/controls/21) mvvm and declarative api/e2e-test.js +175 -0
  44. package/examples/controls/21) mvvm and declarative api/out.html +1 -0
  45. package/examples/controls/21) mvvm and declarative api/page_out.html +1 -0
  46. package/examples/controls/21) mvvm and declarative api/server.js +18 -0
  47. package/examples/data-views/01) query-endpoint/server.js +61 -0
  48. package/labs/website-design/001-base-class-overhead/check.js +162 -0
  49. package/labs/website-design/002-pages-storage/check.js +244 -0
  50. package/labs/website-design/002-pages-storage/results.txt +0 -0
  51. package/labs/website-design/003-type-detection/check.js +193 -0
  52. package/labs/website-design/003-type-detection/results.txt +0 -0
  53. package/labs/website-design/004-two-stage-validation/check.js +314 -0
  54. package/labs/website-design/004-two-stage-validation/results.txt +0 -0
  55. package/labs/website-design/005-normalize-input/check.js +303 -0
  56. package/labs/website-design/006-serve-website-spike/check.js +290 -0
  57. package/labs/website-design/README.md +34 -0
  58. package/labs/website-design/manifest.json +68 -0
  59. package/labs/website-design/run-all.js +60 -0
  60. package/middleware/compression.js +217 -0
  61. package/middleware/index.js +15 -0
  62. package/middleware/json-body.js +126 -0
  63. package/module.js +3 -0
  64. package/openapi.js +474 -0
  65. package/package.json +11 -8
  66. package/publishers/Publishers.js +6 -5
  67. package/publishers/http-function-publisher.js +135 -126
  68. package/publishers/http-webpage-publisher.js +89 -11
  69. package/publishers/query-publisher.js +116 -0
  70. package/publishers/swagger-publisher.js +203 -0
  71. package/publishers/swagger-ui.js +578 -0
  72. package/resources/adapters/array-adapter.js +143 -0
  73. package/resources/query-resource.js +131 -0
  74. package/serve-factory.js +756 -18
  75. package/server.js +502 -123
  76. package/tests/README.md +23 -1
  77. package/tests/admin-ui-jsgui-controls.test.js +16 -1
  78. package/tests/helpers/playwright-e2e-harness.js +326 -0
  79. package/tests/openapi.test.js +319 -0
  80. package/tests/playwright-smoke.test.js +134 -0
  81. package/tests/publish-enhancements.test.js +673 -0
  82. package/tests/query-publisher.test.js +430 -0
  83. package/tests/quick-json-body-test.js +169 -0
  84. package/tests/serve.test.js +425 -122
  85. package/tests/swagger-publisher.test.js +1076 -0
  86. 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;