jsgui3-server 0.0.138 → 0.0.140

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 (57) hide show
  1. package/AGENTS.md +87 -0
  2. package/README.md +12 -0
  3. package/docs/GUIDE_TO_AGENTIC_WORKFLOWS_BY_GROK.md +19 -0
  4. package/docs/advanced-usage-examples.md +1360 -0
  5. package/docs/agent-development-guide.md +386 -0
  6. package/docs/api-reference.md +916 -0
  7. package/docs/broken-functionality-tracker.md +285 -0
  8. package/docs/bundling-system-deep-dive.md +525 -0
  9. package/docs/cli-reference.md +393 -0
  10. package/docs/comprehensive-documentation.md +1403 -0
  11. package/docs/configuration-reference.md +808 -0
  12. package/docs/controls-development.md +859 -0
  13. package/docs/documentation-review/CURRENT_REVIEW.md +95 -0
  14. package/docs/function-publishers-json-apis.md +847 -0
  15. package/docs/getting-started-with-json.md +518 -0
  16. package/docs/minification-compression-sourcemaps-status.md +482 -0
  17. package/docs/minification-compression-sourcemaps-test-results.md +205 -0
  18. package/docs/publishers-guide.md +313 -0
  19. package/docs/resources-guide.md +615 -0
  20. package/docs/serve-helpers.md +406 -0
  21. package/docs/simple-server-api-design.md +13 -0
  22. package/docs/system-architecture.md +275 -0
  23. package/docs/troubleshooting.md +698 -0
  24. package/examples/json/README.md +115 -0
  25. package/examples/json/basic-api/README.md +345 -0
  26. package/examples/json/basic-api/server.js +199 -0
  27. package/examples/json/simple-api/README.md +125 -0
  28. package/examples/json/simple-api/diagnostic-report.json +73 -0
  29. package/examples/json/simple-api/diagnostic-test.js +433 -0
  30. package/examples/json/simple-api/server-debug.md +58 -0
  31. package/examples/json/simple-api/server.js +91 -0
  32. package/examples/json/simple-api/test.js +215 -0
  33. package/http/responders/static/Static_Route_HTTP_Responder.js +1 -2
  34. package/package.json +19 -8
  35. package/publishers/helpers/assigners/static-compressed-response-buffers/Single_Control_Webpage_Server_Static_Compressed_Response_Buffers_Assigner.js +65 -12
  36. package/publishers/helpers/preparers/static/bundle/Static_Routes_Responses_Webpage_Bundle_Preparer.js +6 -1
  37. package/publishers/http-function-publisher.js +59 -38
  38. package/publishers/http-webpage-publisher.js +48 -1
  39. package/resources/processors/bundlers/js/esbuild/Advanced_JS_Bundler_Using_ESBuild.js +38 -146
  40. package/resources/processors/bundlers/js/esbuild/Core_JS_Non_Minifying_Bundler_Using_ESBuild.js +54 -5
  41. package/resources/processors/bundlers/js/esbuild/Core_JS_Single_File_Minifying_Bundler_Using_ESBuild.js +36 -4
  42. package/serve-factory.js +36 -9
  43. package/server.js +10 -4
  44. package/test-report.json +0 -0
  45. package/tests/README.md +250 -0
  46. package/tests/assigners.test.js +316 -0
  47. package/tests/bundlers.test.js +329 -0
  48. package/tests/configuration-validation.test.js +530 -0
  49. package/tests/content-analysis.test.js +641 -0
  50. package/tests/end-to-end.test.js +496 -0
  51. package/tests/error-handling.test.js +746 -0
  52. package/tests/performance.test.js +653 -0
  53. package/tests/publishers.test.js +395 -0
  54. package/tests/temp_invalid.js +7 -0
  55. package/tests/temp_invalid_utf8.js +1 -0
  56. package/tests/temp_malformed.js +10 -0
  57. package/tests/test-runner.js +261 -0
@@ -0,0 +1,496 @@
1
+ const assert = require('assert');
2
+ const { describe, it, before, after } = require('mocha');
3
+ const http = require('http');
4
+ const fs = require('fs').promises;
5
+ const path = require('path');
6
+
7
+ // Import server and related classes
8
+ const Server = require('../module');
9
+
10
+ describe('End-to-End Integration Tests', function() {
11
+ this.timeout(30000); // Allow more time for server startup and requests
12
+
13
+ let server;
14
+ let serverPort = 3001; // Use a different port for testing
15
+ let testControl;
16
+
17
+ before(async function() {
18
+ // Create a test control class
19
+ testControl = class TestControl {
20
+ constructor(spec) {
21
+ this.context = spec.context;
22
+ this.head = {
23
+ add: function(element) {
24
+ // Mock add method
25
+ }
26
+ };
27
+ this.body = {
28
+ add: function(element) {
29
+ // Mock add method
30
+ }
31
+ };
32
+ }
33
+
34
+ active() {
35
+ // Mock activation
36
+ }
37
+
38
+ all_html_render() {
39
+ return Promise.resolve(`<!DOCTYPE html>
40
+ <html>
41
+ <head>
42
+ <title>Test Page</title>
43
+ <script src="/js/js.js"></script>
44
+ </head>
45
+ <body>
46
+ <div id="test-control">
47
+ <h1>Test Control</h1>
48
+ <p>This is a test control with embedded CSS and JS.</p>
49
+ <button onclick="testFunction()">Test Button</button>
50
+ </div>
51
+ </body>
52
+ </html>`);
53
+ }
54
+ };
55
+
56
+ // Add CSS and JS to the control class
57
+ testControl.css = `
58
+ .test-control {
59
+ background-color: #f0f0f0;
60
+ padding: 20px;
61
+ border: 1px solid #ccc;
62
+ font-family: Arial, sans-serif;
63
+ }
64
+ .test-control h1 {
65
+ color: #333;
66
+ margin-bottom: 10px;
67
+ }
68
+ .test-control p {
69
+ color: #666;
70
+ line-height: 1.5;
71
+ }
72
+ `;
73
+
74
+ testControl.js = `
75
+ // Test JavaScript with CSS embedding
76
+ const css = \`${testControl.css}\`;
77
+
78
+ // Add CSS to document
79
+ const style = document.createElement('style');
80
+ style.textContent = css;
81
+ document.head.appendChild(style);
82
+
83
+ // Test function
84
+ function testFunction() {
85
+ console.log('Test function called');
86
+ alert('Test function executed successfully!');
87
+ return 'test result';
88
+ }
89
+
90
+ // Initialize when DOM is ready
91
+ document.addEventListener('DOMContentLoaded', function() {
92
+ console.log('Test control initialized');
93
+ const testDiv = document.getElementById('test-control');
94
+ if (testDiv) {
95
+ testDiv.style.borderColor = '#007bff';
96
+ }
97
+ });
98
+
99
+ // Export for testing
100
+ window.TestControl = { testFunction };
101
+ `;
102
+ });
103
+
104
+ after(async function() {
105
+ // Clean up server
106
+ if (server) {
107
+ await server.stop();
108
+ }
109
+ });
110
+
111
+ describe('Full Server Integration with Minification and Compression', function() {
112
+ it('should serve webpage with minified and compressed JavaScript', async function() {
113
+ // Start server with minification and compression enabled
114
+ server = new Server();
115
+ await server.serve({
116
+ ctrl: testControl,
117
+ port: serverPort,
118
+ debug: false, // Enable minification
119
+ bundler: {
120
+ minify: {
121
+ enabled: true,
122
+ level: 'normal'
123
+ },
124
+ compression: {
125
+ enabled: true,
126
+ algorithms: ['gzip', 'br']
127
+ }
128
+ }
129
+ });
130
+
131
+ // Wait for server to be ready
132
+ await new Promise(resolve => setTimeout(resolve, 2000));
133
+
134
+ // Test gzip compressed JavaScript
135
+ const jsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`, {
136
+ 'Accept-Encoding': 'gzip'
137
+ });
138
+
139
+ assert.strictEqual(jsResponse.statusCode, 200);
140
+ assert.strictEqual(jsResponse.headers['content-encoding'], 'gzip');
141
+ assert(jsResponse.headers['content-type'].includes('javascript'));
142
+
143
+ // Verify the response is actually compressed (should be smaller than original)
144
+ const originalSize = Buffer.from(testControl.js, 'utf8').length;
145
+ const compressedSize = jsResponse.body.length;
146
+ assert(compressedSize < originalSize, 'JavaScript should be compressed');
147
+
148
+ // Test brotli compressed JavaScript
149
+ const brJsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`, {
150
+ 'Accept-Encoding': 'br'
151
+ });
152
+
153
+ assert.strictEqual(brJsResponse.statusCode, 200);
154
+ assert.strictEqual(brJsResponse.headers['content-encoding'], 'br');
155
+
156
+ // Brotli should generally be smaller than gzip for text
157
+ assert(brJsResponse.body.length <= jsResponse.body.length,
158
+ 'Brotli should be at least as good as gzip');
159
+
160
+ // Stop server
161
+ await server.stop();
162
+ });
163
+
164
+ it('should serve webpage with sourcemaps in debug mode', async function() {
165
+ // Start server in debug mode
166
+ server = new Server();
167
+ await server.serve({
168
+ ctrl: testControl,
169
+ port: serverPort,
170
+ debug: true, // Enable sourcemaps
171
+ bundler: {
172
+ sourcemaps: {
173
+ enabled: true,
174
+ format: 'inline'
175
+ },
176
+ compression: {
177
+ enabled: true,
178
+ algorithms: ['gzip']
179
+ }
180
+ }
181
+ });
182
+
183
+ // Wait for server to be ready
184
+ await new Promise(resolve => setTimeout(resolve, 2000));
185
+
186
+ // Test JavaScript with sourcemaps
187
+ const jsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`, {
188
+ 'Accept-Encoding': 'gzip'
189
+ });
190
+
191
+ assert.strictEqual(jsResponse.statusCode, 200);
192
+ assert.strictEqual(jsResponse.headers['content-encoding'], 'gzip');
193
+
194
+ // Decompress to check for sourcemap
195
+ const zlib = require('zlib');
196
+ const decompressed = zlib.gunzipSync(jsResponse.body).toString();
197
+ assert(decompressed.includes('//# sourceMappingURL='), 'Debug mode should include inline sourcemaps');
198
+
199
+ // Stop server
200
+ await server.stop();
201
+ });
202
+
203
+ it('should serve compressed CSS', async function() {
204
+ // Start server with compression
205
+ server = new Server();
206
+ await server.serve({
207
+ ctrl: testControl,
208
+ port: serverPort,
209
+ debug: false,
210
+ bundler: {
211
+ compression: {
212
+ enabled: true,
213
+ algorithms: ['gzip', 'br']
214
+ }
215
+ }
216
+ });
217
+
218
+ // Wait for server to be ready
219
+ await new Promise(resolve => setTimeout(resolve, 2000));
220
+
221
+ // Test gzip compressed CSS
222
+ const cssResponse = await makeRequest(`http://localhost:${serverPort}/css/css.css`, {
223
+ 'Accept-Encoding': 'gzip'
224
+ });
225
+
226
+ assert.strictEqual(cssResponse.statusCode, 200);
227
+ assert.strictEqual(cssResponse.headers['content-encoding'], 'gzip');
228
+ assert(cssResponse.headers['content-type'].includes('css'));
229
+
230
+ // Verify CSS content is compressed
231
+ const originalCssSize = Buffer.from(testControl.css, 'utf8').length;
232
+ const compressedCssSize = cssResponse.body.length;
233
+ assert(compressedCssSize < originalCssSize, 'CSS should be compressed');
234
+
235
+ // Stop server
236
+ await server.stop();
237
+ });
238
+
239
+ it('should serve HTML without compression when below threshold', async function() {
240
+ // Start server with high compression threshold
241
+ server = new Server();
242
+ await server.serve({
243
+ ctrl: testControl,
244
+ port: serverPort,
245
+ debug: false,
246
+ bundler: {
247
+ compression: {
248
+ enabled: true,
249
+ threshold: 10000 // Very high threshold
250
+ }
251
+ }
252
+ });
253
+
254
+ // Wait for server to be ready
255
+ await new Promise(resolve => setTimeout(resolve, 2000));
256
+
257
+ // Test HTML (should not be compressed due to threshold)
258
+ const htmlResponse = await makeRequest(`http://localhost:${serverPort}/`, {
259
+ 'Accept-Encoding': 'gzip'
260
+ });
261
+
262
+ assert.strictEqual(htmlResponse.statusCode, 200);
263
+ assert(!htmlResponse.headers['content-encoding'], 'HTML should not be compressed due to threshold');
264
+ assert(htmlResponse.headers['content-type'].includes('html'));
265
+
266
+ // Stop server
267
+ await server.stop();
268
+ });
269
+
270
+ it('should handle different minification levels', async function() {
271
+ const minificationLevels = ['conservative', 'normal', 'aggressive'];
272
+
273
+ for (const level of minificationLevels) {
274
+ // Start server with specific minification level
275
+ server = new Server();
276
+ await server.serve({
277
+ ctrl: testControl,
278
+ port: serverPort,
279
+ debug: false,
280
+ bundler: {
281
+ minify: {
282
+ enabled: true,
283
+ level: level
284
+ },
285
+ compression: {
286
+ enabled: false // Disable compression for size comparison
287
+ }
288
+ }
289
+ });
290
+
291
+ // Wait for server to be ready
292
+ await new Promise(resolve => setTimeout(resolve, 2000));
293
+
294
+ // Test JavaScript
295
+ const jsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`);
296
+
297
+ assert.strictEqual(jsResponse.statusCode, 200);
298
+ assert(!jsResponse.headers['content-encoding'], 'Should not be compressed');
299
+
300
+ // Verify minification occurred (should be smaller than original)
301
+ const originalSize = Buffer.from(testControl.js, 'utf8').length;
302
+ const minifiedSize = jsResponse.body.length;
303
+ assert(minifiedSize < originalSize, `JavaScript should be minified with ${level} level`);
304
+
305
+ // Stop server
306
+ await server.stop();
307
+ }
308
+ });
309
+
310
+ it('should serve identical content with identity encoding when compression disabled', async function() {
311
+ // Start server with compression disabled
312
+ server = new Server();
313
+ await server.serve({
314
+ ctrl: testControl,
315
+ port: serverPort,
316
+ debug: false,
317
+ bundler: {
318
+ compression: {
319
+ enabled: false
320
+ }
321
+ }
322
+ });
323
+
324
+ // Wait for server to be ready
325
+ await new Promise(resolve => setTimeout(resolve, 2000));
326
+
327
+ // Test with gzip request but compression disabled
328
+ const jsResponse = await makeRequest(`http://localhost:${serverPort}/js/js.js`, {
329
+ 'Accept-Encoding': 'gzip'
330
+ });
331
+
332
+ assert.strictEqual(jsResponse.statusCode, 200);
333
+ assert(!jsResponse.headers['content-encoding'], 'Should not have content-encoding when compression disabled');
334
+
335
+ // Stop server
336
+ await server.stop();
337
+ });
338
+
339
+ it('should handle multiple concurrent requests', async function() {
340
+ // Start server
341
+ server = new Server();
342
+ await server.serve({
343
+ ctrl: testControl,
344
+ port: serverPort,
345
+ debug: false,
346
+ bundler: {
347
+ compression: {
348
+ enabled: true,
349
+ algorithms: ['gzip']
350
+ }
351
+ }
352
+ });
353
+
354
+ // Wait for server to be ready
355
+ await new Promise(resolve => setTimeout(resolve, 2000));
356
+
357
+ // Make multiple concurrent requests
358
+ const requests = [];
359
+ for (let i = 0; i < 5; i++) {
360
+ requests.push(makeRequest(`http://localhost:${serverPort}/js/js.js`, {
361
+ 'Accept-Encoding': 'gzip'
362
+ }));
363
+ }
364
+
365
+ const responses = await Promise.all(requests);
366
+
367
+ // All requests should succeed
368
+ responses.forEach(response => {
369
+ assert.strictEqual(response.statusCode, 200);
370
+ assert.strictEqual(response.headers['content-encoding'], 'gzip');
371
+ });
372
+
373
+ // Stop server
374
+ await server.stop();
375
+ });
376
+
377
+ it('should serve correct content types', async function() {
378
+ // Start server
379
+ server = new Server();
380
+ await server.serve({
381
+ ctrl: testControl,
382
+ port: serverPort,
383
+ debug: false
384
+ });
385
+
386
+ // Wait for server to be ready
387
+ await new Promise(resolve => setTimeout(resolve, 2000));
388
+
389
+ // Test different content types
390
+ const tests = [
391
+ { path: '/', expectedType: 'html' },
392
+ { path: '/js/js.js', expectedType: 'javascript' },
393
+ { path: '/css/css.css', expectedType: 'css' }
394
+ ];
395
+
396
+ for (const test of tests) {
397
+ const response = await makeRequest(`http://localhost:${serverPort}${test.path}`);
398
+ assert.strictEqual(response.statusCode, 200);
399
+ assert(response.headers['content-type'].includes(test.expectedType),
400
+ `Should serve correct content type for ${test.path}`);
401
+ }
402
+
403
+ // Stop server
404
+ await server.stop();
405
+ });
406
+ });
407
+
408
+ describe('Error Handling in End-to-End Scenarios', function() {
409
+ it('should handle invalid configuration gracefully', async function() {
410
+ // Try to start server with invalid configuration
411
+ server = new Server();
412
+
413
+ try {
414
+ await server.serve({
415
+ ctrl: testControl,
416
+ port: serverPort,
417
+ bundler: {
418
+ compression: {
419
+ enabled: 'invalid' // Invalid boolean
420
+ }
421
+ }
422
+ });
423
+ assert.fail('Should have thrown error for invalid configuration');
424
+ } catch (error) {
425
+ assert(error, 'Should throw error for invalid configuration');
426
+ }
427
+ });
428
+
429
+ it('should handle server port conflicts', async function() {
430
+ // Start first server
431
+ const server1 = new Server();
432
+ await server1.serve({
433
+ ctrl: testControl,
434
+ port: serverPort,
435
+ debug: false
436
+ });
437
+
438
+ // Try to start second server on same port
439
+ const server2 = new Server();
440
+ try {
441
+ await server2.serve({
442
+ ctrl: testControl,
443
+ port: serverPort, // Same port
444
+ debug: false
445
+ });
446
+ assert.fail('Should have failed to start server on occupied port');
447
+ } catch (error) {
448
+ assert(error, 'Should throw error for port conflict');
449
+ }
450
+
451
+ // Clean up
452
+ await server1.stop();
453
+ });
454
+ });
455
+ });
456
+
457
+ // Helper function to make HTTP requests
458
+ function makeRequest(url, headers = {}) {
459
+ return new Promise((resolve, reject) => {
460
+ const parsedUrl = new URL(url);
461
+ const options = {
462
+ hostname: parsedUrl.hostname,
463
+ port: parsedUrl.port,
464
+ path: parsedUrl.pathname,
465
+ method: 'GET',
466
+ headers: {
467
+ 'User-Agent': 'JSGUI3-Test/1.0',
468
+ ...headers
469
+ }
470
+ };
471
+
472
+ const req = http.request(options, (res) => {
473
+ let body = Buffer.alloc(0);
474
+
475
+ res.on('data', (chunk) => {
476
+ body = Buffer.concat([body, chunk]);
477
+ });
478
+
479
+ res.on('end', () => {
480
+ resolve({
481
+ statusCode: res.statusCode,
482
+ headers: res.headers,
483
+ body: body
484
+ });
485
+ });
486
+ });
487
+
488
+ req.on('error', reject);
489
+ req.setTimeout(5000, () => {
490
+ req.destroy();
491
+ reject(new Error('Request timeout'));
492
+ });
493
+
494
+ req.end();
495
+ });
496
+ }