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,41 @@
1
+ # 1. Startup Readiness State Machine
2
+
3
+ ## Core Problem
4
+
5
+ A server that binds a socket before its route graph is installed can return transient `404` responses during cold start. This is a correctness defect, not a cosmetic delay.
6
+
7
+ ## Current Model
8
+
9
+ `Server.serve(...)` now enforces a strict ordering:
10
+
11
+ 1. construct `Server` instance
12
+ 2. install API publishers and optional SSE publisher
13
+ 3. wait for server `ready` event (emitted after webpage/website publisher route installation)
14
+ 4. resolve additional page route preparations
15
+ 5. bind sockets with `server.start(...)`
16
+ 6. start configured resources
17
+ 7. resolve `serve(...)` promise
18
+
19
+ ## Removed Failure Pattern
20
+
21
+ Previous behavior had a fallback timer that could start listening before `ready`. This allowed requests to arrive before `/` and bundle routes were present.
22
+
23
+ That path is removed. Startup now rejects on readiness timeout instead of entering a half-ready listening state.
24
+
25
+ ## Startup Timeout
26
+
27
+ `readyTimeoutMs` (default `120000`) bounds waiting for readiness. Timeout behavior:
28
+
29
+ - if readiness is not reached in time, `serve(...)` rejects
30
+ - no forced early listen occurs
31
+
32
+ This makes startup failure explicit and testable.
33
+
34
+ ## Verification
35
+
36
+ `tests/serve.test.js` includes a delayed fake webpage publisher and asserts that:
37
+
38
+ - `serve(...)` does not resolve until delayed readiness arrives
39
+ - post-resolution `/` is immediately routable
40
+
41
+ This test prevents regression to pre-ready listening.
@@ -0,0 +1,92 @@
1
+ # 2. Resource Abstraction and Lifecycle
2
+
3
+ ## Uniform Contract
4
+
5
+ `Process_Resource` and `Remote_Process_Resource` expose the same operational surface:
6
+
7
+ - `start()`
8
+ - `stop()`
9
+ - `restart()`
10
+ - `status` getter
11
+ - `get_abstract()`
12
+
13
+ The contract allows client/API code to remain management-backend agnostic.
14
+
15
+ ## Process_Resource Modes
16
+
17
+ `Process_Resource` supports two process managers:
18
+
19
+ - `direct` (default): local child process (`spawn`)
20
+ - `pm2`: external manager integration (`pm2 start/stop/restart/jlist`)
21
+
22
+ PM2 path resolution is optional and automatic:
23
+
24
+ 1. `processManager.pm2Path`
25
+ 2. `PM2_PATH` env
26
+ 3. local `node_modules/.bin/pm2(.cmd)`
27
+ 4. `pm2` from `PATH`
28
+
29
+ Therefore explicit `pm2Path` is not required for default operation.
30
+
31
+ ## State Machine
32
+
33
+ Nominal states:
34
+
35
+ - `stopped`
36
+ - `starting`
37
+ - `running`
38
+ - `stopping`
39
+ - `restarting`
40
+ - `crashed`
41
+
42
+ `Remote_Process_Resource` additionally uses `unreachable` for transport failure.
43
+
44
+ Each transition emits `state_change` with `{ from, to, timestamp }`.
45
+
46
+ ## Operational Signals
47
+
48
+ `Process_Resource` emits:
49
+
50
+ - `stdout` / `stderr` (line-wise)
51
+ - `exit`
52
+ - `health_check`
53
+ - `unhealthy`
54
+ - `crashed`
55
+
56
+ `Remote_Process_Resource` emits:
57
+
58
+ - `state_change`
59
+ - `unreachable`
60
+ - `recovered`
61
+
62
+ ## Failure Handling
63
+
64
+ ### Local process
65
+
66
+ Unexpected non-zero exit with `autoRestart: true` enters exponential backoff restart.
67
+
68
+ Backoff progression:
69
+
70
+ - base `restartBackoffBaseMs` (default 1000)
71
+ - doubles per attempt
72
+ - capped at 60000ms
73
+
74
+ Exceeding `maxRestarts` transitions to `crashed` and halts auto-restart.
75
+
76
+ ### Remote process
77
+
78
+ Transport failures do not map to `crashed`; they map to `unreachable`. Recovery is explicit via `recovered` event when polling succeeds again.
79
+
80
+ ## Observability Payload
81
+
82
+ `status` normalizes operational metrics:
83
+
84
+ - state
85
+ - pid (if meaningful)
86
+ - uptime
87
+ - restartCount
88
+ - lastHealthCheck
89
+ - memoryUsage
90
+ - processManager metadata
91
+
92
+ The normalized shape is essential for stable API and UI projections.
@@ -0,0 +1,47 @@
1
+ # 3. Resource Pool and Event Topology
2
+
3
+ ## Role
4
+
5
+ `Server_Resource_Pool` is the system-wide resource coordinator. It extends `Resource_Pool` and adds lifecycle orchestration plus event fan-in.
6
+
7
+ ## Lifecycle Surface
8
+
9
+ Implemented operations:
10
+
11
+ - `add(resource)` / `push(resource)`
12
+ - `remove(name)` with stop-on-remove semantics
13
+ - `start(callback)` start-all
14
+ - `stop(callback)` stop-all
15
+ - `get_resources_by_type(type)`
16
+ - `summary` getter
17
+
18
+ ## Event Fan-In
19
+
20
+ Pool-level forwarded events:
21
+
22
+ - `resource_state_change`
23
+ - `crashed`
24
+ - `unhealthy`
25
+ - `unreachable`
26
+ - `recovered`
27
+
28
+ Forwarding payload includes `resourceName` plus original event fields.
29
+
30
+ This gives a single subscription point for system telemetry.
31
+
32
+ ## Summary as Fleet Snapshot
33
+
34
+ `summary` aggregates:
35
+
36
+ - totals by state (`running`, `stopped`, `crashed`, `unreachable`, ...)
37
+ - `byType` entries with `get_abstract()` output per resource
38
+
39
+ `summary` is designed for status APIs and dashboard views.
40
+
41
+ ## Correctness Invariants
42
+
43
+ 1. removing a resource must detach forwarded listeners
44
+ 2. stop-all must tolerate mixed callback/promise resource implementations
45
+ 3. no event should lose resource identity when forwarded
46
+
47
+ `tests/server-resource-pool.test.js` and `tests/serve-resources.test.js` exercise these invariants.
@@ -0,0 +1,41 @@
1
+ # 4. SSE Publisher Semantics
2
+
3
+ ## Component
4
+
5
+ `HTTP_SSE_Publisher` is a general-purpose server-sent events publisher, separate from observable-specific transport.
6
+
7
+ ## Responsibilities
8
+
9
+ - maintain connection registry (`client_id -> response stream`)
10
+ - format protocol-correct SSE frames (`id`, `event`, `data`)
11
+ - provide `broadcast(event, data)`
12
+ - provide `send(client_id, event, data)`
13
+ - issue keepalive comments (`:keepalive`) to prevent idle timeout
14
+ - maintain bounded event history for replay
15
+ - support `Last-Event-ID` replay on reconnect
16
+
17
+ ## Delivery Semantics
18
+
19
+ - event IDs are monotonic and server-local
20
+ - replay sends events with `id > last_event_id`
21
+ - delivery is best-effort per connected client
22
+ - failed writes trigger client disconnect cleanup
23
+
24
+ ## Operational Constraints
25
+
26
+ - max client guard (`maxClients`)
27
+ - explicit `stop()` for deterministic shutdown
28
+ - keepalive timer lifecycle tied to active client count
29
+
30
+ ## Integration Contract
31
+
32
+ When `Server.serve({ events: true })` is used, pool events are bridged into SSE broadcasts. Resource state transitions become browser-consumable without client polling loops.
33
+
34
+ ## Verification
35
+
36
+ `tests/http-sse-publisher.test.js` validates:
37
+
38
+ - multi-client broadcast
39
+ - targeted delivery
40
+ - keepalive emission
41
+ - replay via `Last-Event-ID`
@@ -0,0 +1,46 @@
1
+ # 5. Serve Factory Resource Wiring
2
+
3
+ ## Objective
4
+
5
+ `Server.serve(...)` must be a single-entry composition API that can instantiate and wire:
6
+
7
+ - pages / controls
8
+ - API handlers
9
+ - resources (process or remote)
10
+ - SSE endpoint for resource events
11
+
12
+ without requiring the caller to manually compose internals.
13
+
14
+ ## Resource Configuration Forms
15
+
16
+ Accepted `resources` forms include:
17
+
18
+ - direct resource instance
19
+ - constructor function / class
20
+ - `{ class | Ctor | constructor_fn, ...spec }`
21
+ - `{ type: 'process' | 'remote', ...spec }`
22
+
23
+ Type inference fallbacks:
24
+
25
+ - `command` or `processManager` -> `Process_Resource`
26
+ - `host` or `endpoints` -> `Remote_Process_Resource`
27
+
28
+ ## Event Bridge
29
+
30
+ With `events: true`:
31
+
32
+ - `HTTP_SSE_Publisher` mounted on `/events` (or configured route)
33
+ - pool events broadcast onto SSE stream
34
+
35
+ This creates a default telemetry channel with zero extra server code.
36
+
37
+ ## Startup Ordering
38
+
39
+ 1. configure APIs, events, and resource specs
40
+ 2. wait for ready
41
+ 3. start listening
42
+ 4. start configured resources
43
+
44
+ ## Shutdown Ordering
45
+
46
+ `server.close()` triggers resource pool stop and SSE stop before closing HTTP servers. This prevents orphan resources and dangling SSE clients.
@@ -0,0 +1,48 @@
1
+ # 6. E2E Testing Methodology
2
+
3
+ ## Principle
4
+
5
+ A browser E2E test is valid only if it asserts both:
6
+
7
+ - user-visible state (DOM/control behavior)
8
+ - server truth (resource/process state, event emission)
9
+
10
+ UI-only assertions are necessary but insufficient for fullstack correctness.
11
+
12
+ ## Harness
13
+
14
+ `tests/helpers/puppeteer-e2e-harness.js` provides:
15
+
16
+ - deterministic step runner (`run_interaction_story`)
17
+ - browser probe capture (`console`, `pageerror`, request failures)
18
+ - shared page/server boot helpers
19
+ - stable interaction primitives (input event dispatch, drag)
20
+
21
+ This converts long imperative test scripts into explicit state-transition stories.
22
+
23
+ ## Story Pattern
24
+
25
+ Each step has:
26
+
27
+ - `name`
28
+ - `run(page)`
29
+ - optional `assert(page)`
30
+
31
+ Failure is annotated with `[story :: step]` to localize defects quickly.
32
+
33
+ ## Current High-Value Scenarios
34
+
35
+ 1. control interaction precision (`Date_Picker` + `Datetime_Picker`)
36
+ 2. client-driven resource lifecycle control (`start/stop/restart`)
37
+ 3. SSE propagation to browser and UI projection
38
+ 4. parity check between browser-observed state and server-side resource state
39
+
40
+ Implemented in:
41
+
42
+ - `tests/window-resource-integration.puppeteer.test.js`
43
+
44
+ ## Stability Guards
45
+
46
+ - route readiness gate before browser navigation in resource integration tests
47
+ - allowlist-based probe assertions for expected disconnect noise (`/events` abort on close)
48
+ - strict no-unexpected-console-error policy
@@ -0,0 +1,47 @@
1
+ # 7. Defect Detection and Hardening Loop
2
+
3
+ ## Goal
4
+
5
+ Maximize bug discovery rate while minimizing false confidence.
6
+
7
+ ## Loop
8
+
9
+ 1. define invariant
10
+ 2. encode invariant as automated test
11
+ 3. reproduce failure deterministically
12
+ 4. implement smallest correctness-preserving fix
13
+ 5. re-run focused suite
14
+ 6. run regression suites touching adjacent surfaces
15
+ 7. document invariant and fix rationale
16
+
17
+ ## Practical Invariants for Current Surface
18
+
19
+ ### Startup / Routing
20
+
21
+ - `serve()` must not resolve before root route availability
22
+ - startup timeout must fail explicitly, not partially start
23
+
24
+ ### Resource Management
25
+
26
+ - `stop()` semantics are idempotent for already-stopped resources
27
+ - crash vs unreachable classification must remain distinct
28
+ - process manager backend must not leak into consumer API shape
29
+
30
+ ### Eventing
31
+
32
+ - every forwarded resource event must include `resourceName`
33
+ - SSE replay must preserve event ordering by event ID
34
+
35
+ ### Browser Integration
36
+
37
+ - client action routes must be observable in captured API call log
38
+ - SSE state transitions must drive UI state within bounded time
39
+
40
+ ## Recommended Additional Test Work
41
+
42
+ 1. Add a chaos-style resource test with rapid start/stop/restart bursts and assert no deadlock.
43
+ 2. Add remote resource failure flapping test (unreachable/recovered oscillation) with threshold validation.
44
+ 3. Add SSE reconnection E2E test in browser with explicit `Last-Event-ID` continuity assertion.
45
+ 4. Add matrix tests across process manager modes (`direct`, `pm2` if available) under the same API contract assertions.
46
+
47
+ These increase confidence in concurrency and degraded-network behavior, where latent bugs usually appear.
@@ -100,7 +100,7 @@ const publisher = new HTTP_Function_Publisher({
100
100
  - Support for common image formats (JPEG, PNG, SVG, etc.)
101
101
  - Efficient streaming for large files
102
102
 
103
- ### HTTP_Observable_Publisher
103
+ ### HTTP_Observable_Publisher
104
104
 
105
105
  **Purpose:** Streams observable data to clients using Server-Sent Events (SSE).
106
106
 
@@ -190,9 +190,64 @@ data: {"tick":1,"timestamp":1234567890,"message":"Server tick #1"}
190
190
  data: {"tick":2,"timestamp":1234567891,"message":"Server tick #2"}
191
191
  ```
192
192
 
193
- **See Also:** [Observable SSE Demo](../examples/controls/15)%20window,%20observable%20SSE/) for a complete working example.
194
-
195
- ## Publisher Architecture
193
+ **See Also:** [Observable SSE Demo](../examples/controls/15)%20window,%20observable%20SSE/) for a complete working example.
194
+
195
+ ### HTTP_SSE_Publisher
196
+
197
+ **Purpose:** General-purpose Server-Sent Events publisher for manual event fan-out (not tied to an observable source).
198
+
199
+ **Key Features:**
200
+ - SSE client connection registry with `client_count`
201
+ - `broadcast(event_name, data)` for fan-out to all clients
202
+ - `send(client_id, event_name, data)` for targeted delivery
203
+ - Keepalive comments (`:keepalive`) to prevent idle proxy timeouts
204
+ - Last-Event-ID replay support for reconnecting clients
205
+ - Optional max-client limit
206
+ - Emits:
207
+ - `client_connected`
208
+ - `client_disconnected`
209
+
210
+ **Usage:**
211
+ ```javascript
212
+ const HTTP_SSE_Publisher = require('jsgui3-server/publishers/http-sse-publisher');
213
+
214
+ const sse_publisher = new HTTP_SSE_Publisher({
215
+ name: 'events',
216
+ keepaliveIntervalMs: 15000,
217
+ maxClients: 100
218
+ });
219
+
220
+ server.server_router.set_route('/events', sse_publisher, sse_publisher.handle_http);
221
+
222
+ sse_publisher.broadcast('resource_state_change', {
223
+ resourceName: 'worker_1',
224
+ from: 'running',
225
+ to: 'crashed'
226
+ });
227
+ ```
228
+
229
+ **With `Server.serve()` Auto Wiring:**
230
+ ```javascript
231
+ const server = await Server.serve({
232
+ events: true,
233
+ resources: {
234
+ worker_1: {
235
+ type: 'process',
236
+ command: process.execPath,
237
+ args: ['worker.js']
238
+ }
239
+ }
240
+ });
241
+
242
+ // SSE endpoint is available at /events by default.
243
+ ```
244
+
245
+ ### Choosing an SSE Publisher
246
+
247
+ - Use `HTTP_Observable_Publisher` when your source is an observable stream.
248
+ - Use `HTTP_SSE_Publisher` when you need explicit event push control (`broadcast`/`send`) from arbitrary server logic.
249
+
250
+ ## Publisher Architecture
196
251
 
197
252
  ### Base Publisher Class
198
253
 
@@ -17,19 +17,26 @@ Resources are JSGUI3 Server's abstraction layer for accessing data, functionalit
17
17
 
18
18
  ## Resource Types
19
19
 
20
- ### Server_Resource_Pool
21
-
22
- **Purpose:** Manages collections of resources with access control and lifecycle management.
23
-
24
- **Key Features:**
25
- - Resource registration and discovery
26
- - Access control through permission systems
27
- - Lifecycle management (start/stop/cleanup)
28
- - Resource dependency resolution
29
-
30
- **Usage:**
31
- ```javascript
32
- const pool = new Server_Resource_Pool({
20
+ ### Server_Resource_Pool
21
+
22
+ **Purpose:** Manages collections of resources with access control and lifecycle management.
23
+
24
+ **Key Features:**
25
+ - Resource registration and discovery
26
+ - Access control through permission systems
27
+ - Lifecycle management (`start()`, `stop()`, `remove(name)`)
28
+ - Type filtering with `get_resources_by_type(type)`
29
+ - Aggregated `summary` view of resource states
30
+ - Resource event forwarding:
31
+ - `resource_state_change`
32
+ - `crashed`
33
+ - `unhealthy`
34
+ - `unreachable`
35
+ - `recovered`
36
+
37
+ **Usage:**
38
+ ```javascript
39
+ const pool = new Server_Resource_Pool({
33
40
  access: {
34
41
  full: ['admin'],
35
42
  read: ['user']
@@ -37,14 +44,117 @@ const pool = new Server_Resource_Pool({
37
44
  });
38
45
 
39
46
  pool.add(myResource);
40
- pool.start((err) => {
41
- // Pool is ready
42
- });
43
- ```
44
-
45
- ### Website_Resource
46
-
47
- **Purpose:** Wraps website objects for integration with the server's resource system.
47
+ pool.start((err) => {
48
+ // Pool is ready
49
+ });
50
+
51
+ const summary = pool.summary;
52
+ const process_resources = pool.get_resources_by_type('Process_Resource');
53
+ await pool.remove('legacy_worker');
54
+ ```
55
+
56
+ ### Process_Resource
57
+
58
+ **Purpose:** Represents a local long-running process as a resource.
59
+
60
+ **Key Features:**
61
+ - State machine lifecycle:
62
+ - `stopped`
63
+ - `starting`
64
+ - `running`
65
+ - `stopping`
66
+ - `restarting`
67
+ - `crashed`
68
+ - Emits:
69
+ - `state_change`
70
+ - `stdout`
71
+ - `stderr`
72
+ - `exit`
73
+ - `health_check`
74
+ - `unhealthy`
75
+ - `crashed`
76
+ - Auto-restart with exponential backoff (when `autoRestart: true`)
77
+ - Optional health checks (`http`, `tcp`, `custom`)
78
+ - Consistent status shape for direct and PM2-backed processes
79
+
80
+ **Process Manager Modes:**
81
+ - `direct` (default): Uses `child_process.spawn()`
82
+ - `pm2`: Uses PM2 CLI commands
83
+
84
+ **PM2 Path Resolution:**
85
+ - If `processManager.pm2Path` is set, it is used
86
+ - Else `PM2_PATH` env var is used (if set)
87
+ - Else local `node_modules/.bin/pm2` is used if present
88
+ - Else `pm2` is resolved from system `PATH`
89
+
90
+ **Usage:**
91
+ ```javascript
92
+ const Process_Resource = require('jsgui3-server/resources/process-resource');
93
+
94
+ // Direct mode (default)
95
+ const worker_direct = new Process_Resource({
96
+ name: 'worker_direct',
97
+ command: process.execPath,
98
+ args: ['worker.js'],
99
+ autoRestart: true
100
+ });
101
+
102
+ // PM2 mode (pm2Path optional)
103
+ const worker_pm2 = new Process_Resource({
104
+ name: 'worker_pm2',
105
+ processManager: { type: 'pm2' },
106
+ command: process.execPath,
107
+ args: ['worker.js']
108
+ });
109
+
110
+ await worker_direct.start();
111
+ console.log(worker_direct.status);
112
+ await worker_direct.stop();
113
+ ```
114
+
115
+ ### Remote_Process_Resource
116
+
117
+ **Purpose:** Represents a remote process controlled via HTTP API while keeping a resource-compatible interface.
118
+
119
+ **Key Features:**
120
+ - Same high-level lifecycle API as `Process_Resource`:
121
+ - `start()`
122
+ - `stop()`
123
+ - `restart()`
124
+ - `status`
125
+ - `get_abstract()`
126
+ - Periodic polling of remote status endpoint
127
+ - Emits:
128
+ - `state_change`
129
+ - `unreachable`
130
+ - `recovered`
131
+ - Maintains bounded history snapshots for diagnostics
132
+
133
+ **Usage:**
134
+ ```javascript
135
+ const Remote_Process_Resource = require('jsgui3-server/resources/remote-process-resource');
136
+
137
+ const remote_worker = new Remote_Process_Resource({
138
+ name: 'remote_worker',
139
+ host: '192.168.1.100',
140
+ port: 3400,
141
+ pollIntervalMs: 30000,
142
+ httpTimeoutMs: 6000,
143
+ endpoints: {
144
+ status: '/',
145
+ start: '/api/start',
146
+ stop: '/api/stop',
147
+ health: '/api/health'
148
+ }
149
+ });
150
+
151
+ await remote_worker.start();
152
+ console.log(remote_worker.status);
153
+ ```
154
+
155
+ ### Website_Resource
156
+
157
+ **Purpose:** Wraps website objects for integration with the server's resource system.
48
158
 
49
159
  **Key Features:**
50
160
  - Website object encapsulation
@@ -110,16 +220,34 @@ class Custom_Resource extends Resource {
110
220
  }
111
221
  ```
112
222
 
113
- ### Lifecycle Management
114
-
115
- Resources follow a consistent lifecycle:
223
+ ### Lifecycle Management
224
+
225
+ Resources follow a consistent lifecycle:
116
226
 
117
227
  1. **Construction**: Resource is instantiated with configuration
118
228
  2. **Registration**: Added to resource pool
119
229
  3. **Start**: Resource becomes active and available
120
230
  4. **Usage**: Resource handles requests and operations
121
231
  5. **Stop**: Resource is deactivated
122
- 6. **Cleanup**: Resources are released
232
+ 6. **Cleanup**: Resources are released
233
+
234
+ For process resources, consumers can rely on the same lifecycle API regardless of execution mode (`direct`, `pm2`, or `remote`).
235
+
236
+ ### Unified Process Status
237
+
238
+ Both `Process_Resource` and `Remote_Process_Resource` expose a compatible `status` shape:
239
+
240
+ ```javascript
241
+ {
242
+ state: 'running',
243
+ pid: 12345,
244
+ uptime: 61520,
245
+ restartCount: 1,
246
+ lastHealthCheck: null,
247
+ memoryUsage: { rssBytes: 104857600 },
248
+ processManager: { type: 'direct' } // or 'pm2' / 'remote'
249
+ }
250
+ ```
123
251
 
124
252
  ### Configuration Patterns
125
253
 
@@ -171,18 +299,39 @@ class Database_Resource extends Resource {
171
299
  }
172
300
  ```
173
301
 
174
- ### Integration with Server
175
-
176
- ```javascript
177
- // Add to resource pool
178
- server.resource_pool.add(databaseResource);
302
+ ### Integration with Server
303
+
304
+ ```javascript
305
+ // Add to resource pool
306
+ server.resource_pool.add(databaseResource);
179
307
 
180
308
  // Access from other components
181
309
  const db = server.resource_pool.get_resource('Database_Resource');
182
- db.query('SELECT * FROM users', [], (err, results) => {
183
- // Handle results
184
- });
185
- ```
310
+ db.query('SELECT * FROM users', [], (err, results) => {
311
+ // Handle results
312
+ });
313
+ ```
314
+
315
+ With `Server.serve()` you can register resources declaratively:
316
+
317
+ ```javascript
318
+ const server = await Server.serve({
319
+ resources: {
320
+ worker_direct: {
321
+ type: 'process',
322
+ command: process.execPath,
323
+ args: ['worker.js']
324
+ },
325
+ remote_worker: {
326
+ type: 'remote',
327
+ host: '127.0.0.1',
328
+ port: 3400
329
+ },
330
+ local_cache: new In_Process_Cache_Resource({ name: 'local_cache' })
331
+ },
332
+ events: true
333
+ });
334
+ ```
186
335
 
187
336
  ## Resource Communication Patterns
188
337
 
@@ -612,4 +761,4 @@ class Logged_Resource extends Resource {
612
761
 
613
762
  ---
614
763
 
615
- This guide provides the foundation for understanding and extending the resource system. For specific resource implementations, refer to their individual source files in the `resources/` directory.
764
+ This guide provides the foundation for understanding and extending the resource system. For specific resource implementations, refer to their individual source files in the `resources/` directory.