redweb 0.12.0 → 0.13.0

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 (167) hide show
  1. package/CHANGELOG.md +166 -9
  2. package/README.md +177 -523
  3. package/bin/redweb.js +11 -20
  4. package/client.d.ts +7 -2
  5. package/config/tsconfig.json +14 -14
  6. package/contract.d.ts +45 -0
  7. package/contract.js +5 -0
  8. package/docs/ACTION_INPUT_VERIFICATION.md +96 -0
  9. package/docs/ADMISSION_TIMEOUT_VERIFICATION.md +69 -0
  10. package/docs/AGENT_ACCESS.md +35 -0
  11. package/docs/AGENT_EVALUATION.md +58 -0
  12. package/docs/AGENT_READY_ACCEPTANCE.md +763 -0
  13. package/docs/APPLICATION_RECORDER_VERIFICATION.md +50 -0
  14. package/docs/BENCHMARK_VERIFICATION.md +307 -0
  15. package/docs/BROWSER_OWNER_VERIFICATION.md +191 -0
  16. package/docs/CLI.md +116 -0
  17. package/docs/CLIENT_DEVELOPMENT.md +152 -0
  18. package/docs/CLIENT_POLISH_VERIFICATION.md +282 -0
  19. package/docs/COVERAGE_COUNTER_VALIDATION.md +109 -0
  20. package/docs/COVERAGE_SCOPE_AUDIT.md +1183 -0
  21. package/docs/DEVELOPMENT.md +79 -0
  22. package/docs/DIAGNOSTIC_COMPATIBILITY.md +76 -0
  23. package/docs/DOCUMENTATION.md +37 -0
  24. package/docs/FEEDBACK_COMMAND_VERIFICATION.md +228 -0
  25. package/docs/GETTING_STARTED.md +58 -0
  26. package/docs/JSX_PERFORMANCE_VERIFICATION.md +59 -0
  27. package/docs/LIVE_HTML.md +169 -21
  28. package/docs/LIVE_HTML_LOAD_VERIFICATION.md +98 -0
  29. package/docs/MIGRATION.md +28 -0
  30. package/docs/MULTIPLAYER_OPERATIONS.md +26 -4
  31. package/docs/ORIGINAL_RECOVERY_VERIFICATION.md +100 -0
  32. package/docs/PACKAGED_EXAMPLE_VERIFICATION.md +126 -0
  33. package/docs/POLISH_RELEASE_CHECKPOINT.md +91 -0
  34. package/docs/PROCESS_CLEANUP_OBSERVATION.md +61 -0
  35. package/docs/PROCESS_REAPING_VERIFICATION.md +30 -0
  36. package/docs/PRODUCTION_READINESS.md +11 -2
  37. package/docs/RECOVERY_CLIENT_HEAP.md +201 -0
  38. package/docs/RECOVERY_CODE_ATTRIBUTION.md +174 -0
  39. package/docs/RECOVERY_CODE_CENSUS.md +158 -0
  40. package/docs/RECOVERY_COMPARISON.md +103 -0
  41. package/docs/RECOVERY_DEOPTIMIZATION.md +169 -0
  42. package/docs/RECOVERY_FOLLOWUP_SPIKE.md +147 -0
  43. package/docs/RECOVERY_INVESTIGATION.md +229 -0
  44. package/docs/RECOVERY_RUNTIME_CONTROLS.md +181 -0
  45. package/docs/RELEASE_TRUST.md +58 -0
  46. package/docs/ROOM_AUTHORIZATION.md +49 -0
  47. package/docs/RUNTIME_DIAGNOSTICS.md +78 -0
  48. package/docs/SERVER_RECOVERY_CANDIDATE.md +185 -0
  49. package/docs/SOAK_ROTATION_OBSERVATION.md +160 -0
  50. package/docs/SOAK_VERIFICATION.md +154 -0
  51. package/docs/SOCKET_CONTRACTS.md +39 -0
  52. package/docs/SPLIT_RECOVERY_COVERAGE.md +83 -0
  53. package/docs/SPLIT_RECOVERY_ERROR_HANDLING.md +67 -0
  54. package/docs/STARTER_COORDINATOR_VERIFICATION.md +112 -0
  55. package/docs/STARTER_LIFECYCLE_VERIFICATION.md +75 -0
  56. package/docs/STARTER_REPORT_RETENTION.md +73 -0
  57. package/docs/VERIFICATION_EVIDENCE.md +2 -0
  58. package/docs/generated.json +2154 -0
  59. package/docs/guides/chatroom.md +27 -0
  60. package/docs/guides/http-websocket.md +28 -0
  61. package/docs/guides/jsx-without-react.md +26 -0
  62. package/docs/guides/realtime-dashboard.md +29 -0
  63. package/docs/guides/typed-websockets.md +26 -0
  64. package/docs/reference.json +1207 -0
  65. package/docs/snippets/room-access.tsx +51 -0
  66. package/docs/topics.json +21 -0
  67. package/examples/live-html/chatroom.js +207 -268
  68. package/examples/live-html/chatroom.tsx +167 -0
  69. package/examples/live-html/jsx-page.js +1 -1
  70. package/examples/live-html/jsx-page.tsx +1 -1
  71. package/examples/live-html/tsconfig.json +8 -7
  72. package/index.d.ts +170 -45
  73. package/index.js +2 -0
  74. package/jsx-dev-runtime.js +2 -2
  75. package/jsx-runtime.d.ts +7 -2
  76. package/package.json +88 -7
  77. package/recipes/add/artifact.test.cjs +57 -0
  78. package/recipes/add/live.tsx +18 -0
  79. package/recipes/add/socket-route.ts +24 -0
  80. package/recipes/chat/README.md +22 -0
  81. package/recipes/chat/app.test.cjs +105 -0
  82. package/recipes/chat/app.tsx +9 -0
  83. package/recipes/dashboard/README.md +43 -0
  84. package/recipes/dashboard/admin.ts +21 -0
  85. package/recipes/dashboard/app.css +16 -0
  86. package/recipes/dashboard/app.test.cjs +450 -0
  87. package/recipes/dashboard/app.tsx +86 -0
  88. package/recipes/dashboard/auth.ts +80 -0
  89. package/recipes/dashboard/cards.tsx +102 -0
  90. package/recipes/dashboard/rate-window.test.cjs +17 -0
  91. package/recipes/dashboard/store.ts +120 -0
  92. package/recipes/http-ws/README.md +11 -0
  93. package/recipes/http-ws/app.test.cjs +92 -0
  94. package/recipes/http-ws/app.tsx +36 -0
  95. package/recipes/realtime/README.md +8 -0
  96. package/recipes/realtime/app.test.cjs +15 -0
  97. package/recipes/realtime/app.tsx +28 -0
  98. package/recipes/shared/README.md +40 -0
  99. package/recipes/shared/app.css +8 -0
  100. package/recipes/shared/copy-assets.cjs +8 -0
  101. package/recipes/shared/network.cjs +59 -0
  102. package/recipes/shared/run-app.test.cjs +158 -0
  103. package/recipes/shared/run-app.ts +50 -0
  104. package/recipes/site/README.md +4 -0
  105. package/recipes/site/app.test.cjs +19 -0
  106. package/recipes/site/app.tsx +25 -0
  107. package/recipes/socket/README.md +39 -0
  108. package/recipes/socket/app.test.cjs +85 -0
  109. package/recipes/socket/app.tsx +30 -0
  110. package/recipes/socket/contract.ts +12 -0
  111. package/recipes/socket/handlers.ts +40 -0
  112. package/src/OwnedServerLifecycle.js +66 -0
  113. package/src/access/AccessPolicy.js +37 -0
  114. package/src/access/AuthenticationFailure.js +13 -0
  115. package/src/access/RequestFailure.js +33 -0
  116. package/src/access/failure-codes.json +25 -0
  117. package/src/async/BoundedOperation.js +62 -0
  118. package/src/cli/ActionReferences.js +193 -0
  119. package/src/cli/AdditionLayout.js +140 -0
  120. package/src/cli/FilePlan.js +94 -0
  121. package/src/cli/ProjectAddition.js +60 -0
  122. package/src/cli/ProjectConfig.js +26 -0
  123. package/src/cli/ProjectDoctor.js +112 -0
  124. package/src/cli/ProjectInitializer.js +20 -30
  125. package/src/cli/SourceInspector.js +207 -0
  126. package/src/cli/StaticSource.js +192 -0
  127. package/src/cli/arguments.js +62 -0
  128. package/src/cli/formatCommand.js +10 -0
  129. package/src/cli/run.js +57 -0
  130. package/src/cli/templates.js +86 -87
  131. package/src/context/RequestSnapshot.js +41 -0
  132. package/src/dataProperty.js +11 -0
  133. package/src/development/DevelopmentPageManager.js +48 -0
  134. package/src/development/Inspection.js +104 -0
  135. package/src/development/ObservedRenderer.js +42 -0
  136. package/src/development/description.js +35 -0
  137. package/src/development/loopbackRequest.js +27 -0
  138. package/src/development/refreshBrowser.js +96 -0
  139. package/src/development/refreshStyles.js +9 -0
  140. package/src/development/settings.js +17 -0
  141. package/src/docs/Documentation.js +182 -0
  142. package/src/htmx/ActionDefinition.js +44 -0
  143. package/src/htmx/Jsx.js +24 -8
  144. package/src/htmx/LiveHtmlServer.js +41 -19
  145. package/src/htmx/LivePage.js +63 -13
  146. package/src/htmx/PageIdentity.js +32 -0
  147. package/src/htmx/PageLifetime.js +37 -0
  148. package/src/htmx/PageManager.js +203 -74
  149. package/src/htmx/ReactiveRenderer.js +241 -0
  150. package/src/htmx/StaticExporter.js +1 -1
  151. package/src/htmx/TemplateRenderer.js +13 -7
  152. package/src/htmx/browserRuntime.js +2 -93
  153. package/src/htmx/metadata.js +19 -7
  154. package/src/validation/ActionInputError.js +12 -0
  155. package/src/validation/SchemaValidator.js +38 -0
  156. package/src/ws/AdmissionPolicy.js +24 -23
  157. package/src/ws/BaseSocketServer.js +53 -38
  158. package/src/ws/ContractValidationError.js +12 -0
  159. package/src/ws/HeartbeatMonitor.js +19 -7
  160. package/src/ws/ProtocolPolicy.js +1 -1
  161. package/src/ws/RoomAccess.js +82 -0
  162. package/src/ws/RoomRegistry.js +56 -6
  163. package/src/ws/RouteRuntime.js +56 -10
  164. package/src/ws/SocketContract.js +112 -0
  165. package/src/ws/SocketRoute.js +18 -0
  166. package/src/ws/protocol-schema.json +6 -1
  167. package/examples/live-html/chatroom.ts +0 -217
@@ -0,0 +1,79 @@
1
+ # Development refresh and inspection
2
+
3
+ This API is **unreleased**. Use the matching packed candidate rather than assuming it exists in the published package.
4
+
5
+ ## Browser refresh
6
+
7
+ The generated `npm run dev` command enables browser refresh while rebuilding and restarting your application. No extra application code is needed. For an existing Live HTML application, enable it explicitly:
8
+
9
+ ```ts
10
+ const app = start(CounterPage, { development: { refresh: true } });
11
+ ```
12
+
13
+ Alternatively, set `REDWEB_DEV_REFRESH=1` only for your development process. Explicit `development: { refresh: false }` overrides that environment flag. Setting `NODE_ENV=development` alone enables neither refresh nor inspection. Both features are refused at construction under `NODE_ENV=production`; changing environment variables after construction is not a mode switch. `npm start` does not set the refresh flag. Keep it out of production environments.
14
+
15
+ On direct loopback access, the initial HTML embeds the serving process's revision. The browser polls the same listener sequentially, with a two-second request deadline and one second between completed attempts. Only a valid, different revision triggers refresh. Failed builds, unavailable listeners, malformed responses and redirects do not cause reload loops. A restart before the external script finishes loading is still detected against the revision embedded in the original document.
16
+
17
+ Clean pages reload automatically after a new revision appears. The edit guard conservatively keeps the current document if it observes input/change events, sees differing form defaults when it starts, encounters an editable element with focus, or finds contenteditable content. A native, keyboard-operable notice offers **Reload and discard drafts**. Ordinary untouched selects are compared against the browser's actual reset defaults, not simply their `selected` attributes. Once confirmation is required, resetting or submitting a form does not silently permit automatic reload.
18
+
19
+ This is not autosave or a precise unsaved-change detector. False positives are intentional; custom editors or programmatic changes without input/change events may not be detected. The helper does not persist or transmit form contents, write browser storage, replay actions, or restore files/passwords after reload. It keeps the current DOM while waiting for your decision. Manual navigation, browser termination, and confirmed reload can discard drafts.
20
+
21
+ The notice uses a shadow root so ordinary reactive root updates preserve it and the application controls' existing focus/draft behavior. Its script, stylesheet and revision fetch are same-origin external resources; your CSP must allow those resources. Navigation away stops polling. History restoration resumes it, including back-forward-cache restoration where the browser supports and chooses it.
22
+
23
+ ### Connections and server state
24
+
25
+ Keeping the old document does **not** make its old page token/session valid on a replacement process. Existing reconnect rules still apply to a temporary connection outage on the same server. A process restart resets in-memory page/chat/counter state; persistent application data remains the application's responsibility. Actions in flight may have uncertain outcomes. Refresh does not retry them, guarantee completion or migrate state. Reload creates a new page session.
26
+
27
+ ### Access and resource boundaries
28
+
29
+ Refresh is for direct `localhost`, literal `127.x.x.x`, or `[::1]` URLs at the listener's actual port. It verifies the actual loopback peer, Host, any supplied Origin, and Fetch Metadata. It does not trust forwarding headers or support custom hostnames, tunnels or reverse-proxy origins. Rejected requests receive no refresh bootstrap; this restriction does not make the rest of your application private. An application can still bind publicly unless you separately set `bind`.
30
+
31
+ Enabled refresh reserves `/__redweb/development`, `/__redweb/development.js` and `/__redweb/development.css`. They reveal only a boot revision, fixed client code and styling—not inspection snapshots, application state or compiler output. Responses and decorated HTML are no-store. There is no extra listener or server timer. Served `live: false` pages support refresh without a live socket client; `exportStatic()` output remains script-free and never enables it from the environment. Raw `SocketServer`/`SecureSocketServer` do not accept the HTML `refresh` option.
32
+
33
+ The injected `rw-dev-refresh` element and `__redweb_dev` ID belong to this helper; do not reuse them in application markup. The repository's `npm run verify:development:browser` gate runs actual generated watchers and Chromium against real HTTP/WebSocket listeners, including edited-document confirmation and failed-build recovery. CI runs it separately from the production browser regression gate.
34
+
35
+ ## Inspection
36
+
37
+ Enable inspection explicitly when starting a development application:
38
+
39
+ ```ts
40
+ const app = start(CounterPage, {
41
+ port: 8181,
42
+ development: { inspect: true },
43
+ });
44
+
45
+ // Read this in your development code, debugger, or integration test.
46
+ console.dir(app.inspect(), { depth: null });
47
+ ```
48
+
49
+ `SocketServer` and `SecureSocketServer` accept the same option and expose the same `inspect()` method. Without the option, `inspect()` returns `null`. Merely setting `NODE_ENV=development` does not enable inspection. Explicitly enabling it while `NODE_ENV=production` throws before routes or listeners are attached. The environment check occurs at construction; changing environment variables afterward is not a runtime mode switch.
50
+
51
+ Inspection itself is an in-process, read-only API. It does not create an HTTP/debugging route, listener, browser script, background timer, or automatic logger; browser refresh is a separate option and never exposes inspection data. Do not expose inspection results through an application endpoint in production. Your existing `redweb doctor --json` command remains the source/configuration checker; it does not inspect a running process.
52
+
53
+ ## What the snapshot means
54
+
55
+ `inspect()` returns immutable, versioned JSON-compatible data:
56
+
57
+ - `pages.registrations`: configured route paths, live/shared flags, class names, decorated action/state names, and descriptions of currently available owned components. It never constructs a page to discover its members. Standard decorator metadata and component fields may not exist before first construction, so `instanceMetadata: "unobserved"` means an incomplete inventory, not “this page has no actions.” Static or expired pages can have no current instance even when class metadata was observed previously.
58
+ - `pages.connections`: separate counts for pending HTTP-created sessions, connected sockets, closing transports or disconnect hooks in progress (`detaching`), and disconnected sessions retained for reconnect. An attached socket that is no longer open is not yet a retained/reconnectable session. Shared pages appear once in each registration's instance list even when several visitors use them.
59
+ - `pages.sessions`: bounded per-render descriptions using inspector-local numeric IDs. These are not page tokens, credentials, principal IDs or socket IDs. A reconnect to the same retained page session keeps its renderer ID.
60
+ - `sockets.routes`: registered socket paths and handler names, registered connection counts, draining status, and room/session counts. Runtime-added routes and handlers appear on the next read. `pendingUpgrades` counts currently tracked handshakes. Room names, session identifiers and stored data are omitted. A registered raw connection is not a promise that every transport is currently open; lifecycle cleanup may be in progress.
61
+ - `history`: the latest reactive state invalidations and flush attempts. A state invalidation lists the member/component name and affected render-owner IDs. An empty affected-owner list means no current reactive owner read that member. Several invalidations can be batched into one flush.
62
+
63
+ Page-session and underlying socket counts describe overlapping resources—do not add them together as independent visitors. Counts remain available independently of truncated detail lists. A description failure yields `available: false` for its section without reflecting exception text.
64
+
65
+ ## Render history is not delivery tracing
66
+
67
+ `flush-started` reports whether the attempt is a reconnect/attach snapshot and which owners were dirty. `flush-completed`, `flush-superseded`, and `flush-failed` describe that attempt, with elapsed milliseconds. Completion can mean unchanged HTML, no transport write, or a transport write that the peer did not receive. It is **not** a delivery acknowledgement. Supersession means a disconnect, disposal or generation change made the attempt obsolete.
68
+
69
+ History does not attribute an invalidation to a particular action: timers, services and application code can also assign state. It does not retain action arguments, state values, HTML, request headers, cookies, query parameters, identities, socket contexts, or exception messages. It does not serialize getters or call action/render/lifecycle callbacks to produce a snapshot. Application accessors replacing declaration fields are skipped; standard action metadata excludes replaced accessor methods. This is not a security sandbox against hostile JavaScript Proxies or global monkey-patching.
70
+
71
+ The history observes the reactive TSX renderer's connected update path, starting with socket attachment. Initial HTTP rendering, static output, changes with no connected reactive renderer, and nonreactive template `redweb:state` transport messages are not traced. `pages.sessions[].reactive` distinguishes those sessions. Existing runtime failure diagnostics and application tests remain necessary.
72
+
73
+ ## Bounds and overhead
74
+
75
+ History retains at most 256 entries per inspected server and only primitive metadata; each event's owner list retains at most 100 names. Current page/socket description lists retain at most 100 items each and share a separate 1,000-item budget per snapshot. Lists include `total` and `truncated`. Labels are limited to 128 UTF-16 code units. Names and route paths are application-defined declarations: do not put secrets in them. The local history's `total` is its sequence counter, including any contained recording failure; retained entries may therefore have gaps.
76
+
77
+ Inspection selects a specialized renderer once for the enabled server. Ordinary reactive invalidation, flush, and socket-message paths have no inspector callbacks or added inspection branches. Disabled servers retain the original renderer class. The only ordinary rendering seam is renderer-class selection when a page session is constructed. Enabled inspection deliberately does extra metadata work and allocations; its timings are diagnostic observations, not production benchmarks.
78
+
79
+ Shutdown removes page sessions and connections through the existing lifecycle. The bounded primitive history remains readable while you retain the server object; it does not keep disposed page instances alive. The inspector's local ID table uses weak keys.
@@ -0,0 +1,76 @@
1
+ # Diagnostic runtime compatibility
2
+
3
+ This increment fixes private verification tools, not Redweb's public runtime or
4
+ the recovery acceptance contract. The existing recovery workloads, deadlines,
5
+ thresholds and historical evidence remain unchanged. It does not establish
6
+ release readiness.
7
+
8
+ ## Confirmed causes and narrow fixes
9
+
10
+ - Node 18.20.8 and 20.20.2 reject `--trace-flush-code`. Trace workers now use
11
+ `--trace-flush-bytecode` on those major versions and retain the modern flag on
12
+ Node 22/24. These traces have different scope; bytecode flushing is not proof
13
+ of all code flushing. Reports retain the actual flags and runtime identity.
14
+ - Node 18 lacks `--no-log-source-position`. Omitting it emitted prohibited
15
+ source-position/feedback records in a real test. Code/deoptimization logging
16
+ therefore rejects Node 18 before either worker or an output directory starts;
17
+ no privacy assertion is weakened. Other diagnostic modes remain available.
18
+ - Legacy V8 heap-snapshot streams never completed their destroy callback,
19
+ causing an actual Node 18 capture timeout. Node's upstream fix is documented in
20
+ [PR #58846](https://github.com/nodejs/node/pull/58846). The capture owner uses
21
+ `Readable.wrap` only when the snapshot's existing `_destroy` signature has no
22
+ callback parameters; modern streams retain their original pipeline. This is
23
+ read-only compatibility with the known implementations, not a guaranteed
24
+ future capability API. A major-version cutoff would miss older Node 20/22/24
25
+ releases before that upstream fix.
26
+ - The output-limit regression now snapshots a small owned child instead of the
27
+ entire Jest process. It still verifies the actual one-byte limit, poisoned
28
+ session and exclusive file creation without mocks or increased deadlines.
29
+ This bounds the test workload; it is not proof of the cause of every prior CI
30
+ timeout.
31
+
32
+ The 64 MiB file limit does not bound V8's synchronous snapshot-generation memory
33
+ or pause. Existing process ownership/deadlines remain necessary. Heap graphs
34
+ remain private local artifacts and are not committed or uploaded.
35
+
36
+ ## Verification
37
+
38
+ Full local regression at `daacdac` passed `npm test -- --runInBand --silent`:
39
+ 863 tests across 83 suites in 419.852 seconds, including pretest/type checks.
40
+ Instrumented library coverage is all-four 100%: 5,445 statements, 4,044 branches,
41
+ 978 functions and 4,464 lines. The local `coverage/coverage-final.json` SHA-256 is
42
+ `546711819397028d98d5a45f6983919ec45a04231d985b31b0b671743e0b796e`.
43
+ This library scope is separate from the diagnostic capture scope below and does
44
+ not imply all repository tooling/browser sources are covered. The documentation
45
+ catalogue was regenerated and checked; hosted final-head CI remains pending.
46
+
47
+ Sequential focused Jest runs passed 34 tests across four suites on Windows:
48
+ Node 18.20.8, 20.20.2 and 22.21.0. Suites cover flag units, real diagnostic workers,
49
+ native code-log privacy/preflight rejection, deoptimization parsing boundaries,
50
+ and real network heap captures. The Node 18/20 Jest runs preceded the final
51
+ signature refinement with equivalent paths; Node 22 ran the final source.
52
+
53
+ The final source additionally passed eight native tests on Node 18 and eight on
54
+ Node 22, sequentially, combining original-source V8 coverage for legacy and
55
+ modern capture paths. Only `scripts/diagnostics/ClientHeapCapture.cjs` is claimed
56
+ at 100% here: 56 statements/lines, 17 branches, three functions. This is not
57
+ whole-diagnostic or whole-repository coverage. Node 24 execution of this change
58
+ remains a hosted CI gate, not a local result.
59
+
60
+ - Capture source SHA-256:
61
+ `949e63376b402b7202b3a23e8bc0c381681766c79091b9a9c82156235048ae38`.
62
+ - Local report: `coverage/compatibility-capture-runtime/coverage-final.json`.
63
+ - Report SHA-256:
64
+ `d166288f7cce3d35441f6f2e1457a331631cf082383665660493b6c5b514521c`.
65
+ - All matching native report ranges fit the same 2,553-character original source;
66
+ Jest-wrapped source was not merged into this coverage result.
67
+
68
+ Rejected candidates are not passes: omitting the privacy flag leaked forbidden
69
+ records; wrapping every snapshot caused a Node 22 premature-close failure;
70
+ earlier concurrent attempts also timed out. Final focused runs were sequential.
71
+ No recovery gate was retried or relaxed to qualify these changes. The senior
72
+ critic independently inspected the final code and hashes and gave scoped
73
+ approval, explicitly not release approval.
74
+
75
+ The separate recovery acceptance decision remains documented in
76
+ `docs/RECOVERY_COMPARISON.md` and `docs/RECOVERY_FOLLOWUP_SPIKE.md`.
@@ -0,0 +1,37 @@
1
+ # Maintaining executable documentation
2
+
3
+ Edit the canonical Markdown guides listed in `docs/topics.json`, API/article/example metadata in `docs/reference.json`, or the maintained applications in `recipes/` and `examples/live-html/`. Do not edit `docs/generated.json` by hand. Reference entries can select a recipe file or a maintained snippet under `docs/snippets/` instead of duplicating source code.
4
+
5
+ `npm run generate:docs` builds a deterministic, version-labelled catalogue containing topic Markdown, full public TypeScript declarations, a compact `llms.txt`, and complete recipe files. Recipe files come from the exact same `projectFiles()` implementation used by `redweb init`. Chat continues to reuse the canonical component example. Markdown code fences expand when necessary so nested Markdown/readme examples remain intact.
6
+
7
+ The README's marked realtime and HTTP/WebSocket application blocks are generated from those same recipes. Its setup block uses the same channel-aware commands as recipe pages, including the version notice, directory change, and matching artifact for both initialization and installation. Other README prose is preserved. Package/test preflights reject stale, missing or duplicate blocks.
8
+
9
+ The generated catalogue is included in the npm tarball but is not loaded by the HTTP/WebSocket runtime. A site or a separate read-only documentation adapter can consume the same JSON. Each page has a stable ID, versioned Markdown URL, source path, summary, and SHA-256 content hash. Recipe pages also contain their complete file lists. Hashes identify content, not package authenticity or signatures.
10
+
11
+ Task-oriented guides live under `docs/guides/` and are registered in `docs/topics.json` with a `recipe: { template, file }` selection. Their walkthroughs explain the task; generation appends the same version-correct setup and exact selected starter source used by the initializer/API examples, plus a link to the complete recipe. Guide pages do not duplicate recipe `files` collections. The site selects current-version guides for its task cards and resolves historical guides and file downloads against their own catalogue version. Dashboard setup provisions an explicit account after installation and before development starts.
12
+
13
+ API articles retain their ELI5 explanations, practical examples, walkthroughs, methods, and production cautions. Each API section and capability example also has an individual Markdown page. The shared HTTP/WebSocket example comes from the complete `http-ws` starter, exercised against both the checkout and packed package; it uses one listener with separate route and message-handler classes and the shared entrypoint lifecycle helper. Historical release snapshots retain their original source/examples.
14
+
15
+ ## Version boundaries
16
+
17
+ Development output uses `/docs/reference/unreleased/`. Its package metadata version is informational: it does not claim that the published package of that version contains new behavior. Development recipe commands explicitly require the matching tarball for both initialization and installation.
18
+
19
+ For a release, first update the package version and move the pending changelog entries into that version's section. Run `npm run generate:docs -- --release`. This creates a snapshot in `docs/releases/<version>.json` and updates the current catalogue. An existing release snapshot cannot be overwritten with different content. Commit the snapshot with the release. These commands do not publish npm or deploy the website.
20
+
21
+ `npm test` and `npm pack` check generated content for drift. `--check` preserves the existing catalogue's channel rather than silently turning release documentation into development documentation. Run `npm run generate:docs` explicitly to start documenting the next unreleased increment.
22
+
23
+ ## Verification scope
24
+
25
+ Unit tests check determinism, version labels, links, hashes, fences, and identity with the initializer's file plan. Real integration tests extract application files from the actual Markdown code fences, compile them, execute the shipped HTTP/WebSocket tests, remove source from the deployed location, and rerun those tests. The packed-package gate repeats this against the extracted tarball, including checking that packed docs match packed source.
26
+
27
+ Complete recipe pages are executable programs. Topic/API snippets remain explanatory and are not all independently runnable; public declarations are separately covered by the package's type-test suites. Do not claim that every illustrative snippet or generated browser branch is covered by library coverage metrics.
28
+
29
+ Website export, published-version availability, read-only MCP access, and fresh-agent benchmarks have separate acceptance gates. Generating this catalogue alone does not complete those requirements or guarantee agent discovery.
30
+
31
+ The optional MCP integration reads this same catalogue rather than regenerating or duplicating documentation. See [agent access setup and limits](AGENT_ACCESS.md); its dependencies and tests are separate from the normal library runtime.
32
+
33
+ ## Website consumer
34
+
35
+ The separate Redweb site imports this catalogue through `npm run sync:docs -- /absolute/path/to/redweb`; after a matching release is installed, `npm run sync:docs` reads that package by default. It does not import application runtime code from the development checkout. Its committed generated content allows independent clean-checkout builds.
36
+
37
+ The site derives its existing API articles, examples, homepage snippets, versioned guides, raw recipe downloads, and agent-readable indexes from this source. Release snapshots are retained across imports rather than replaced by the newest package's snapshot set. Import preflight and atomic site-build replacement are separate safeguards. Website tests exercise real imports, builds, and HTTP requests for current and historical versions; publishing npm and deploying hosting remain separate actions.
@@ -0,0 +1,228 @@
1
+ # Browser-command deadlines for feedback verification
2
+
3
+ Independent review identified unbounded command promises when the feedback driver
4
+ received a raw debugging connection. A local native probe acquired a genuine
5
+ Chromium tab, terminated its debugging socket, waited for its real close event,
6
+ and returned the unchanged tab to the driver. After 20 seconds the verifier was
7
+ still pending and its actual Redweb server was still listening. The probe then
8
+ explicitly rescued and closed its resources. No browser/server methods or timers
9
+ were replaced. This is a verifier hang, not an application WebSocket defect.
10
+
11
+ Pre-fix helper SHA-256:
12
+ `3174a331f8848c4efdff3a4aebdb7feddd4efd3dcb5f5caaedaf7b5cbaef4b76`.
13
+ The retained diagnostic transcription `coverage/feedback-disconnect-before.json`
14
+ has SHA-256 `8e5c442e9a00ad352d1b4c0c4b1175d2c6ae14a701dcb9d814f1c05546d5a0c4`.
15
+
16
+ ## Shared command adapter, unchanged ownership
17
+
18
+ `browserCommands` bounds evaluation and protocol commands to 15 seconds. The raw
19
+ tab is registered with its caller before the adapter is created. The adapter keeps
20
+ the same socket and delegates through the original method receiver without mutating
21
+ the tab. The coverage caller's duplicate adapter was removed; its separately bounded
22
+ startup validation and final coverage collection remain. The installed-package
23
+ harness copies the same helper, increasing its input inventory from 25 to 26 files.
24
+
25
+ These command deadlines allow the feedback driver's existing `finally` to shut down
26
+ its server after a disconnected debugging transport. They do not cancel an underlying
27
+ command or establish page-acquisition ownership. In particular, raw `openPage`
28
+ acquisition from the frozen launcher remains unbounded. No unowned timeout race was
29
+ added there, and no complete-acquisition claim is made. The separate native tests
30
+ below now measure all authored feedback-driver paths; complete coverage is not a
31
+ claim that every underlying acquisition operation is bounded.
32
+
33
+ ## Feedback coverage milestone (`9897924`)
34
+
35
+ At this checkpoint, `npm run verify:feedback:commands` combined nine explicit command-boundary units
36
+ (including labelled fake-clock checks) with six real integration cases. The closed
37
+ Chromium connection case uses actual sockets/timers and checks that the server is no longer
38
+ listening and has no shared pages **before** rescue cleanup runs. The other three
39
+ cases retain real page-disposal/setup failure coverage. Production shutdown wraps
40
+ disposal rejections in `AggregateError`; this work does not claim a native falsy
41
+ shutdown bug.
42
+
43
+ Two additional Chromium cases run the complete acceptance driver. The successful
44
+ case omits optional callbacks and verifies that its real HTTP listener refuses a
45
+ connection after return. The cleanup-only failure registers an actual decorated
46
+ page whose disposal throws, and verifies error identity, empty shared-page storage,
47
+ listener closure and resolution of an actual pending fixture waiter. No browser,
48
+ server or transport API is replaced. These cases reuse the existing workspace and
49
+ page owners, with a 180-second driver watchdog, independent browser cleanup and a
50
+ bounded drain of the original driver promise. Each has a 360-second outer budget.
51
+
52
+ That 15-test/four-suite scope passed in 20.765 seconds with all-four 100%
53
+ coverage: 176 statements, nine branches, 14 functions and 162 lines. The adapter
54
+ accounts for five statements/lines, three functions and zero branches; the complete
55
+ feedback driver accounts for 171 statements, nine branches, 11 functions and 157
56
+ lines. Browser coordinator coverage remains separate. The closed-connection test allows 180 seconds
57
+ for bounded launch, 60-second supervision and independent cleanup. Existing failure
58
+ tests now allow 45 seconds instead of inheriting five while server shutdown can
59
+ take 15. Uncertain browser shutdown retains its workspace and independently releases
60
+ local pipe/reference handles; those releases are not proof of process termination.
61
+ That checkpoint allowed 20 minutes in CI and retained coverage for 30 days.
62
+
63
+ | Exact source | SHA-256 |
64
+ | --- | --- |
65
+ | `scripts/lib/browserCommands.js` | `cc6d26f257a20c8549225772d379a2091288a55719c7aa2f63dc151ce5a1fc76` |
66
+ | `scripts/lib/verify-action-feedback.js` | `8f35661e324f8dd962f80165800cc15e491b9c9a0f0d3261470e9162df6dd028` |
67
+ | `scripts/verify-browser-coverage.js` | `96325de65161f7d68c6da3ea85700e6fccb85b45ddb34c7645cdf5eaeefe8e06` |
68
+ | `scripts/lib/PackedBrowserHarness.js` | `fd9cf313775b77fbebd73a0097efe0c8f5ec830b17f370451f2ed4f3cae39855` |
69
+
70
+ That checkpoint's report `coverage/browser-commands/coverage-final.json`
71
+ has SHA-256 `5c04776ecc36f5df1753c94afa388d3b509c54425f179a4454006261dec7f18b`,
72
+ matching the initial expanded-scope report under `coverage/feedback-driver/`.
73
+ The critic approved the corrected native tests after requiring exact error leaves,
74
+ an actual waiter promise and preservation of late driver failures. Pretest,
75
+ generated-documentation and all three type configurations also pass.
76
+
77
+ ## Refresh command reuse follow-up
78
+
79
+ The same native disconnected-DevTools test now also runs the actual refresh
80
+ control driver against its real revision peer. Before correction, it remained
81
+ pending until the 60-second supervisory watchdog fired; the expected command
82
+ deadline was never reached. No browser/server/timer method was replaced.
83
+ Pre-fix refresh-control source SHA-256:
84
+ `0573ef0f8f589f49cc64849285ed61967869e8085dd344246bf8566fca2a8275`.
85
+
86
+ Generated-app refresh and its shared control driver now reuse `browserCommands`.
87
+ Raw tabs are registered before wrapping. A private WeakSet recognizes already
88
+ bounded facades, so the coverage caller can reuse the same adapter without
89
+ stacking timers or keeping tabs alive. Its duplicate inline adapter was removed;
90
+ coverage cleanup still receives bounded commands, and generated-app cleanup
91
+ continues to use bounded DevTools HTTP requests.
92
+
93
+ The maintained command now passes 17 tests/four suites in 36.407 seconds: ten
94
+ explicit command-boundary units and seven real integration cases. Both disconnected
95
+ native paths reach their 15-second command deadline and verify actual listener
96
+ cleanup before rescue. The refresh test also verifies empty pending/script sets.
97
+ All-four coverage of the adapter and complete feedback driver remains 100%:
98
+ 181 statements, 11 branches, 14 functions and 166 lines. The adapter contributes
99
+ 10 statements, two branches, three functions and nine lines. This is not complete
100
+ direct coverage of refresh helpers or either browser coordinator.
101
+
102
+ Current report `coverage/browser-commands/coverage-final.json` SHA-256:
103
+ `5a4be585d836f0510a4ec80c0fef0a32dbbff3e41330af19af1f158709b45e21`.
104
+ CI allows 25 minutes for the added native case and all declared failure budgets;
105
+ individual command deadlines are unchanged. The critic approved the shared
106
+ wrapper, raw ownership ordering, bounded cleanup and expanded budget.
107
+
108
+ | Corrected source | SHA-256 |
109
+ | --- | --- |
110
+ | `scripts/lib/browserCommands.js` | `bb2d1de242289f543680e97493cb04fe99ae2f35c89b4e276e1862a1e21336e3` |
111
+ | `scripts/lib/verify-refresh-controls.js` | `a05a1145e636a8e4f7750fff3dd8036aab54fa3ee22bbb6d8bdb068dbca104b2` |
112
+ | `scripts/lib/verify-refresh-coverage.js` | `7062f23e3fcac0273b2c9d41858ad7e95dd519daaa0d70a60e10695930f1d6e9` |
113
+ | `scripts/verify-development-refresh-browser.js` | `ccb01383ef684cb59bc07bcd87e576e7fb08d2c734abfabdb2c047d957449e0e` |
114
+
115
+ The unchanged native runtime/refresh scopes also pass: 426/262/64/351 and
116
+ 82/44/12/71 statements/branches/functions/lines, respectively. Actual case
117
+ inventories match between plain/instrumented runs; back-forward-cache restoration
118
+ was observed. Runtime run: `f5943d26-64ae-4ea1-b754-c917996ccb8b`; refresh run:
119
+ `732f7c31-bfeb-402d-bf2c-4446fb5c26d6`. No public runtime, frozen helper or
120
+ acceptance threshold changed. Raw page acquisition remains a separate open
121
+ boundary; command deadlines do not cancel its underlying operations.
122
+
123
+ The corresponding runtime/refresh report SHA-256 values are
124
+ `f0067f98198760a5ed07b5536c6ae9a0b8253b65e75e1b998f80dc5c57a42b86`
125
+ and `7392a9a0d69d40bff5cfdf85ae1e21b6699ca60c2f485c38afc8948cdbbdb418`.
126
+ The complete generated-app development gate also passes real TypeScript/CSS
127
+ rebuilds, failed-build recovery, draft/focus retention, explicit discard and state
128
+ reset, plus the shared outage/recovery and input guards. Actual back-forward-cache
129
+ restoration was observed. Pretest, all three type configurations and the four
130
+ documentation units pass for this increment.
131
+
132
+ The refreshed linked-client authored gate passes its 26 collector/preflight/report
133
+ tests, five worker reports and matching ordinary/instrumented native browser cases.
134
+ All-four authored coverage remains 100% over 791 statements, 521 branches, 125
135
+ functions and 659 lines. Its ordinary browser/transport bundles retain their
136
+ production identities. Run `0248026f-dadf-42fe-bb9a-1bc287f4fbb5` under
137
+ `coverage/client-source/` retains `summary.json` SHA-256
138
+ `c876bc77f0261fff6e7b1f8761cbcd09e26053d802246a44eec431e4387fd876`
139
+ and `coverage.json` SHA-256
140
+ `8673e236f675d741cb0f55d4f4bf630f2e2a50c2f2f76f856622558491ac8009`.
141
+ Both npm links and the client's pre-existing version edit remain untouched.
142
+
143
+ The complete isolated-package gate subsequently passed with registry
144
+ `redweb-client@0.2.0` and matching identities for all four production bundles.
145
+ Installed counter/chat/reconnect/disconnect, dependency isolation, generated
146
+ additions, authenticated dashboard, all three copied browser phases, source-free
147
+ starters, executable docs, compiled consumers and static export passed. TLS
148
+ verification remained enabled. Tested archive SHA-256:
149
+ `97ab4789755132d66bcdd219b2390879ea4c4657fb273fafe2c8326edf975ee3`.
150
+ This archive predates the final evidence-only documentation additions.
151
+ Report `coverage/packed-browser/ed6f21ed-4300-4645-94e5-6a6842765e4f/report.json`
152
+ has SHA-256 `01d047163d0569b30c0769231486ab815b33b4fac6bc6519bb081f8a18296e39`.
153
+ It records 210 package files and 26 unchanged copied harness inputs, with harness
154
+ SHA-256 `0a0cdf39fa16c8e995de1474fae0d70773594eb96552423cd5215c96a43232b4`.
155
+ The critic approved all eleven actual remote files at implementation commit
156
+ `82156ee`, their evidence identities and all 66 generated pages. The critic also
157
+ approved the three actual remote package-evidence files at `7a0297e`.
158
+
159
+ The full regression at `7a0297e` then passed 1,488 tests across 142 suites in
160
+ 794.914 seconds, with two POSIX-only skips. The unchanged 91-file library retained
161
+ all-four 100% coverage: 5,449 statements, 4,046 branches, 978 functions and 4,468
162
+ lines. Full result `coverage/refresh-commands-full-results.json` has SHA-256
163
+ `7cba49a5fed554ceafbcba91e888b2e00a3ed4d541bb1e2ef216b086fff98e65`;
164
+ its `coverage/coverage-final.json` has SHA-256
165
+ `275f82a20c7ed1389b65ef7d2b3752006926ae85c8dc4800d5dc9c07173cb1ac`.
166
+ The client type check also passed, and a fresh production dependency audit
167
+ reported zero vulnerabilities with TLS verification retained. Later documentation
168
+ corrections and their additional tests are not included in this full-run count.
169
+ Both PR and push workflows for `82156ee` and `7a0297e` subsequently passed.
170
+ Later-head hosted outcomes remain separate; no prior pass is relabelled current.
171
+
172
+ ## Earlier native acceptance and remaining gates
173
+
174
+ The complete ordinary/instrumented browser-runtime and development-refresh gates
175
+ pass with matching case inventories and unchanged all-four 100% emitted-code scopes.
176
+ Runtime covers 426 statements, 262 branches, 64 functions and 351 lines; refresh
177
+ covers 82 statements, 44 branches, 12 functions and 71 lines. Actual server actions,
178
+ feedback, selection updates, history restoration and outage/draft guards pass on
179
+ Windows / Node 22.21.0 / Chrome 152.0.7977.64.
180
+
181
+ | Native report | Run | SHA-256 |
182
+ | --- | --- | --- |
183
+ | `coverage/browser-runtime/report.json` | `2813578e-7b5d-4af6-a331-403f2328b15c` | `5bc71d191bd66de750bdb08dd657772c4fb72b10dcd8743936b282e71c6643e3` |
184
+ | `coverage/browser-refresh/report.json` | `fa70d407-f57f-45c3-8793-8a1626db594a` | `fd3b9bcfd5cedb970cc15a3412f21ffcbd05ec10c4830b562c61811045d8ba05` |
185
+
186
+ The linked-client gate also passes 77 tests per ordinary/instrumented mode, five
187
+ worker reports and actual browser acceptance. Its authored scope remains all-four
188
+ 100% over 791 statements, 521 branches, 125 functions and 659 lines. Source-built
189
+ ordinary bundles still match the linked production build. Run
190
+ `3ba3d058-886d-42e7-9e01-d07e64fe2dff` under `coverage/client-source/` retains
191
+ `summary.json` SHA-256 `877858b6ad0b98b0bce825dde8f39f6010682905dfd5acd5574ded9205284aa7`
192
+ and `coverage.json` SHA-256 `4f6c0ce9e07e613366360dbda6dffc0dff0cb16fa02e55cd4470a32a8bb9fb21`.
193
+ The separate collector/preflight/report suite passes 26 tests. The standalone
194
+ Node-only V8 diagnostic remains separate and is not relabelled passing.
195
+
196
+ Pretest/generated/type checks and four documentation units pass. The critic approved
197
+ the adapter, native test, independent fallback releases, budgets and scoped evidence.
198
+ The actual-PR review approved all 16 remote blobs at `e3b4902`.
199
+
200
+ The complete isolated-package gate then passed with registry `redweb-client@0.2.0`
201
+ and matching identities for all four bundles. It exercised installed counter/chat,
202
+ dependency isolation, generated additions, authenticated dashboard, copied browser
203
+ acceptance/runtime/refresh, all source-free starters, executable docs, compiled
204
+ action/room consumers and static export. No runtime modules were replaced, and
205
+ TLS verification remained enabled.
206
+
207
+ Tested archive SHA-256:
208
+ `c2589e8fff6c4247b98b5aa0de47c2244feaefb79351bc0abf4ff4f8c0cbbdcd`.
209
+ This archive predates subsequent evidence-only documentation edits. The retained
210
+ browser phase report is
211
+ `coverage/packed-browser/369c631b-7c8b-4986-9e23-8e8bba9b6a68/report.json`, SHA-256
212
+ `c43cdc79bc50645e8f07d715f29982ce99b15946e2b23714ee17d1c4df0dd237`.
213
+ It records all three browser phases passing, 210 package files, 26 unchanged
214
+ harness inputs, and harness SHA-256
215
+ `ce81b626e0d87bb50edf1856522a3916bdf983dd1629404b7e1ab1a2052608c3`.
216
+
217
+ The full regression for `69dcbf8` passed 1,469 tests/140 suites in 759.054 seconds,
218
+ with two POSIX-only skips and the unchanged 91-file library at all-four 100%
219
+ (5,449 statements, 4,046 branches, 978 functions, 4,468 lines). The two full-driver
220
+ cases were added after discovery and pass separately; they are not included in
221
+ 1,469. Retained full result `coverage/feedback-commands-full-results.json` has
222
+ SHA-256 `b4a5bcb06d59d2759e7a6a7190c9100023916beeb70d062d25f6a02e0d749be9`;
223
+ the corresponding `coverage/coverage-final.json` has SHA-256
224
+ `04c2f534616e477c367126cb5009b7e0496fc832b3e1dfb57e9048b64330952f`.
225
+ Both `659f638`, `9c29a6e` and `e3b4902` hosted workflows passed completely. Latest hosted
226
+ results remain separate and are not presumed passed.
227
+ No npm publication, deployment, frozen-file edit, benchmark waiver or new long-soak
228
+ claim is made.
@@ -0,0 +1,58 @@
1
+ # Build a site and its realtime backend together
2
+
3
+ Redweb renders TypeScript/TSX on Node.js and connects server-owned state and actions to the browser through WebSockets. Use it for live dashboards, chat, collaboration, documentation sites, and socket services. You can use HTTP or WebSockets independently.
4
+
5
+ It is not React, a browser component framework, a database, an identity provider, or a managed multiplayer platform. Do not use React hooks or import `react/jsx-runtime`. An edge-only host without Node listeners cannot run a live Redweb server; exported static pages need no Node runtime.
6
+
7
+ ## Start with a complete recipe
8
+
9
+ Choose one of these complete applications:
10
+
11
+ - [Realtime counter](../recipes/realtime/README.md): the smallest live website, sharing server-owned state between visitors.
12
+ - [Chatroom](../recipes/chat/README.md): reusable stateful components, messages, and live presence.
13
+ - [Site](../recipes/site/README.md): non-live pages with a shared layout and stylesheet.
14
+ - [Socket service](../recipes/socket/README.md): a typed `/match` route with separate join/move/resume handlers.
15
+ - [HTTP and WebSockets](../recipes/http-ws/README.md): one listener, an HTTP health endpoint and a raw `/chat` route with an explicit cleanup owner.
16
+ - [Private dashboard](../recipes/dashboard/README.md): persistent SQLite cards, account sessions and private live updates (Node 22.13+).
17
+
18
+ Each generated recipe page contains its exact files, commands, limitations, and real HTTP/WebSocket acceptance tests. Follow that recipe's version-specific setup instructions rather than mixing an unreleased example with a published npm version.
19
+
20
+ Requirements: Node.js satisfying the package's `engines` field and npm. Use a supported Node.js release in production. TypeScript and the development watcher are installed by the starter. No React, frontend bundler or broker is required. Only the dashboard starter uses a database; its native SQLite requirement is recipe-local.
21
+
22
+ The installation floor is not a security-support promise for old Node releases. See [runtime compatibility, release verification and provenance](RELEASE_TRUST.md) before choosing a production version.
23
+
24
+ ## One development loop
25
+
26
+ After initialization and installation, `npm test` compiles the project, copies assets, and runs the shipped network tests. `npm run dev` watches source/configuration files, rebuilds, and restarts. Served HTML pages on direct localhost access refresh when the replacement server is ready; detected edits instead produce a confirmation notice that keeps the current document until explicit reload. This is not autosave or browser hot-module replacement; in-memory state and old socket sessions reset on restart. See [development refresh and its guarantees](DEVELOPMENT.md#browser-refresh).
27
+
28
+ Use `.tsx` for markup and extend `redweb/tsconfig.json`. Colocate CSS with the decorated page/component or declare an explicit asset root. `npm run build` prepares `dist/`; `npm start` runs that compiled application.
29
+
30
+ When setup fails, run `npx --no-install redweb doctor --json` from the application directory. Fix reported errors and examine unresolved warnings, then rerun the build and real tests. Doctor does not execute application code or prove application correctness. See [diagnostics and boundaries](CLI.md).
31
+
32
+ ## The mental model
33
+
34
+ - A page is a decorated class. Its `render()` returns server-side TSX.
35
+ - State is server-owned data. An ordinary TSX expression reading `@state()` updates automatically when that property is assigned. Replace arrays/objects rather than mutating them in place.
36
+ - Only decorated actions are browser-callable. Validate and authorize every untrusted input; hiding a button is not access control.
37
+ - A class component owns reusable state/actions and has its own update boundary. Function components are convenient presentation helpers.
38
+ - Pages are connection-scoped by default. `shared: true` intentionally shares one page instance; do not put private visitor data there.
39
+ - Shared in-memory state survives visitors and reloads, not server restarts. Durable cards/history require application-owned persistence. Multiple processes do not automatically share memory.
40
+ - Socket URLs select routes; message `type` selects a handler. Do not add a second `message.action` dispatcher inside a catch-all handler.
41
+
42
+ See [rendering and lifecycle](LIVE_HTML.md) and [shared socket contracts](SOCKET_CONTRACTS.md) for exact semantics.
43
+
44
+ For private raw socket subscriptions, see [room authorization and shared request identity](ROOM_AUTHORIZATION.md). Keep authentication, subscription permission, and application-specific write permission explicit.
45
+
46
+ ## Deploy deliberately
47
+
48
+ Build first. Deploy `dist/`, the package manifest, and the lockfile, then install runtime dependencies with `npm ci --omit=dev`. The starters are tested with `src/` unavailable after compilation. Configure HTTPS/WSS and a proxy that supports WebSocket upgrades when using a reverse proxy.
49
+
50
+ These deployment commands require a verified release pair. `redweb-client@0.2.0` is published and installs automatically through the matching Redweb dependency. Unreleased Redweb changes still require the matching tested tarball until their own release is published. The `npm link` workflow is local development only: a clean production install does not preserve that link.
51
+
52
+ Before public access, add authentication, authorization, trusted-origin policy, input/rate limits, application persistence where needed, and bounded shutdown. Treat reconnect/session tokens as credentials. Do not promise exactly-once delivery or durable sessions from an in-memory starter. See [operations](MULTIPLAYER_OPERATIONS.md) and [guarantees and limits](PRODUCTION_READINESS.md).
53
+
54
+ ## Evidence and compatibility
55
+
56
+ Complete recipe files are executable applications; shorter API snippets explain individual methods and may require surrounding application code. Type-check and test a complete recipe before adapting it. The package verifier runs the documented recipe files against an extracted tarball and actual listeners, not mocks.
57
+
58
+ Coverage reports refer to instrumented library code. They do not prove exhaustive browser behavior, application security, all generated-example branches, or production capacity. Historical [verification evidence](VERIFICATION_EVIDENCE.md) applies only to its recorded revision/environment; consult the [current release checklist](AGENT_READY_ACCEPTANCE.md) for remaining work.
@@ -0,0 +1,59 @@
1
+ # JSX performance-verifier correction
2
+
3
+ This changes the acceptance check, not Redweb's renderer. The previous predicate
4
+ counted 10,000 `<li ` occurrences and required only one escaped label. Executing
5
+ that exact predicate against malformed markup demonstrated a false pass despite
6
+ missing numeric children and closing tags. A separate duplicate-index regression
7
+ also failed before the correction: the verifier accepted the corrupted output.
8
+ Neither result demonstrates that the actual renderer produces incorrect markup.
9
+
10
+ One short-lived function now compares the complete expected list: every class,
11
+ index, escaped label, numeric child and closing tag. Its independent literal
12
+ oracle does not use the renderer under test. Validation runs after stopping the
13
+ render timer, and its temporary data is out of scope before retained-heap sampling.
14
+
15
+ The 10,000-row workload, original timing boundary, two GC calls, cleared page and
16
+ output references, negative-growth clamp, five-second render threshold and 32 MiB
17
+ retained-heap limit are unchanged. The stronger oracle is a harness revision;
18
+ it is not a rendering optimization or byte-identical repeat of historical heap
19
+ measurements.
20
+
21
+ A performance comparison cannot interrupt stuck synchronous JavaScript. CI now
22
+ supervises the default command with a two-minute external deadline. Native tests
23
+ run real CLI subprocesses with 10/30-second command bounds and owned termination;
24
+ the outer test allows 80 seconds for operations and cleanup. Direct manual command
25
+ invocations still need an external supervisor if a hard execution deadline is
26
+ required. No extra runtime worker or timer abstraction was added.
27
+
28
+ ## Scoped verification
29
+
30
+ Windows / Node 22.21.0: the final maintained command passed 14 tests across two
31
+ suites in 2.408 seconds (the initial focused run passed in 2.560 seconds). The
32
+ maintained `npm run verify:jsx:coverage` command measures the original verifier:
33
+ 27 statements, eight branches, four functions and 23 lines, all 100%. CI retains
34
+ this report on success or failure with a separate three-minute deadline.
35
+
36
+ Thirteen explicitly labelled boundary units cover malformed markup, missing GC,
37
+ slow rendering, excess retained heap, exact limit acceptance, negative-growth
38
+ clamping, sampling order and suppression of success output after failure. The
39
+ native integration test uses the real renderer, process, clock and GC for both
40
+ missing-GC rejection and the complete 10,000-row CLI workload, without API mocks.
41
+ It is separate from clean performance measurement; no native non-finite clock or
42
+ heap defect is claimed from fault injection.
43
+
44
+ Source `scripts/verify-jsx-performance.js` SHA-256:
45
+ `31e4a1d88a55cecdc3c604d8fb87e911d4e79a180a22517880903830e340aeca`.
46
+ Report `coverage/jsx-performance-tools/coverage-final.json` SHA-256:
47
+ `eb88af0e3318c48abd24fbf30e34ce4819a7ea98287a1c10c6cfb52cbcf0a7ef`.
48
+
49
+ The senior critic approved the scoped implementation, sampling parity, native
50
+ command budgets and separation of real evidence from boundary fault injection.
51
+ After the full regression exited and before rerunning scoped coverage, one clean
52
+ default JSX command passed 10,000 rows in 48.8 ms with 0.6 MiB retained, against
53
+ the unchanged 5,000 ms / 32 MiB limits. The smaller reported retained heap is not
54
+ claimed as a runtime improvement; the validation allocation pattern changed.
55
+ These 14 tests were added after the preceding full regression had selected its
56
+ test inventory; they are not retroactively included in that run. Hosted review,
57
+ remaining private-tool coverage and the separate unresolved throughput benchmark
58
+ remain distinct release requirements. No npm publication, deployment or merge is
59
+ claimed.