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.
- package/.github/workflows/control-scan-manifest-check.yml +31 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-071799b982906680f5fd699d.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-07352945ad5c92654fcb8b65.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-138a601fadb6191ea314c6fd.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-171f6c381c2cadf2e9fa7087.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-1d973388156b84a04373fac9.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-20e117bc8a10d2cd16234bbe.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-2b028a82b0e5efddba42425f.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-4518556cd5c7e059e82b22b8.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5bac1aa0f213902f718ed74f.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-5f9996ac7822caf777d92f56.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-60a92c702e65fd9cf748e3ec.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6164c1f8f738995c541895d2.js +44 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-6718a85eb9e5aa782dd47a05.js +45 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-69e280f14e37aee76a1d4675.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7570d1b030d44b111ed59c4c.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7798c9bbd55e510d5039f936.js +42 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-78cd511ea1ef18ecb03d1be5.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-7d482e0b95bcb5e3c543118b.js +43 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-80e9476d1127c55b40fdb36f.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-810ced55d5320a3088a05b13.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-8423565f1a40e329afc8c6cf.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-900bef783b8cee36506ec282.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-a1a37aff6416fdad74040ddf.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-ad48d5e8eda40f175b4df090.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-aec5a2d963015528c9099462.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-af9d34e0f1722fab9e28c269.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-b818e4015e2f1fe86280b5ab.js +41 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bcb2541adc70b7aba61768c5.js +44 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-bfe89d2c78ed44f95ed7dd73.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c06f04806a1e688e1187110c.js +40 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-c3f3adf904f585afc544b96a.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-d45acb873e1d8e32d5e60f2e.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-db06f132533706f4a0163b8c.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f660f40d78b135fc8560a862.js +39 -0
- package/.jsgui3-server-cache/jsgui3-html-shims/jsgui3-html-controls-shim-f9dee4ec18a96e09bee06bae.js +39 -0
- package/README.md +85 -3
- package/admin-ui/client.js +213 -0
- package/admin-ui/server.js +104 -0
- package/client/controls/auto-observable.js +207 -0
- package/dev-status.svg +139 -0
- package/docs/api-reference.md +301 -43
- package/docs/books/admin-ui/01-introduction.md +32 -0
- package/docs/books/admin-ui/02-architecture.md +92 -0
- package/docs/books/admin-ui/03-controls.md +194 -0
- package/docs/books/admin-ui/04-implementation-plan.md +62 -0
- package/docs/books/admin-ui/README.md +26 -0
- package/docs/books/jsgui3-bundling-research-book/00-table-of-contents.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/01-pipeline-and-runtime-semantics.md +34 -0
- package/docs/books/jsgui3-bundling-research-book/02-javascript-bundling-core.md +36 -0
- package/docs/books/jsgui3-bundling-research-book/03-style-extraction-and-css-compilation.md +35 -0
- package/docs/books/jsgui3-bundling-research-book/04-static-publishing-and-delivery.md +39 -0
- package/docs/books/jsgui3-bundling-research-book/05-current-limits-and-size-bloat-vectors.md +25 -0
- package/docs/books/jsgui3-bundling-research-book/06-unused-module-elimination-strategy.md +77 -0
- package/docs/books/jsgui3-bundling-research-book/07-jsgui3-html-control-and-mixin-pruning.md +63 -0
- package/docs/books/jsgui3-bundling-research-book/08-test-and-verification-methodology.md +43 -0
- package/docs/books/jsgui3-bundling-research-book/09-roadmap-and-rollout.md +42 -0
- package/docs/books/jsgui3-bundling-research-book/10-further-research-strategies-and-upgrades.md +211 -0
- package/docs/books/jsgui3-bundling-research-book/README.md +35 -0
- package/docs/bundling-system-deep-dive.md +9 -4
- package/docs/comprehensive-documentation.md +49 -18
- package/docs/configuration-reference.md +152 -27
- package/docs/core/README.md +19 -0
- package/docs/core/jsgui3-server-core-book/00-table-of-contents.md +21 -0
- package/docs/core/jsgui3-server-core-book/01-startup-readiness-state-machine.md +41 -0
- package/docs/core/jsgui3-server-core-book/02-resource-abstraction-and-lifecycle.md +92 -0
- package/docs/core/jsgui3-server-core-book/03-resource-pool-and-event-topology.md +47 -0
- package/docs/core/jsgui3-server-core-book/04-sse-publisher-semantics.md +41 -0
- package/docs/core/jsgui3-server-core-book/05-serve-factory-resource-wiring.md +46 -0
- package/docs/core/jsgui3-server-core-book/06-e2e-testing-methodology.md +48 -0
- package/docs/core/jsgui3-server-core-book/07-defect-detection-and-hardening-loop.md +47 -0
- package/docs/publishers-guide.md +59 -4
- package/docs/resources-guide.md +184 -35
- package/docs/simple-server-api-design.md +72 -17
- package/docs/system-architecture.md +18 -14
- package/examples/controls/15) window, observable SSE/server.js +6 -1
- package/examples/controls/19) window, auto observable ui/client.js +125 -0
- package/examples/controls/19) window, auto observable ui/server.js +73 -0
- package/examples/controls/20) window, task manager app/README.md +133 -0
- package/examples/controls/20) window, task manager app/client.js +797 -0
- package/examples/controls/20) window, task manager app/server.js +178 -0
- package/examples/controls/6) window, color_palette/client.js +165 -68
- package/examples/controls/9) window, date picker/client.js +362 -76
- package/examples/controls/9b) window, shared data.model mirrored date pickers/client.js +104 -83
- package/examples/jsgui3-html/06) theming/client.js +22 -1
- package/examples/jsgui3-html/10) binding-debugger/client.js +137 -1
- package/http/responders/static/Static_Route_HTTP_Responder.js +52 -34
- package/lab/experiments/capture-color-controls.js +196 -0
- package/lab/results/screenshots/color-controls/full_page.png +0 -0
- package/lab/results/screenshots/color-controls/section_1_color_grid_12x12.png +0 -0
- package/lab/results/screenshots/color-controls/section_2_color_grid_4x2.png +0 -0
- package/lab/results/screenshots/color-controls/section_3_color_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_4_palette_comparison.png +0 -0
- package/lab/results/screenshots/color-controls/section_5_raw_swatches.png +0 -0
- package/lab/results/screenshots/color-controls/section_6_optimized_crayola.png +0 -0
- package/lab/results/screenshots/color-controls/section_7_pastel_palette.png +0 -0
- package/lab/results/screenshots/color-controls/section_8_extended_144.png +0 -0
- package/lab/screenshot-utils.js +248 -0
- package/module.js +11 -4
- package/package.json +14 -4
- package/publishers/Publishers.js +4 -3
- package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +5 -5
- package/publishers/http-observable-publisher.js +8 -0
- package/publishers/http-sse-publisher.js +341 -0
- package/publishers/http-webpage-publisher.js +13 -3
- package/publishers/http-webpageorsite-publisher.js +18 -0
- package/resources/process-resource.js +950 -0
- package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +164 -46
- package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +18 -7
- package/resources/processors/bundlers/js/esbuild/JSGUI3_HTML_Control_Optimizer.js +829 -0
- package/resources/remote-process-resource.js +355 -0
- package/resources/server-resource-pool.js +354 -41
- package/serve-factory.js +441 -259
- package/server.js +161 -16
- package/tests/README.md +66 -4
- package/tests/admin-ui-render.test.js +24 -0
- package/tests/assigners.test.js +56 -40
- package/tests/bundling-default-control-elimination.puppeteer.test.js +260 -0
- package/tests/configuration-validation.test.js +21 -18
- package/tests/content-analysis.test.js +7 -6
- package/tests/control-optimizer-cache-behavior.test.js +52 -0
- package/tests/control-scan-manifest-regression.test.js +144 -0
- package/tests/end-to-end.test.js +15 -14
- package/tests/error-handling.test.js +222 -179
- package/tests/fixtures/bundling-default-button-client.js +37 -0
- package/tests/fixtures/bundling-default-window-client.js +34 -0
- package/tests/fixtures/control_scan_manifest_expectations.json +48 -0
- package/tests/fixtures/resource-monitor-client.js +319 -0
- package/tests/helpers/puppeteer-e2e-harness.js +317 -0
- package/tests/http-sse-publisher.test.js +136 -0
- package/tests/performance.test.js +69 -65
- package/tests/process-resource.test.js +138 -0
- package/tests/publishers.test.js +7 -7
- package/tests/remote-process-resource.test.js +160 -0
- package/tests/sass-controls.e2e.test.js +7 -1
- package/tests/serve-resources.test.js +270 -0
- package/tests/serve.test.js +120 -50
- package/tests/server-resource-pool.test.js +106 -0
- package/tests/small-controls-bundle-size.test.js +252 -0
- package/tests/test-runner.js +13 -1
- package/tests/window-examples.puppeteer.test.js +204 -1
- package/tests/window-resource-integration.puppeteer.test.js +585 -0
- package/tests/temp_invalid.js +0 -7
- package/tests/temp_invalid_utf8.js +0 -1
- package/tests/temp_malformed.js +0 -10
|
@@ -1,8 +1,144 @@
|
|
|
1
1
|
const jsgui = require('jsgui3-client');
|
|
2
2
|
const Active_HTML_Document = require('../../../controls/Active_HTML_Document');
|
|
3
|
-
const
|
|
3
|
+
const jsgui3_html = require('jsgui3-html');
|
|
4
4
|
const { Data_Object } = jsgui;
|
|
5
5
|
|
|
6
|
+
const snapshot_model_values = (model) => {
|
|
7
|
+
if (!model || typeof model !== 'object') return {};
|
|
8
|
+
const raw_model = model._ && typeof model._ === 'object' ? model._ : model;
|
|
9
|
+
const result = {};
|
|
10
|
+
Object.keys(raw_model).forEach((key) => {
|
|
11
|
+
if (key.startsWith('_')) return;
|
|
12
|
+
const value = raw_model[key];
|
|
13
|
+
if (typeof value === 'function') return;
|
|
14
|
+
result[key] = value;
|
|
15
|
+
});
|
|
16
|
+
return result;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
class Fallback_Binding_Debugger {
|
|
20
|
+
constructor(control) {
|
|
21
|
+
this.control = control;
|
|
22
|
+
this.logs = [];
|
|
23
|
+
this.enabled = false;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
enable() {
|
|
27
|
+
this.enabled = true;
|
|
28
|
+
this.log('Debugging enabled');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
disable() {
|
|
32
|
+
this.enabled = false;
|
|
33
|
+
this.log('Debugging disabled');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
log(message) {
|
|
37
|
+
const entry = {
|
|
38
|
+
timestamp: new Date().toISOString(),
|
|
39
|
+
message
|
|
40
|
+
};
|
|
41
|
+
this.logs.push(entry);
|
|
42
|
+
if (this.logs.length > 100) {
|
|
43
|
+
this.logs.shift();
|
|
44
|
+
}
|
|
45
|
+
if (this.enabled) {
|
|
46
|
+
console.log(`[BindingDebugger:fallback] ${message}`);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
getBindingSummary() {
|
|
51
|
+
const binding_manager = this.control && this.control._binding_manager;
|
|
52
|
+
if (!binding_manager || typeof binding_manager.inspect !== 'function') {
|
|
53
|
+
return {
|
|
54
|
+
totalBinders: 0,
|
|
55
|
+
totalComputed: 0,
|
|
56
|
+
totalWatchers: 0,
|
|
57
|
+
details: {
|
|
58
|
+
binders: [],
|
|
59
|
+
computed: [],
|
|
60
|
+
watchers: []
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const details = binding_manager.inspect();
|
|
66
|
+
const binders = Array.isArray(details.binders) ? details.binders : [];
|
|
67
|
+
const computed = Array.isArray(details.computed) ? details.computed : [];
|
|
68
|
+
const watchers = Array.isArray(details.watchers) ? details.watchers : [];
|
|
69
|
+
|
|
70
|
+
return {
|
|
71
|
+
totalBinders: binders.length,
|
|
72
|
+
totalComputed: computed.length,
|
|
73
|
+
totalWatchers: watchers.length,
|
|
74
|
+
details
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
snapshotModels() {
|
|
79
|
+
const control = this.control || {};
|
|
80
|
+
return {
|
|
81
|
+
timestamp: new Date().toISOString(),
|
|
82
|
+
dataModel: snapshot_model_values(control.data && control.data.model),
|
|
83
|
+
viewDataModel: snapshot_model_values(control.view && control.view.data && control.view.data.model),
|
|
84
|
+
viewModel: snapshot_model_values(control.view && control.view.model)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
compareSnapshots(snapshot_a = {}, snapshot_b = {}) {
|
|
89
|
+
const differences = [];
|
|
90
|
+
const compare_group = (group_name) => {
|
|
91
|
+
const before_group = snapshot_a[group_name] || {};
|
|
92
|
+
const after_group = snapshot_b[group_name] || {};
|
|
93
|
+
const key_set = new Set([...Object.keys(before_group), ...Object.keys(after_group)]);
|
|
94
|
+
key_set.forEach((key) => {
|
|
95
|
+
if (before_group[key] === after_group[key]) return;
|
|
96
|
+
differences.push({
|
|
97
|
+
path: `${group_name}.${key}`,
|
|
98
|
+
oldValue: before_group[key],
|
|
99
|
+
newValue: after_group[key]
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
compare_group('dataModel');
|
|
105
|
+
compare_group('viewDataModel');
|
|
106
|
+
compare_group('viewModel');
|
|
107
|
+
return differences;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const create_fallback_binding_debug_tools = () => {
|
|
112
|
+
const debugger_by_control = new WeakMap();
|
|
113
|
+
const get_debugger = (control) => {
|
|
114
|
+
if (!debugger_by_control.has(control)) {
|
|
115
|
+
debugger_by_control.set(control, new Fallback_Binding_Debugger(control));
|
|
116
|
+
}
|
|
117
|
+
return debugger_by_control.get(control);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
return {
|
|
121
|
+
getDebugger: get_debugger,
|
|
122
|
+
enableFor(control) {
|
|
123
|
+
const debugger_instance = get_debugger(control);
|
|
124
|
+
debugger_instance.enable();
|
|
125
|
+
return debugger_instance;
|
|
126
|
+
},
|
|
127
|
+
disableFor(control) {
|
|
128
|
+
const debugger_instance = get_debugger(control);
|
|
129
|
+
debugger_instance.disable();
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const BindingDebugTools = (
|
|
135
|
+
jsgui3_html
|
|
136
|
+
&& jsgui3_html.BindingDebugTools
|
|
137
|
+
&& typeof jsgui3_html.BindingDebugTools.getDebugger === 'function'
|
|
138
|
+
)
|
|
139
|
+
? jsgui3_html.BindingDebugTools
|
|
140
|
+
: create_fallback_binding_debug_tools();
|
|
141
|
+
|
|
6
142
|
class Binding_Debugger_Control extends jsgui.Control {
|
|
7
143
|
constructor(spec = {}) {
|
|
8
144
|
spec.__type_name = spec.__type_name || 'binding_debugger_control';
|
|
@@ -14,7 +14,7 @@ const HTTP_Responder = require('../HTTP_Responder');
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
class Static_Route_HTTP_Responder extends HTTP_Responder {
|
|
17
|
+
class Static_Route_HTTP_Responder extends HTTP_Responder {
|
|
18
18
|
constructor(spec) {
|
|
19
19
|
super(spec);
|
|
20
20
|
|
|
@@ -37,7 +37,7 @@ class Static_Route_HTTP_Responder extends HTTP_Responder {
|
|
|
37
37
|
// Need to call it with the correct context.
|
|
38
38
|
// Seems like jsgui3-html Router and Routing_Tree need some more fixes.
|
|
39
39
|
|
|
40
|
-
const {type, extension, text, route, response_buffers, response_headers} = this;
|
|
40
|
+
const {type, extension, text, route, response_buffers, response_headers} = this;
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
//console.log('accept_encoding', accept_encoding);
|
|
@@ -55,50 +55,68 @@ class Static_Route_HTTP_Responder extends HTTP_Responder {
|
|
|
55
55
|
|
|
56
56
|
if (typeof accept_encoding === 'string' && accept_encoding.includes('br')) supported_encodings.br = true;
|
|
57
57
|
|
|
58
|
-
const
|
|
59
|
-
const
|
|
58
|
+
const safe_response_buffers = response_buffers || {};
|
|
59
|
+
const safe_response_headers = response_headers || {};
|
|
60
|
+
|
|
61
|
+
const identity_buffer = safe_response_buffers.identity || Buffer.from(text || '', 'utf8');
|
|
62
|
+
const has_br = safe_response_buffers.br;
|
|
63
|
+
const has_gzip = safe_response_buffers.gzip;
|
|
60
64
|
const use_br = supported_encodings.br === true && has_br;
|
|
61
65
|
const use_gzip = supported_encodings.gzip === true && has_gzip;
|
|
66
|
+
|
|
67
|
+
let selected_encoding = 'identity';
|
|
68
|
+
let selected_buffer = identity_buffer;
|
|
69
|
+
if (use_br) {
|
|
70
|
+
selected_encoding = 'br';
|
|
71
|
+
selected_buffer = safe_response_buffers.br;
|
|
72
|
+
} else if (use_gzip) {
|
|
73
|
+
selected_encoding = 'gzip';
|
|
74
|
+
selected_buffer = safe_response_buffers.gzip;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (!Buffer.isBuffer(selected_buffer)) {
|
|
78
|
+
selected_buffer = Buffer.from(String(selected_buffer || ''), 'utf8');
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const selected_headers = safe_response_headers[selected_encoding] || safe_response_headers.identity || {};
|
|
62
82
|
|
|
63
83
|
//console.log('supported_encodings', supported_encodings);
|
|
64
84
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
res.
|
|
85
|
+
const has_header = (header_name) => {
|
|
86
|
+
if (typeof res.hasHeader === 'function') {
|
|
87
|
+
return res.hasHeader(header_name);
|
|
88
|
+
}
|
|
89
|
+
if (typeof res.getHeader === 'function') {
|
|
90
|
+
return typeof res.getHeader(header_name) !== 'undefined';
|
|
71
91
|
}
|
|
92
|
+
return false;
|
|
93
|
+
};
|
|
72
94
|
|
|
73
|
-
|
|
74
|
-
|
|
95
|
+
if (typeof res.setHeader === 'function') {
|
|
96
|
+
for (const key in selected_headers) {
|
|
97
|
+
const value = selected_headers[key];
|
|
98
|
+
res.setHeader(key, value);
|
|
99
|
+
}
|
|
75
100
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
res.setHeader(
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
res.setHeader(key, value);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
101
|
+
if (!has_header('Content-Type')) {
|
|
102
|
+
if (extension === 'css') res.setHeader('Content-Type', 'text/css; charset=utf-8');
|
|
103
|
+
if (extension === 'js') res.setHeader('Content-Type', 'application/javascript; charset=utf-8');
|
|
104
|
+
if (extension === 'html') res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
|
105
|
+
}
|
|
106
|
+
if (!has_header('Content-Length')) {
|
|
107
|
+
res.setHeader('Content-Length', selected_buffer.length);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
88
110
|
|
|
89
111
|
// Then write the (hopefully compressed) response bodies...
|
|
90
112
|
|
|
91
|
-
if (
|
|
113
|
+
if (typeof res.write === 'function') {
|
|
114
|
+
res.write(selected_buffer);
|
|
115
|
+
}
|
|
92
116
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
res.write(response_buffers.gzip);
|
|
97
|
-
} else {
|
|
98
|
-
res.write(response_buffers.identity);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
res.end();
|
|
117
|
+
if (typeof res.end === 'function') {
|
|
118
|
+
res.end();
|
|
119
|
+
}
|
|
102
120
|
|
|
103
121
|
//console.trace();
|
|
104
122
|
//throw 'NYI';
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture Color Controls Screenshots
|
|
3
|
+
*
|
|
4
|
+
* Starts the jsgui3-html color controls demo server and uses Puppeteer
|
|
5
|
+
* to capture screenshots of each section for visual verification.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* node lab/experiments/capture-color-controls.js
|
|
9
|
+
*
|
|
10
|
+
* Prerequisites:
|
|
11
|
+
* npm install (puppeteer is a devDependency)
|
|
12
|
+
* jsgui3-html repo must be at ../jsgui3-html (relative to jsgui3-server)
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
const { spawn } = require('child_process');
|
|
16
|
+
const path = require('path');
|
|
17
|
+
const fs = require('fs');
|
|
18
|
+
const { launch_browser, capture_url_screenshots, close_browser } = require('../screenshot-utils');
|
|
19
|
+
|
|
20
|
+
const JSGUI3_HTML_PATH = path.resolve(__dirname, '..', '..', '..', 'jsgui3-html');
|
|
21
|
+
const DEMO_SERVER_SCRIPT = path.join(JSGUI3_HTML_PATH, 'lab', 'color_controls_demo_server.js');
|
|
22
|
+
const DEMO_URL = 'http://localhost:3600';
|
|
23
|
+
const OUTPUT_DIR = path.join(__dirname, '..', 'results', 'screenshots', 'color-controls');
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Start the color controls demo server as a child process.
|
|
27
|
+
*/
|
|
28
|
+
const start_demo_server = () => {
|
|
29
|
+
return new Promise((resolve, reject) => {
|
|
30
|
+
console.log(`Starting demo server: ${DEMO_SERVER_SCRIPT}`);
|
|
31
|
+
|
|
32
|
+
if (!fs.existsSync(DEMO_SERVER_SCRIPT)) {
|
|
33
|
+
reject(new Error(`Demo server script not found: ${DEMO_SERVER_SCRIPT}`));
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const child = spawn('node', [DEMO_SERVER_SCRIPT], {
|
|
38
|
+
cwd: JSGUI3_HTML_PATH,
|
|
39
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
40
|
+
env: { ...process.env, HOME: process.env.USERPROFILE || process.env.HOME }
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
let started = false;
|
|
44
|
+
const timeout = setTimeout(() => {
|
|
45
|
+
if (!started) {
|
|
46
|
+
reject(new Error('Demo server startup timeout (15s)'));
|
|
47
|
+
}
|
|
48
|
+
}, 15000);
|
|
49
|
+
|
|
50
|
+
child.stdout.on('data', (data) => {
|
|
51
|
+
const text = data.toString();
|
|
52
|
+
process.stdout.write(` [demo-server] ${text}`);
|
|
53
|
+
if (text.includes('running at') && !started) {
|
|
54
|
+
started = true;
|
|
55
|
+
clearTimeout(timeout);
|
|
56
|
+
// Give it a moment to settle
|
|
57
|
+
setTimeout(() => resolve(child), 500);
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
child.stderr.on('data', (data) => {
|
|
62
|
+
process.stderr.write(` [demo-server-err] ${data.toString()}`);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
child.on('error', (err) => {
|
|
66
|
+
clearTimeout(timeout);
|
|
67
|
+
reject(err);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
child.on('exit', (code) => {
|
|
71
|
+
if (!started) {
|
|
72
|
+
clearTimeout(timeout);
|
|
73
|
+
reject(new Error(`Demo server exited with code ${code} before starting`));
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Stop the demo server child process.
|
|
81
|
+
*/
|
|
82
|
+
const stop_demo_server = (child) => {
|
|
83
|
+
return new Promise((resolve) => {
|
|
84
|
+
if (!child || child.killed) {
|
|
85
|
+
resolve();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
child.on('exit', () => resolve());
|
|
90
|
+
child.kill('SIGTERM');
|
|
91
|
+
|
|
92
|
+
// Force kill after 3s
|
|
93
|
+
setTimeout(() => {
|
|
94
|
+
if (!child.killed) {
|
|
95
|
+
child.kill('SIGKILL');
|
|
96
|
+
}
|
|
97
|
+
resolve();
|
|
98
|
+
}, 3000);
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const format_bytes = (bytes) => {
|
|
103
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
104
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
105
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
// ============================================
|
|
109
|
+
// Main
|
|
110
|
+
// ============================================
|
|
111
|
+
const main = async () => {
|
|
112
|
+
console.log('╔══════════════════════════════════════════════╗');
|
|
113
|
+
console.log('║ Color Controls Screenshot Capture ║');
|
|
114
|
+
console.log('╚══════════════════════════════════════════════╝\n');
|
|
115
|
+
|
|
116
|
+
let demo_server;
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
// 1. Start demo server
|
|
120
|
+
demo_server = await start_demo_server();
|
|
121
|
+
console.log(`✓ Demo server started (PID: ${demo_server.pid})\n`);
|
|
122
|
+
|
|
123
|
+
// 2. Launch Puppeteer browser
|
|
124
|
+
console.log('Launching Puppeteer browser...');
|
|
125
|
+
await launch_browser();
|
|
126
|
+
console.log('✓ Browser launched\n');
|
|
127
|
+
|
|
128
|
+
// 3. Capture screenshots
|
|
129
|
+
console.log(`Capturing screenshots to: ${OUTPUT_DIR}\n`);
|
|
130
|
+
|
|
131
|
+
const results = await capture_url_screenshots(DEMO_URL, OUTPUT_DIR, {
|
|
132
|
+
width: 1280,
|
|
133
|
+
height: 900,
|
|
134
|
+
wait_ms: 2000,
|
|
135
|
+
section_selectors: [
|
|
136
|
+
'.demo-section:nth-child(2)', // Section 1: Color_Grid 12x12
|
|
137
|
+
'.demo-section:nth-child(3)', // Section 2: Color_Grid 4x2
|
|
138
|
+
'.demo-section:nth-child(4)', // Section 3: Color_Palette
|
|
139
|
+
'.demo-section:nth-child(5)', // Section 4: Palette Comparison
|
|
140
|
+
'.demo-section:nth-child(6)', // Section 5: Raw HTML Swatches
|
|
141
|
+
'.demo-section:nth-child(7)', // Section 6: Optimized Crayola
|
|
142
|
+
'.demo-section:nth-child(8)', // Section 7: Pastel Palette
|
|
143
|
+
'.demo-section:nth-child(9)' // Section 8: Extended 144
|
|
144
|
+
],
|
|
145
|
+
section_names: [
|
|
146
|
+
'section_1_color_grid_12x12',
|
|
147
|
+
'section_2_color_grid_4x2',
|
|
148
|
+
'section_3_color_palette',
|
|
149
|
+
'section_4_palette_comparison',
|
|
150
|
+
'section_5_raw_swatches',
|
|
151
|
+
'section_6_optimized_crayola',
|
|
152
|
+
'section_7_pastel_palette',
|
|
153
|
+
'section_8_extended_144'
|
|
154
|
+
]
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// 4. Print summary
|
|
158
|
+
console.log('\n════════════════════════════════════════════════');
|
|
159
|
+
console.log(' Screenshot Capture Summary');
|
|
160
|
+
console.log('════════════════════════════════════════════════\n');
|
|
161
|
+
|
|
162
|
+
const table_data = results.map(r => ({
|
|
163
|
+
Name: r.name,
|
|
164
|
+
Dimensions: r.error ? 'FAILED' : `${r.width}×${r.height}`,
|
|
165
|
+
Size: r.error ? r.error : format_bytes(r.size_bytes),
|
|
166
|
+
Path: r.error ? '' : path.basename(r.path)
|
|
167
|
+
}));
|
|
168
|
+
|
|
169
|
+
console.table(table_data);
|
|
170
|
+
|
|
171
|
+
const success_count = results.filter(r => !r.error).length;
|
|
172
|
+
const fail_count = results.filter(r => r.error).length;
|
|
173
|
+
|
|
174
|
+
console.log(`\n✓ ${success_count} screenshots captured`);
|
|
175
|
+
if (fail_count > 0) {
|
|
176
|
+
console.log(`⚠ ${fail_count} captures failed`);
|
|
177
|
+
}
|
|
178
|
+
console.log(`\nOutput directory: ${OUTPUT_DIR}`);
|
|
179
|
+
|
|
180
|
+
} catch (err) {
|
|
181
|
+
console.error(`\n✗ Error: ${err.message}`);
|
|
182
|
+
if (err.stack) console.error(err.stack);
|
|
183
|
+
process.exitCode = 1;
|
|
184
|
+
} finally {
|
|
185
|
+
// Cleanup
|
|
186
|
+
console.log('\nCleaning up...');
|
|
187
|
+
await close_browser().catch(() => { });
|
|
188
|
+
if (demo_server) {
|
|
189
|
+
await stop_demo_server(demo_server);
|
|
190
|
+
console.log('✓ Demo server stopped');
|
|
191
|
+
}
|
|
192
|
+
console.log('Done.');
|
|
193
|
+
}
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
main();
|
|
Binary file
|