jsgui3-server 0.0.134 → 0.0.135

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 (29) hide show
  1. package/AGENTS.md +6 -0
  2. package/README.md +114 -18
  3. package/TODO.md +81 -0
  4. package/cli.js +96 -0
  5. package/docs/simple-server-api-design.md +702 -0
  6. package/examples/controls/14d) window, canvas globe/Clipping.js +0 -0
  7. package/examples/controls/14d) window, canvas globe/EarthGlobeRenderer.js +319 -762
  8. package/examples/controls/14d) window, canvas globe/RenderingPipeline.js +43 -0
  9. package/examples/controls/14d) window, canvas globe/pipeline/BaseStage.js +46 -0
  10. package/examples/controls/14d) window, canvas globe/pipeline/ClippingStage.js +29 -0
  11. package/examples/controls/14d) window, canvas globe/pipeline/ComposeStage.js +15 -0
  12. package/examples/controls/14d) window, canvas globe/pipeline/ContinentsStage.js +116 -0
  13. package/examples/controls/14d) window, canvas globe/pipeline/GridStage.js +105 -0
  14. package/examples/controls/14d) window, canvas globe/pipeline/HUDStage.js +10 -0
  15. package/examples/controls/14d) window, canvas globe/pipeline/ShadeSphereStage.js +153 -0
  16. package/examples/controls/14d) window, canvas globe/pipeline/TransformStage.js +23 -0
  17. package/examples/controls/14d) window, canvas globe/pipeline/clipping/FrontFaceStrategy.js +46 -0
  18. package/examples/controls/14d) window, canvas globe/pipeline/clipping/PlaneClipStrategy.js +339 -0
  19. package/module.js +3 -1
  20. package/package.json +9 -3
  21. package/resources/_old_website-resource.js +10 -2
  22. package/resources/jsbuilder/babel/deep_iterate/deep_iterate_babel.js +37 -0
  23. package/serve-factory.js +221 -0
  24. package/serve-helpers.js +95 -0
  25. package/server.js +93 -7
  26. package/tests/cli.test.js +66 -0
  27. package/tests/dummy-client.js +10 -0
  28. package/tests/serve.test.js +210 -0
  29. package/.vscode/settings.json +0 -13
@@ -0,0 +1,702 @@
1
+ # Simple Server API Design
2
+
3
+ **Goal:** Make jsgui3-server trivially easy to use for simple cases while preserving full power for complex scenarios.
4
+
5
+ ## Design Philosophy
6
+
7
+ 1. **Progressive Disclosure** – Simple things should be simple; complex things should be possible
8
+ 2. **Convention Over Configuration** – Smart defaults; minimal required config
9
+ 3. **Consistent Patterns** – Same API shape at every scale
10
+ 4. **Zero-to-Hero Path** – Clear upgrade path from simple to advanced
11
+ 5. **Composable** – Mix and match features (pages, APIs, static files)
12
+
13
+ ---
14
+
15
+ ## Current Pain Points
16
+
17
+ ### Boilerplate Example (Current)
18
+ Every example needs ~30 lines of identical code:
19
+
20
+ ```javascript
21
+ const jsgui = require('./client');
22
+ const {Demo_UI} = jsgui.controls;
23
+ const Server = require('../../../server');
24
+
25
+ if (require.main === module) {
26
+ const server = new Server({
27
+ Ctrl: Demo_UI,
28
+ src_path_client_js: require.resolve('./client.js')
29
+ });
30
+ console.log('waiting for server ready event');
31
+ server.on('ready', () => {
32
+ console.log('server ready');
33
+ server.start(52000, (err) => {
34
+ if (err) throw err;
35
+ console.log('server started');
36
+ });
37
+ });
38
+ }
39
+ ```
40
+
41
+ ### Problems:
42
+ - Manual path resolution (`require.resolve`)
43
+ - Hard-coded ports (no ENV var support)
44
+ - Verbose event handling (3 console.logs)
45
+ - No convention-based discovery
46
+ - Callback nesting
47
+ - Repetitive across all 42 examples
48
+
49
+ ---
50
+
51
+ ## Proposed API Layers
52
+
53
+ ### Layer 0: Single Control (Simplest)
54
+
55
+ **Use Case:** Quick demo, single-page app, learning
56
+
57
+ ```javascript
58
+ // Ultra-minimal – just serve a control
59
+ const Server = require('jsgui3-server');
60
+ const { MyControl } = require('./client').controls;
61
+
62
+ Server.serve(MyControl);
63
+ // Runs on port 8080, auto-discovers client.js in same directory
64
+ ```
65
+
66
+ ```javascript
67
+ // With port override
68
+ Server.serve(MyControl, { port: 3000 });
69
+ ```
70
+
71
+ ```javascript
72
+ // Explicit object notation
73
+ Server.serve({
74
+ ctrl: MyControl,
75
+ port: 3000,
76
+ host: 'localhost'
77
+ });
78
+ ```
79
+
80
+ **Defaults:**
81
+ - Port: `8080` (or `process.env.PORT`)
82
+ - Host: All IPv4 interfaces (or `process.env.HOST`)
83
+ - Auto-discovers `client.js` in same directory as `server.js`
84
+ - Auto-bundles CSS/JS
85
+ - Routes: `/` → control, `/js/js.js` → bundled JS, `/css/css.css` → bundled CSS
86
+
87
+ ---
88
+
89
+ ### Layer 1: Single Page with Metadata
90
+
91
+ **Use Case:** Add page title, description, favicon, custom path
92
+
93
+ ```javascript
94
+ Server.serve({
95
+ page: {
96
+ content: MyControl,
97
+ title: 'My Awesome App',
98
+ description: 'A jsgui3 application',
99
+ path: '/', // Default
100
+ favicon: './favicon.ico' // Optional
101
+ },
102
+ port: 3000
103
+ });
104
+ ```
105
+
106
+ **Benefits:**
107
+ - Proper HTML `<title>` and meta tags
108
+ - Explicit page configuration
109
+ - Still single-file simplicity
110
+
111
+ ---
112
+
113
+ ### Layer 2: Multiple Pages (Multi-Page App)
114
+
115
+ **Use Case:** Website with multiple routes, each with different content
116
+
117
+ ```javascript
118
+ Server.serve({
119
+ pages: {
120
+ '/': {
121
+ content: HomeControl,
122
+ title: 'Home - My Site'
123
+ },
124
+ '/about': {
125
+ content: AboutControl,
126
+ title: 'About Us'
127
+ },
128
+ '/contact': {
129
+ content: ContactControl,
130
+ title: 'Contact'
131
+ }
132
+ },
133
+ port: 3000
134
+ });
135
+ ```
136
+
137
+ **Auto-routing:**
138
+ - Each key becomes a route
139
+ - Shared JS/CSS bundle automatically included on all pages
140
+ - Pages can reference different client files if needed
141
+
142
+ ---
143
+
144
+ ### Layer 3: Pages + API Endpoints
145
+
146
+ **Use Case:** Frontend controls + backend API functions
147
+
148
+ ```javascript
149
+ Server.serve({
150
+ pages: {
151
+ '/': { content: DashboardControl, title: 'Dashboard' }
152
+ },
153
+ api: {
154
+ // GET/POST /api/hello
155
+ 'hello': (name) => `Hello ${name || 'World'}!`,
156
+
157
+ // GET/POST /api/calculate
158
+ 'calculate': ({ a, b }) => ({ sum: a + b, product: a * b }),
159
+
160
+ // Async function support
161
+ 'users': async () => {
162
+ const users = await db.getUsers();
163
+ return users;
164
+ }
165
+ },
166
+ port: 3000
167
+ });
168
+ ```
169
+
170
+ **API Conventions:**
171
+ - Routes prefixed with `/api/` automatically
172
+ - JSON input/output auto-parsed/serialized
173
+ - String returns sent as `text/plain`
174
+ - Object/Array returns sent as `application/json`
175
+ - Promises automatically awaited
176
+
177
+ ---
178
+
179
+ ### Layer 4: Pages + API + Static Files
180
+
181
+ **Use Case:** Full web application with assets
182
+
183
+ ```javascript
184
+ Server.serve({
185
+ pages: {
186
+ '/': { content: HomeControl, title: 'Home' },
187
+ '/gallery': { content: GalleryControl, title: 'Gallery' }
188
+ },
189
+ api: {
190
+ 'images': () => fs.readdirSync('./images').map(f => `/images/${f}`)
191
+ },
192
+ static: {
193
+ '/images': './public/images',
194
+ '/assets': './public/assets'
195
+ },
196
+ port: 3000
197
+ });
198
+ ```
199
+
200
+ **Static file handling:**
201
+ - Automatic MIME type detection
202
+ - Efficient streaming for large files
203
+ - Optional caching headers
204
+ - Directory listing (configurable)
205
+
206
+ ---
207
+
208
+ ### Layer 5: Shorthand Routes (Mixed Types)
209
+
210
+ **Use Case:** Mix controls, functions, and static content flexibly
211
+
212
+ ```javascript
213
+ Server.serve({
214
+ routes: {
215
+ '/': HomeControl, // Control at root
216
+ '/dashboard': DashboardControl, // Control at path
217
+ '/api/time': () => new Date(), // Function endpoint
218
+ '/docs': './documentation' // Static directory
219
+ },
220
+ port: 3000
221
+ });
222
+ ```
223
+
224
+ **Auto-detection:**
225
+ - Control constructor → webpage
226
+ - Function → API endpoint
227
+ - String path → static directory
228
+ - Object with `content` → full page config
229
+
230
+ ---
231
+
232
+ ### Layer 6: Full Website Object
233
+
234
+ **Use Case:** Complex multi-page sites, existing `Website` instances
235
+
236
+ ```javascript
237
+ const { Website, Webpage } = require('jsgui3-website');
238
+
239
+ const myWebsite = new Website({
240
+ name: 'My Corporate Site'
241
+ });
242
+
243
+ myWebsite.pages.push(new Webpage({
244
+ name: 'Home',
245
+ title: 'Welcome',
246
+ content: HomeControl,
247
+ path: '/'
248
+ }));
249
+
250
+ myWebsite.pages.push(new Webpage({
251
+ name: 'Products',
252
+ title: 'Our Products',
253
+ content: ProductsControl,
254
+ path: '/products'
255
+ }));
256
+
257
+ Server.serve({
258
+ website: myWebsite,
259
+ api: { /* ... */ },
260
+ static: { /* ... */ },
261
+ port: 3000
262
+ });
263
+ ```
264
+
265
+ **Benefits:**
266
+ - Full `Website` API available
267
+ - Compose complex structures programmatically
268
+ - Mix with API and static files
269
+ - Reuse website objects
270
+
271
+ ---
272
+
273
+ ### Layer 7: Legacy/Advanced (Current API)
274
+
275
+ **Still fully supported for maximum control:**
276
+
277
+ ```javascript
278
+ const server = new Server({
279
+ Ctrl: MyControl,
280
+ src_path_client_js: require.resolve('./client.js'),
281
+ debug: true,
282
+ https_options: { /* ... */ }
283
+ });
284
+
285
+ server.on('ready', () => {
286
+ server.publish('endpoint', handler);
287
+ server.start(port, callback);
288
+ });
289
+ ```
290
+
291
+ ---
292
+
293
+ ## Convention-Based Defaults
294
+
295
+ ### Auto-Discovery Rules
296
+
297
+ 1. **Client JS:**
298
+ - Look for `client.js` in same directory as `server.js`
299
+ - Look for `index.js` with exported controls
300
+ - Can be overridden with `clientPath` option
301
+
302
+ 2. **Control Detection:**
303
+ - If `client.js` exports single control → use it
304
+ - If exports `controls.Demo_UI` → use Demo_UI
305
+ - If exports multiple → use first in `controls` object
306
+ - Can be overridden with `ctrl` option
307
+
308
+ 3. **Port:**
309
+ - Use `process.env.PORT` if set
310
+ - Default to `8080`
311
+ - Override with `port` option
312
+
313
+ 4. **Host:**
314
+ - Use `process.env.HOST` if set (single interface)
315
+ - Default to all IPv4 interfaces
316
+ - Override with `host` option
317
+
318
+ 5. **Debug Mode:**
319
+ - Use `process.env.JSGUI_DEBUG` if set
320
+ - Default to `false`
321
+ - Override with `debug` option
322
+
323
+ ---
324
+
325
+ ## Environment Variable Support
326
+
327
+ ```bash
328
+ # Port
329
+ PORT=3000 node server.js
330
+
331
+ # Specific host/interface
332
+ HOST=127.0.0.1 node server.js
333
+
334
+ # Debug mode (verbose logging, no minification)
335
+ JSGUI_DEBUG=1 node server.js
336
+
337
+ # Combine
338
+ PORT=3000 HOST=localhost JSGUI_DEBUG=1 node server.js
339
+ ```
340
+
341
+ ---
342
+
343
+ ## Async/Promise Support
344
+
345
+ ### Callback Style (Legacy)
346
+ ```javascript
347
+ Server.serve({ ctrl: MyControl, port: 3000 }, (err, server) => {
348
+ if (err) throw err;
349
+ console.log('Server running');
350
+ });
351
+ ```
352
+
353
+ ### Promise Style (Modern)
354
+ ```javascript
355
+ const server = await Server.serve({ ctrl: MyControl, port: 3000 });
356
+ console.log('Server running on port', server.port);
357
+ ```
358
+
359
+ ### Event Style (Current)
360
+ ```javascript
361
+ const server = Server.serve({ ctrl: MyControl, port: 3000 });
362
+ server.on('ready', () => console.log('Ready!'));
363
+ server.on('started', () => console.log('Started!'));
364
+ ```
365
+
366
+ ---
367
+
368
+ ## Configuration File Support
369
+
370
+ ### `jsgui.config.js` (Optional)
371
+
372
+ ```javascript
373
+ module.exports = {
374
+ port: 3000,
375
+ host: 'localhost',
376
+ debug: true,
377
+ pages: {
378
+ '/': { content: require('./controls/home'), title: 'Home' },
379
+ '/about': { content: require('./controls/about'), title: 'About' }
380
+ },
381
+ api: {
382
+ 'hello': name => `Hello ${name}`
383
+ },
384
+ static: {
385
+ '/assets': './public'
386
+ }
387
+ };
388
+ ```
389
+
390
+ **Usage:**
391
+ ```javascript
392
+ // Reads jsgui.config.js automatically
393
+ Server.serve();
394
+
395
+ // Or specify config file
396
+ Server.serve({ config: './my-config.js' });
397
+
398
+ // Config file + overrides
399
+ Server.serve({ config: './my-config.js', port: 4000 });
400
+ ```
401
+
402
+ ---
403
+
404
+ ## Special Modes
405
+
406
+ ### Preview Mode
407
+ **Opens browser automatically, uses ephemeral port:**
408
+ ```javascript
409
+ await Server.serve.preview({ ctrl: MyControl });
410
+ // Opens http://localhost:58392/ automatically
411
+ ```
412
+
413
+ ### Development Mode
414
+ **Auto-restart on file changes:**
415
+ ```javascript
416
+ Server.serve.dev({
417
+ ctrl: MyControl,
418
+ watch: ['./client.js', './controls/*.js']
419
+ });
420
+ // Restarts when files change
421
+ ```
422
+
423
+ ### Build Mode
424
+ **Pre-bundle for production (no server start):**
425
+ ```javascript
426
+ await Server.serve.build({
427
+ ctrl: MyControl,
428
+ output: './dist'
429
+ });
430
+ // Creates ./dist with bundled HTML/CSS/JS
431
+ ```
432
+
433
+ ---
434
+
435
+ ## CLI Integration
436
+
437
+ ### Serve Examples Directly
438
+ ```powershell
439
+ # Serve a specific example
440
+ node cli.js serve-example "7) window, month_view" --port 3000
441
+
442
+ # Serve by client.js path
443
+ node cli.js serve-client ./examples/controls/7*/client.js --port 3000
444
+
445
+ # Serve current directory (auto-discover)
446
+ node cli.js serve --port 3000
447
+
448
+ # Preview mode (ephemeral port, auto-open browser)
449
+ node cli.js preview ./examples/controls/7*/client.js
450
+ ```
451
+
452
+ ---
453
+
454
+ ## Error Messages
455
+
456
+ ### Clear, Actionable Errors
457
+
458
+ **Before:**
459
+ ```
460
+ TypeError: Cannot read property 'content' of undefined
461
+ ```
462
+
463
+ **After:**
464
+ ```
465
+ jsgui3-server: Control not found
466
+
467
+ Looking for a control to serve but none was specified.
468
+
469
+ Did you mean to:
470
+ - Pass a control: Server.serve(MyControl)
471
+ - Specify ctrl option: Server.serve({ ctrl: MyControl })
472
+ - Create a client.js with exported controls?
473
+
474
+ Current directory: C:\Users\james\project
475
+ Searched for: client.js, index.js
476
+
477
+ See docs: https://github.com/metabench/jsgui3-server#quick-start
478
+ ```
479
+
480
+ ---
481
+
482
+ ## Migration Path
483
+
484
+ ### Current Example (30 lines)
485
+ ```javascript
486
+ const jsgui = require('./client');
487
+ const {Demo_UI} = jsgui.controls;
488
+ const Server = require('../../../server');
489
+
490
+ if (require.main === module) {
491
+ const server = new Server({
492
+ Ctrl: Demo_UI,
493
+ src_path_client_js: require.resolve('./client.js')
494
+ });
495
+ console.log('waiting for server ready event');
496
+ server.on('ready', () => {
497
+ console.log('server ready');
498
+ server.start(52000, (err) => {
499
+ if (err) throw err;
500
+ console.log('server started');
501
+ });
502
+ });
503
+ }
504
+ ```
505
+
506
+ ### New Example (3 lines)
507
+ ```javascript
508
+ const Server = require('../../../server');
509
+ const { Demo_UI } = require('./client').controls;
510
+
511
+ Server.serve({ ctrl: Demo_UI, port: 52000 });
512
+ ```
513
+
514
+ ### Even Simpler (1 line)
515
+ ```javascript
516
+ require('../../../server').serve(require('./client').controls.Demo_UI);
517
+ ```
518
+
519
+ ---
520
+
521
+ ## Implementation Checklist
522
+
523
+ ### Phase 1: Core `serve()` Method (Complete)
524
+ - [x] Add `Server.serve()` static method
525
+ - [x] Detect input type (Control, object)
526
+ - [x] Support `ctrl`, `page`, `pages` options
527
+ - [x] Handle port/host/debug options
528
+ - [x] Auto-discover client.js convention
529
+ - [x] Return a Promise that resolves with the server instance
530
+ - [x] Support Promise/async and callback patterns
531
+
532
+ ### Phase 2: API & Static (Partially Complete)
533
+ - [x] `api` option for function publishing
534
+ - [x] Auto-prefix `/api/` routes
535
+ - [x] JSON/text content-type detection
536
+ - [ ] `static` option for directory serving
537
+ - [ ] MIME type detection for static files
538
+
539
+ ### Phase 3: Enhanced Features (Partially Complete)
540
+ - [x] ENV var support (PORT, HOST, JSGUI_DEBUG)
541
+ - [ ] Config file support (`jsgui.config.js`)
542
+ - [ ] Improved error messages
543
+ - [x] Consolidated console output (reduce noise)
544
+
545
+ ### Phase 4: Special Modes
546
+ - [ ] `Server.serve.preview()` – ephemeral port + browser open
547
+ - [ ] `Server.serve.dev()` – file watching + auto-restart
548
+ - [ ] `Server.serve.build()` – pre-bundle for production
549
+
550
+ ### Phase 5: CLI Integration
551
+ - [ ] `node cli.js serve-example <name>`
552
+ - [ ] `node cli.js serve-client <path>`
553
+ - [ ] `node cli.js preview <path>`
554
+ - [ ] Auto-discovery in current directory
555
+
556
+ ### Phase 6: Documentation
557
+ - [ ] Update README with new API
558
+ - [ ] Create migration guide
559
+ - [ ] Add API reference docs
560
+ - [ ] Update 2-3 examples as demos
561
+ - [ ] Keep legacy examples as-is (still valid)
562
+
563
+ ---
564
+
565
+ ## Example Conversions
566
+
567
+ ### Example 1: Simple Window + Checkbox
568
+ **Before:**
569
+ ```javascript
570
+ const jsgui = require('./client');
571
+ const {Demo_UI} = jsgui.controls;
572
+ const Server = require('../../../server');
573
+
574
+ if (require.main === module) {
575
+ const server = new Server({
576
+ Ctrl: Demo_UI,
577
+ src_path_client_js: require.resolve('./client.js')
578
+ });
579
+ console.log('waiting for server ready event');
580
+ server.on('ready', () => {
581
+ console.log('server ready');
582
+ server.start(52000, (err) => {
583
+ if (err) throw err;
584
+ console.log('server started');
585
+ });
586
+ });
587
+ }
588
+ ```
589
+
590
+ **After:**
591
+ ```javascript
592
+ require('../../../server').serve({
593
+ ctrl: require('./client').controls.Demo_UI,
594
+ port: 52000
595
+ });
596
+ ```
597
+
598
+ ### Example 2: Month View with Title
599
+ **After (with page metadata):**
600
+ ```javascript
601
+ require('../../../server').serve({
602
+ page: {
603
+ content: require('./client').controls.Demo_UI,
604
+ title: 'JSGUI3 Month View Demo',
605
+ description: 'Interactive calendar control example'
606
+ },
607
+ port: 52000
608
+ });
609
+ ```
610
+
611
+ ### Example 3: Multi-Control Dashboard
612
+ **After (multiple pages):**
613
+ ```javascript
614
+ const { HomeControl, SettingsControl, ReportsControl } = require('./client').controls;
615
+
616
+ require('../../../server').serve({
617
+ pages: {
618
+ '/': { content: HomeControl, title: 'Dashboard' },
619
+ '/settings': { content: SettingsControl, title: 'Settings' },
620
+ '/reports': { content: ReportsControl, title: 'Reports' }
621
+ },
622
+ port: 52000
623
+ });
624
+ ```
625
+
626
+ ### Example 4: Dashboard with API
627
+ **After (pages + API):**
628
+ ```javascript
629
+ const { DashboardControl } = require('./client').controls;
630
+
631
+ require('../../../server').serve({
632
+ page: {
633
+ content: DashboardControl,
634
+ title: 'Analytics Dashboard'
635
+ },
636
+ api: {
637
+ 'metrics': () => ({
638
+ users: 1234,
639
+ revenue: 56789,
640
+ growth: 0.23
641
+ }),
642
+ 'data': async ({ range }) => {
643
+ return await fetchAnalytics(range);
644
+ }
645
+ },
646
+ port: 52000
647
+ });
648
+ ```
649
+
650
+ ---
651
+
652
+ ## Backwards Compatibility
653
+
654
+ **All existing code continues to work unchanged:**
655
+
656
+ ```javascript
657
+ // Current API - still fully supported
658
+ const server = new Server({
659
+ Ctrl: Demo_UI,
660
+ src_path_client_js: require.resolve('./client.js'),
661
+ debug: true
662
+ });
663
+
664
+ server.on('ready', () => {
665
+ server.publish('api', handler);
666
+ server.start(52000, (err) => {
667
+ if (err) throw err;
668
+ console.log('server started');
669
+ });
670
+ });
671
+ ```
672
+
673
+ **Zero breaking changes. New API is purely additive.**
674
+
675
+ ---
676
+
677
+ ## Summary
678
+
679
+ ### Before (Current)
680
+ - 30 lines of boilerplate per example
681
+ - Manual path resolution
682
+ - Hard-coded ports
683
+ - Verbose console output
684
+ - No conventions
685
+ - Callback nesting
686
+
687
+ ### After (New)
688
+ - 1-5 lines for simple cases
689
+ - Auto-discovery of client.js
690
+ - ENV var support
691
+ - Clean, minimal output
692
+ - Progressive disclosure
693
+ - Promise/async support
694
+ - Still 100% backwards compatible
695
+
696
+ ### Key Benefits
697
+ 1. **Faster prototyping** – from idea to running in seconds
698
+ 2. **Less boilerplate** – 90% reduction for simple cases
699
+ 3. **Better defaults** – works out of the box
700
+ 4. **Clearer intent** – code reads like configuration
701
+ 5. **Easy scaling** – simple projects grow naturally
702
+ 6. **Zero breaking changes** – all existing code still works