jsgui3-server 0.0.147 → 0.0.149

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 (145) hide show
  1. package/.github/workflows/control-scan-manifest-check.yml +31 -0
  2. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-071799b982906680f5fd699d.js +40 -0
  3. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-07352945ad5c92654fcb8b65.js +39 -0
  4. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-138a601fadb6191ea314c6fd.js +39 -0
  5. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-171f6c381c2cadf2e9fa7087.js +39 -0
  6. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-1d973388156b84a04373fac9.js +39 -0
  7. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-20e117bc8a10d2cd16234bbe.js +40 -0
  8. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-2b028a82b0e5efddba42425f.js +39 -0
  9. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-4518556cd5c7e059e82b22b8.js +40 -0
  10. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5bac1aa0f213902f718ed74f.js +40 -0
  11. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5f9996ac7822caf777d92f56.js +39 -0
  12. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-60a92c702e65fd9cf748e3ec.js +39 -0
  13. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6164c1f8f738995c541895d2.js +44 -0
  14. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6718a85eb9e5aa782dd47a05.js +45 -0
  15. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-69e280f14e37aee76a1d4675.js +39 -0
  16. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7570d1b030d44b111ed59c4c.js +39 -0
  17. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7798c9bbd55e510d5039f936.js +42 -0
  18. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-78cd511ea1ef18ecb03d1be5.js +40 -0
  19. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7d482e0b95bcb5e3c543118b.js +43 -0
  20. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-80e9476d1127c55b40fdb36f.js +40 -0
  21. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-810ced55d5320a3088a05b13.js +40 -0
  22. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-8423565f1a40e329afc8c6cf.js +40 -0
  23. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-900bef783b8cee36506ec282.js +39 -0
  24. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-a1a37aff6416fdad74040ddf.js +39 -0
  25. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-ad48d5e8eda40f175b4df090.js +39 -0
  26. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-aec5a2d963015528c9099462.js +39 -0
  27. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-af9d34e0f1722fab9e28c269.js +39 -0
  28. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-b818e4015e2f1fe86280b5ab.js +41 -0
  29. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bcb2541adc70b7aba61768c5.js +44 -0
  30. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bfe89d2c78ed44f95ed7dd73.js +40 -0
  31. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c06f04806a1e688e1187110c.js +40 -0
  32. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c3f3adf904f585afc544b96a.js +39 -0
  33. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-d45acb873e1d8e32d5e60f2e.js +39 -0
  34. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-db06f132533706f4a0163b8c.js +39 -0
  35. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f660f40d78b135fc8560a862.js +39 -0
  36. package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f9dee4ec18a96e09bee06bae.js +39 -0
  37. package/README.md +85 -3
  38. package/admin-ui/client.js +213 -0
  39. package/admin-ui/server.js +104 -0
  40. package/client/controls/auto-observable.js +207 -0
  41. package/dev-status.svg +139 -0
  42. package/docs/api-reference.md +301 -43
  43. package/docs/books/admin-ui/01-introduction.md +32 -0
  44. package/docs/books/admin-ui/02-architecture.md +92 -0
  45. package/docs/books/admin-ui/03-controls.md +194 -0
  46. package/docs/books/admin-ui/04-implementation-plan.md +62 -0
  47. package/docs/books/admin-ui/README.md +26 -0
  48. package/docs/books/jsgui3-bundling-research-book/00-table-of-contents.md +35 -0
  49. package/docs/books/jsgui3-bundling-research-book/01-pipeline-and-runtime-semantics.md +34 -0
  50. package/docs/books/jsgui3-bundling-research-book/02-javascript-bundling-core.md +36 -0
  51. package/docs/books/jsgui3-bundling-research-book/03-style-extraction-and-css-compilation.md +35 -0
  52. package/docs/books/jsgui3-bundling-research-book/04-static-publishing-and-delivery.md +39 -0
  53. package/docs/books/jsgui3-bundling-research-book/05-current-limits-and-size-bloat-vectors.md +25 -0
  54. package/docs/books/jsgui3-bundling-research-book/06-unused-module-elimination-strategy.md +77 -0
  55. package/docs/books/jsgui3-bundling-research-book/07-jsgui3-html-control-and-mixin-pruning.md +63 -0
  56. package/docs/books/jsgui3-bundling-research-book/08-test-and-verification-methodology.md +43 -0
  57. package/docs/books/jsgui3-bundling-research-book/09-roadmap-and-rollout.md +42 -0
  58. package/docs/books/jsgui3-bundling-research-book/10-further-research-strategies-and-upgrades.md +211 -0
  59. package/docs/books/jsgui3-bundling-research-book/README.md +35 -0
  60. package/docs/bundling-system-deep-dive.md +9 -4
  61. package/docs/comprehensive-documentation.md +49 -18
  62. package/docs/configuration-reference.md +152 -27
  63. package/docs/core/README.md +19 -0
  64. package/docs/core/jsgui3-server-core-book/00-table-of-contents.md +21 -0
  65. package/docs/core/jsgui3-server-core-book/01-startup-readiness-state-machine.md +41 -0
  66. package/docs/core/jsgui3-server-core-book/02-resource-abstraction-and-lifecycle.md +92 -0
  67. package/docs/core/jsgui3-server-core-book/03-resource-pool-and-event-topology.md +47 -0
  68. package/docs/core/jsgui3-server-core-book/04-sse-publisher-semantics.md +41 -0
  69. package/docs/core/jsgui3-server-core-book/05-serve-factory-resource-wiring.md +46 -0
  70. package/docs/core/jsgui3-server-core-book/06-e2e-testing-methodology.md +48 -0
  71. package/docs/core/jsgui3-server-core-book/07-defect-detection-and-hardening-loop.md +47 -0
  72. package/docs/publishers-guide.md +59 -4
  73. package/docs/resources-guide.md +184 -35
  74. package/docs/simple-server-api-design.md +72 -17
  75. package/docs/system-architecture.md +18 -14
  76. package/examples/controls/15) window, observable SSE/server.js +6 -1
  77. package/examples/controls/19) window, auto observable ui/client.js +125 -0
  78. package/examples/controls/19) window, auto observable ui/server.js +73 -0
  79. package/examples/controls/20) window, task manager app/README.md +133 -0
  80. package/examples/controls/20) window, task manager app/client.js +797 -0
  81. package/examples/controls/20) window, task manager app/server.js +178 -0
  82. package/examples/controls/6) window, color_palette/client.js +165 -68
  83. package/examples/controls/9) window, date picker/client.js +362 -76
  84. package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +104 -83
  85. package/examples/jsgui3-html/06) theming/client.js +22 -1
  86. package/examples/jsgui3-html/10) binding-debugger/client.js +137 -1
  87. package/http/responders/static/Static_Route_HTTP_Responder.js +52 -34
  88. package/lab/experiments/capture-color-controls.js +196 -0
  89. package/lab/results/screenshots/color-controls/full_page.png +0 -0
  90. package/lab/results/screenshots/color-controls/section_1_color_grid_12x12.png +0 -0
  91. package/lab/results/screenshots/color-controls/section_2_color_grid_4x2.png +0 -0
  92. package/lab/results/screenshots/color-controls/section_3_color_palette.png +0 -0
  93. package/lab/results/screenshots/color-controls/section_4_palette_comparison.png +0 -0
  94. package/lab/results/screenshots/color-controls/section_5_raw_swatches.png +0 -0
  95. package/lab/results/screenshots/color-controls/section_6_optimized_crayola.png +0 -0
  96. package/lab/results/screenshots/color-controls/section_7_pastel_palette.png +0 -0
  97. package/lab/results/screenshots/color-controls/section_8_extended_144.png +0 -0
  98. package/lab/screenshot-utils.js +248 -0
  99. package/module.js +11 -4
  100. package/package.json +14 -4
  101. package/publishers/Publishers.js +4 -3
  102. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +5 -5
  103. package/publishers/http-observable-publisher.js +8 -0
  104. package/publishers/http-sse-publisher.js +341 -0
  105. package/publishers/http-webpage-publisher.js +13 -3
  106. package/publishers/http-webpageorsite-publisher.js +18 -0
  107. package/resources/process-resource.js +950 -0
  108. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +164 -46
  109. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +18 -7
  110. package/resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer.js +829 -0
  111. package/resources/remote-process-resource.js +355 -0
  112. package/resources/server-resource-pool.js +354 -41
  113. package/serve-factory.js +441 -259
  114. package/server.js +161 -16
  115. package/tests/README.md +66 -4
  116. package/tests/admin-ui-render.test.js +24 -0
  117. package/tests/assigners.test.js +56 -40
  118. package/tests/bundling-default-control-elimination.puppeteer.test.js +260 -0
  119. package/tests/configuration-validation.test.js +21 -18
  120. package/tests/content-analysis.test.js +7 -6
  121. package/tests/control-optimizer-cache-behavior.test.js +52 -0
  122. package/tests/control-scan-manifest-regression.test.js +144 -0
  123. package/tests/end-to-end.test.js +15 -14
  124. package/tests/error-handling.test.js +222 -179
  125. package/tests/fixtures/bundling-default-button-client.js +37 -0
  126. package/tests/fixtures/bundling-default-window-client.js +34 -0
  127. package/tests/fixtures/control_scan_manifest_expectations.json +48 -0
  128. package/tests/fixtures/resource-monitor-client.js +319 -0
  129. package/tests/helpers/puppeteer-e2e-harness.js +317 -0
  130. package/tests/http-sse-publisher.test.js +136 -0
  131. package/tests/performance.test.js +69 -65
  132. package/tests/process-resource.test.js +138 -0
  133. package/tests/publishers.test.js +7 -7
  134. package/tests/remote-process-resource.test.js +160 -0
  135. package/tests/sass-controls.e2e.test.js +7 -1
  136. package/tests/serve-resources.test.js +270 -0
  137. package/tests/serve.test.js +120 -50
  138. package/tests/server-resource-pool.test.js +106 -0
  139. package/tests/small-controls-bundle-size.test.js +252 -0
  140. package/tests/test-runner.js +13 -1
  141. package/tests/window-examples.puppeteer.test.js +204 -1
  142. package/tests/window-resource-integration.puppeteer.test.js +585 -0
  143. package/tests/temp_invalid.js +0 -7
  144. package/tests/temp_invalid_utf8.js +0 -1
  145. package/tests/temp_malformed.js +0 -10
@@ -0,0 +1,248 @@
1
+ /**
2
+ * Screenshot Utilities for jsgui3-server
3
+ *
4
+ * Reusable Puppeteer-based screenshot capture, extracted from
5
+ * tests/window-examples.puppeteer.test.js patterns.
6
+ *
7
+ * Usage:
8
+ * const { launch_browser, capture_page, close_browser } = require('./screenshot-utils');
9
+ * await launch_browser();
10
+ * const result = await capture_page('http://localhost:3600', {
11
+ * output_path: './screenshots/full_page.png',
12
+ * full_page: true
13
+ * });
14
+ * await close_browser();
15
+ */
16
+
17
+ const fs = require('fs');
18
+ const path = require('path');
19
+
20
+ let puppeteer;
21
+ let browser;
22
+
23
+ /**
24
+ * Launch a headless Puppeteer browser.
25
+ * @param {Object} [options]
26
+ * @param {boolean} [options.headless=true]
27
+ * @param {string} [options.executable_path] - Custom Chrome/Chromium path
28
+ * @returns {Promise<import('puppeteer').Browser>}
29
+ */
30
+ const launch_browser = async (options = {}) => {
31
+ if (browser) return browser;
32
+
33
+ if (!puppeteer) {
34
+ puppeteer = require('puppeteer');
35
+ }
36
+
37
+ const launch_options = {
38
+ headless: options.headless !== false ? 'new' : false,
39
+ args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-gpu']
40
+ };
41
+
42
+ if (options.executable_path || process.env.PUPPETEER_EXECUTABLE_PATH) {
43
+ launch_options.executablePath = options.executable_path || process.env.PUPPETEER_EXECUTABLE_PATH;
44
+ }
45
+
46
+ browser = await puppeteer.launch(launch_options);
47
+ return browser;
48
+ };
49
+
50
+ /**
51
+ * Capture a screenshot of a URL.
52
+ * @param {string} url - URL to navigate to
53
+ * @param {Object} [options]
54
+ * @param {string} [options.output_path] - File path for the PNG
55
+ * @param {boolean} [options.full_page=true] - Capture full scrollable page
56
+ * @param {number} [options.width=1280] - Viewport width
57
+ * @param {number} [options.height=720] - Viewport height
58
+ * @param {number} [options.wait_ms=1000] - Wait time after load before capture
59
+ * @param {string} [options.wait_for_selector] - CSS selector to wait for
60
+ * @returns {Promise<{path: string, width: number, height: number, size_bytes: number}>}
61
+ */
62
+ const capture_page = async (url, options = {}) => {
63
+ if (!browser) {
64
+ throw new Error('Browser not launched. Call launch_browser() first.');
65
+ }
66
+
67
+ const {
68
+ output_path,
69
+ full_page = true,
70
+ width = 1280,
71
+ height = 720,
72
+ wait_ms = 1000,
73
+ wait_for_selector
74
+ } = options;
75
+
76
+ const page = await browser.newPage();
77
+
78
+ try {
79
+ await page.setViewport({ width, height });
80
+ await page.goto(url, { waitUntil: 'networkidle0', timeout: 30000 });
81
+
82
+ if (wait_for_selector) {
83
+ await page.waitForSelector(wait_for_selector, { timeout: 10000 });
84
+ }
85
+
86
+ if (wait_ms > 0) {
87
+ await new Promise(r => setTimeout(r, wait_ms));
88
+ }
89
+
90
+ // Ensure output directory exists
91
+ if (output_path) {
92
+ fs.mkdirSync(path.dirname(output_path), { recursive: true });
93
+ }
94
+
95
+ const screenshot_path = output_path || path.join(process.cwd(), 'screenshot.png');
96
+ await page.screenshot({ path: screenshot_path, fullPage: full_page });
97
+
98
+ const stats = fs.statSync(screenshot_path);
99
+ const dimensions = await page.evaluate(() => ({
100
+ width: document.documentElement.scrollWidth,
101
+ height: document.documentElement.scrollHeight
102
+ }));
103
+
104
+ return {
105
+ path: screenshot_path,
106
+ width: dimensions.width,
107
+ height: dimensions.height,
108
+ size_bytes: stats.size
109
+ };
110
+ } finally {
111
+ await page.close();
112
+ }
113
+ };
114
+
115
+ /**
116
+ * Capture a screenshot of a specific element on a page.
117
+ * @param {string} url - URL to navigate to
118
+ * @param {string} selector - CSS selector for the element
119
+ * @param {Object} [options]
120
+ * @param {string} [options.output_path] - File path for the PNG
121
+ * @param {number} [options.width=1280] - Viewport width
122
+ * @param {number} [options.height=720] - Viewport height
123
+ * @param {number} [options.wait_ms=1000] - Wait time after load
124
+ * @returns {Promise<{path: string, width: number, height: number, size_bytes: number}>}
125
+ */
126
+ const capture_element = async (url, selector, options = {}) => {
127
+ if (!browser) {
128
+ throw new Error('Browser not launched. Call launch_browser() first.');
129
+ }
130
+
131
+ const {
132
+ output_path,
133
+ width = 1280,
134
+ height = 720,
135
+ wait_ms = 1000
136
+ } = options;
137
+
138
+ const page = await browser.newPage();
139
+
140
+ try {
141
+ await page.setViewport({ width, height });
142
+ await page.goto(url, { waitUntil: 'networkidle0', timeout: 30000 });
143
+ await page.waitForSelector(selector, { timeout: 10000 });
144
+
145
+ if (wait_ms > 0) {
146
+ await new Promise(r => setTimeout(r, wait_ms));
147
+ }
148
+
149
+ if (output_path) {
150
+ fs.mkdirSync(path.dirname(output_path), { recursive: true });
151
+ }
152
+
153
+ const element = await page.$(selector);
154
+ if (!element) {
155
+ throw new Error(`Element not found: ${selector}`);
156
+ }
157
+
158
+ const screenshot_path = output_path || path.join(process.cwd(), 'element_screenshot.png');
159
+ await element.screenshot({ path: screenshot_path });
160
+
161
+ const stats = fs.statSync(screenshot_path);
162
+ const box = await element.boundingBox();
163
+
164
+ return {
165
+ path: screenshot_path,
166
+ width: Math.round(box.width),
167
+ height: Math.round(box.height),
168
+ size_bytes: stats.size
169
+ };
170
+ } finally {
171
+ await page.close();
172
+ }
173
+ };
174
+
175
+ /**
176
+ * Capture multiple screenshots from a single URL — full page + individual sections.
177
+ * @param {string} url - URL to screenshot
178
+ * @param {string} output_dir - Directory to save screenshots
179
+ * @param {Object} [options]
180
+ * @param {string[]} [options.section_selectors] - CSS selectors for individual section captures
181
+ * @param {string[]} [options.section_names] - Names for screenshot files (parallel to selectors)
182
+ * @param {number} [options.width=1280]
183
+ * @param {number} [options.height=720]
184
+ * @param {number} [options.wait_ms=1000]
185
+ * @returns {Promise<Array<{name: string, path: string, width: number, height: number, size_bytes: number}>>}
186
+ */
187
+ const capture_url_screenshots = async (url, output_dir, options = {}) => {
188
+ const {
189
+ section_selectors = [],
190
+ section_names = [],
191
+ width = 1280,
192
+ height = 720,
193
+ wait_ms = 1000
194
+ } = options;
195
+
196
+ fs.mkdirSync(output_dir, { recursive: true });
197
+
198
+ const results = [];
199
+
200
+ // Full page capture
201
+ const full_result = await capture_page(url, {
202
+ output_path: path.join(output_dir, 'full_page.png'),
203
+ full_page: true,
204
+ width,
205
+ height,
206
+ wait_ms
207
+ });
208
+ results.push({ name: 'full_page', ...full_result });
209
+
210
+ // Section captures
211
+ for (let i = 0; i < section_selectors.length; i++) {
212
+ const selector = section_selectors[i];
213
+ const name = section_names[i] || `section_${i + 1}`;
214
+
215
+ try {
216
+ const section_result = await capture_element(url, selector, {
217
+ output_path: path.join(output_dir, `${name}.png`),
218
+ width,
219
+ height,
220
+ wait_ms: 500
221
+ });
222
+ results.push({ name, ...section_result });
223
+ } catch (err) {
224
+ console.warn(` ⚠ Failed to capture "${name}" (${selector}): ${err.message}`);
225
+ results.push({ name, error: err.message });
226
+ }
227
+ }
228
+
229
+ return results;
230
+ };
231
+
232
+ /**
233
+ * Close the Puppeteer browser.
234
+ */
235
+ const close_browser = async () => {
236
+ if (browser) {
237
+ await browser.close();
238
+ browser = null;
239
+ }
240
+ };
241
+
242
+ module.exports = {
243
+ launch_browser,
244
+ capture_page,
245
+ capture_element,
246
+ capture_url_screenshots,
247
+ close_browser
248
+ };
package/module.js CHANGED
@@ -16,10 +16,17 @@ jsgui.controls.Active_HTML_Document = require('./controls/Active_HTML_Document')
16
16
 
17
17
  //const Resource_Publisher = require('./publishing/http-resource-publisher');
18
18
  //jsgui.Resource_Publisher = Resource_Publisher;
19
- const Server = require('./server');
20
- jsgui.Server = Server;
21
- jsgui.serve = Server.serve;
22
- jsgui.fs2 = require('./fs2');
19
+ const Server = require('./server');
20
+ jsgui.Server = Server;
21
+ jsgui.serve = Server.serve;
22
+ jsgui.Process_Resource = Server.Process_Resource;
23
+ jsgui.Remote_Process_Resource = Server.Remote_Process_Resource;
24
+ jsgui.HTTP_SSE_Publisher = Server.HTTP_SSE_Publisher;
25
+ if (jsgui.Resource) {
26
+ jsgui.Resource.Process = Server.Process_Resource;
27
+ jsgui.Resource.Remote_Process = Server.Remote_Process_Resource;
28
+ }
29
+ jsgui.fs2 = require('./fs2');
23
30
 
24
31
  // Port utilities for auto-port selection
25
32
  const port_utils = require('./port-utils');
package/package.json CHANGED
@@ -10,8 +10,8 @@
10
10
  "esbuild": "^0.27.1",
11
11
  "fnl": "^0.0.37",
12
12
  "fnlfs": "^0.0.34",
13
- "jsgui3-client": "^0.0.128",
14
- "jsgui3-html": "^0.0.179",
13
+ "jsgui3-client": "^0.0.129",
14
+ "jsgui3-html": "^0.0.180",
15
15
  "jsgui3-webpage": "^0.0.8",
16
16
  "jsgui3-website": "^0.0.8",
17
17
  "lang-tools": "^0.0.44",
@@ -43,7 +43,7 @@
43
43
  "type": "git",
44
44
  "url": "https://github.com/metabench/jsgui3-server.git"
45
45
  },
46
- "version": "0.0.147",
46
+ "version": "0.0.149",
47
47
  "scripts": {
48
48
  "cli": "node cli.js",
49
49
  "serve": "node cli.js serve",
@@ -53,13 +53,23 @@
53
53
  "test:assigners": "node tests/test-runner.js --test=assigners.test.js",
54
54
  "test:publishers": "node tests/test-runner.js --test=publishers.test.js",
55
55
  "test:config": "node tests/test-runner.js --test=configuration-validation.test.js",
56
+ "test:admin-ui": "node tests/test-runner.js --test=admin-ui-render.test.js",
57
+ "test:serve": "node tests/test-runner.js --test=serve.test.js",
58
+ "test:serve:resources": "node tests/test-runner.js --test=serve-resources.test.js",
59
+ "test:resources:process": "node tests/test-runner.js --test=process-resource.test.js",
60
+ "test:resources:remote": "node tests/test-runner.js --test=remote-process-resource.test.js",
61
+ "test:resources:pool": "node tests/test-runner.js --test=server-resource-pool.test.js",
62
+ "test:sse": "node tests/test-runner.js --test=http-sse-publisher.test.js",
56
63
  "test:e2e": "node tests/test-runner.js --test=end-to-end.test.js",
57
64
  "test:content": "node tests/test-runner.js --test=content-analysis.test.js",
65
+ "test:bundler:cache": "node tests/test-runner.js --test=control-optimizer-cache-behavior.test.js",
58
66
  "test:performance": "node tests/test-runner.js --test=performance.test.js",
59
67
  "test:errors": "node tests/test-runner.js --test=error-handling.test.js",
60
68
  "test:examples:controls": "node tests/test-runner.js --test=examples-controls.e2e.test.js",
69
+ "test:puppeteer:bundling": "node tests/test-runner.js --test=bundling-default-control-elimination.puppeteer.test.js",
61
70
  "test:puppeteer:windows": "node tests/test-runner.js --test=window-examples.puppeteer.test.js",
71
+ "test:puppeteer:resources": "node tests/test-runner.js --test=window-resource-integration.puppeteer.test.js",
62
72
  "test:debug": "node tests/test-runner.js --debug",
63
73
  "test:verbose": "node tests/test-runner.js --verbose"
64
74
  }
65
- }
75
+ }
@@ -7,10 +7,11 @@ const Publishers = {
7
7
  'html': require('./http-html-publisher'),
8
8
  'jpeg': require('./http-jpeg-publisher'),
9
9
  'js': require('./http-js-publisher'),
10
- 'observable': require('./http-observable-publisher'),
11
- 'png': require('./http-png-publisher'),
10
+ 'observable': require('./http-observable-publisher'),
11
+ 'sse': require('./http-sse-publisher'),
12
+ 'png': require('./http-png-publisher'),
12
13
  'resource': require('./http-resource-publisher'),
13
14
  'svg': require('./http-svg-publisher')
14
15
  }
15
16
 
16
- module.exports = Publishers;
17
+ module.exports = Publishers;
@@ -65,11 +65,11 @@ class Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner
65
65
 
66
66
  async assign(arr_bundled_items) {
67
67
  // Get compression configuration with defaults
68
- const enabled = this.compression_config.enabled !== false; // Default: true
69
- const algorithms = this.compression_config.algorithms || ['gzip', 'br'];
70
- const gzipLevel = this.compression_config.gzip?.level || 6;
71
- const brotliQuality = this.compression_config.brotli?.quality || 6;
72
- const threshold = this.compression_config.threshold || 1024;
68
+ const enabled = this.compression_config.enabled !== false; // Default: true
69
+ const algorithms = this.compression_config.algorithms || ['gzip', 'br'];
70
+ const gzipLevel = this.compression_config.gzip?.level ?? 6;
71
+ const brotliQuality = this.compression_config.brotli?.quality ?? 6;
72
+ const threshold = this.compression_config.threshold ?? 1024;
73
73
 
74
74
  if (!enabled) {
75
75
  console.log('Compression disabled, skipping compression assignment');
@@ -27,6 +27,9 @@ class Observable_Publisher extends HTTP_Publisher {
27
27
  this.type = 'observable';
28
28
  this.obs = obs;
29
29
 
30
+ // Expose schema if provided (either in spec or on the observable itself)
31
+ this.schema = spec.schema || obs.schema || null;
32
+
30
33
  this.keep_alive_interval_ms = (spec && spec.keep_alive_interval_ms !== undefined)
31
34
  ? spec.keep_alive_interval_ms
32
35
  : default_keep_alive_interval_ms;
@@ -301,6 +304,11 @@ class Observable_Publisher extends HTTP_Publisher {
301
304
  this._write_sse(res, `event: paused\ndata: ${this._stringify_sse_data({ status: 'paused' })}\n\n`);
302
305
  }
303
306
 
307
+ // Send schema if available
308
+ if (this.schema) {
309
+ this._write_sse(res, `event: schema\ndata: ${this._stringify_sse_data(this.schema)}\n\n`);
310
+ }
311
+
304
312
  let removed = false;
305
313
  const remove_connection = () => {
306
314
  if (removed) return;