redweb 0.16.0 → 0.16.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/docs/MIGRATION.md CHANGED
@@ -1,28 +1,28 @@
1
- # Upgrade an existing Redweb application
2
-
3
- Match the installed package to its versioned documentation. Redweb 0.15.0 contains the capabilities described by the 0.15.0 guides; a later development checkout may not match that release. See [release verification](RELEASE_TRUST.md) and the changelog shipped with your selected package. Keep your lockfile and rollback artifact, and run your own real HTTP/WebSocket/browser tests after upgrading.
4
-
5
- ## 0.8 migration notes
6
-
7
- - Unmatched WebSocket paths are rejected unless `fallbackToRoot: true` is configured.
8
- - Handler exception details are hidden unless `exposeErrors: true` is configured. Do not expose private exception messages in production.
9
- - Shutting down a WebSocket server no longer closes a caller-supplied HTTP/HTTPS server by default. Explicitly set `closeServerOnShutdown: true` only when handing cleanup responsibility to that socket server.
10
- - `bind` is honored by HTTP, HTTPS, WebSocket, and secure WebSocket listeners.
11
- - `shutdown()` is asynchronous; await it when deterministic cleanup matters. Awaiting a shutdown is not a delivery or persistence guarantee.
12
-
13
- ## 0.9 migration notes
14
-
15
- - No migration is required when the new multiplayer options are disabled.
16
- - Production controls are route-local and opt-in; size them from measured capacity rather than copying example limits.
17
- - `ProtocolClient` is available from `redweb/client` for negotiated protocol routes without adding runtime dependencies. It wraps a transport; your application creates and reconnects that transport.
18
- - Node.js 18 is the installation/legacy-compatibility floor, not a recommendation to deploy an end-of-life runtime. Use a maintained LTS release with current security patches; check [runtime compatibility](RELEASE_TRUST.md).
19
-
20
- ## Live HTML migration
21
-
22
- The executable `.htmx` sandbox and `enableHtmxRendering` option were replaced. Templates are ordinary `.html` files registered through decorated plain classes. Move calculations and imports into the page class, mark reactive fields with `@state()`, expose browser-callable methods with `@action()`, and start the page with `start(PageClass)`.
23
-
24
- For server-rendered TSX, extend `redweb/tsconfig.json`; do not configure React's JSX runtime. `redweb init --existing` creates a missing root configuration without overwriting one you already have. Check the effective configuration with your installed CLI: `npx --no-install redweb doctor --json`. Review warnings and fix errors before compiling; preservation does not imply correctness.
25
-
26
- In the reactive-rendering candidate, ordinary TSX expressions reading decorated state update after assignment. Replace arrays/objects instead of mutating them in place. Use stable JSX keys for lists. Existing explicit HTML bindings remain supported. See [rendering and lifecycle](LIVE_HTML.md) for owner isolation, component lifetimes and reconnect behavior, and [runtime diagnostics](RUNTIME_DIAGNOSTICS.md) for failure categories and retry limits.
27
-
28
- Shared page state is process-local, not durable or automatically private. Add explicit identity, authorization and persistence for your application. The [private dashboard recipe](../recipes/dashboard/README.md) demonstrates one single-process implementation; it is not a distributed session store.
1
+ # Upgrade an existing Redweb application
2
+
3
+ Match the installed package to its versioned documentation. Redweb 0.16.2 contains the capabilities described by the 0.16.2 guides; a later development checkout may not match that release. See [release verification](RELEASE_TRUST.md) and the changelog shipped with your selected package. Keep your lockfile and rollback artifact, and run your own real HTTP/WebSocket/browser tests after upgrading.
4
+
5
+ ## 0.8 migration notes
6
+
7
+ - Unmatched WebSocket paths are rejected unless `fallbackToRoot: true` is configured.
8
+ - Handler exception details are hidden unless `exposeErrors: true` is configured. Do not expose private exception messages in production.
9
+ - Shutting down a WebSocket server no longer closes a caller-supplied HTTP/HTTPS server by default. Explicitly set `closeServerOnShutdown: true` only when handing cleanup responsibility to that socket server.
10
+ - `bind` is honored by HTTP, HTTPS, WebSocket, and secure WebSocket listeners.
11
+ - `shutdown()` is asynchronous; await it when deterministic cleanup matters. Awaiting a shutdown is not a delivery or persistence guarantee.
12
+
13
+ ## 0.9 migration notes
14
+
15
+ - No migration is required when the new multiplayer options are disabled.
16
+ - Production controls are route-local and opt-in; size them from measured capacity rather than copying example limits.
17
+ - `ProtocolClient` is available from `redweb/client` for negotiated protocol routes without adding runtime dependencies. It wraps a transport; your application creates and reconnects that transport.
18
+ - Node.js 18 is the installation/legacy-compatibility floor, not a recommendation to deploy an end-of-life runtime. Use a maintained LTS release with current security patches; check [runtime compatibility](RELEASE_TRUST.md).
19
+
20
+ ## Live HTML migration
21
+
22
+ The executable `.htmx` sandbox and `enableHtmxRendering` option were replaced. Templates are ordinary `.html` files registered through decorated plain classes. Move calculations and imports into the page class, mark reactive fields with `@state()`, expose browser-callable methods with `@action()`, and register it with `defineApp({ pages: [PageClass] })`, then call `app.run()`.
23
+
24
+ For server-rendered TSX, extend `redweb/tsconfig.json`; do not configure React's JSX runtime. `redweb init --existing` creates a missing root configuration without overwriting one you already have. Check the effective configuration with your installed CLI: `npx --no-install redweb doctor --json`. Review warnings and fix errors before compiling; preservation does not imply correctness.
25
+
26
+ Ordinary TSX expressions reading decorated state update after assignment. Replace arrays/objects instead of mutating them in place. Use stable JSX keys for lists. Existing explicit HTML bindings remain supported. See [rendering and lifecycle](LIVE_HTML.md) for owner isolation, component lifetimes and reconnect behavior, and [runtime diagnostics](RUNTIME_DIAGNOSTICS.md) for failure categories and retry limits.
27
+
28
+ Shared page state is process-local, not durable or automatically private. Add explicit identity, authorization and persistence for your application. The [private dashboard recipe](../recipes/dashboard/README.md) demonstrates one single-process implementation; it is not a distributed session store.
@@ -1,21 +1,21 @@
1
- # Choose and verify a Redweb release
2
-
3
- Redweb is a Node.js HTTP/WebSocket library with server-rendered TSX, not a hosted service. Evaluate the exact package, runtime, application and deployment you intend to use. A passing test suite, a registry signature and a provenance statement answer different questions; none certifies an application as secure.
4
-
5
- ## Runtime and compiler compatibility
6
-
7
- | Area | Contract and verification boundary |
8
- | --- | --- |
9
- | Core runtime | The package declares Node `>=18`. This is an installation/compatibility floor, not a recommendation to deploy an end-of-life runtime. |
10
- | Production Node | Use a currently maintained LTS release with current security patches. As checked on 2026-08-30, Node 22 and 24 are LTS; Node 18 and 20 are end-of-life. Recheck the official schedule when deploying. |
11
- | CI coverage | The repository matrix targets Node 18, 20, 22 and 24 on Linux. The 18/20 jobs are legacy-compatibility checks, not security-support claims. A configured job is not a passing result; inspect checks for your exact commit. |
12
- | TypeScript/TSX | The starter uses the package's tested TypeScript dependency and `redweb/tsconfig.json`. Standard decorators and legacy `experimentalDecorators` consumers have separate compile tests. Node's native TypeScript execution is not a replacement for compiling TSX/decorators with this configuration. |
13
- | Persistent dashboard | This application recipe requires Node 22.13+ and native `node:sqlite`; it is not part of the core runtime requirement. Its database and account/session design are single-process. |
14
- | Browser | The real-browser gates exercise Chromium. They are not a Firefox/Safari compatibility certification. Test the browsers you support, including reconnect and forms, before release. |
15
- | Runtime platforms | This branch has local Windows evidence and Linux CI configuration. Neither proves every OS, architecture, proxy, container platform or serverless host works. Live pages require a long-lived Node listener with WebSocket upgrades. Static export is a separate deployment mode. |
16
-
17
- Use the [official Node release schedule](https://nodejs.org/en/about/previous-releases) for maintained releases, the [TypeScript decorator documentation](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#decorators) for the distinction between decorator modes, and [Node's TypeScript limitations](https://nodejs.org/api/typescript.html) for native execution constraints. Current per-commit test evidence and uncompleted checks are recorded in the [release checklist](AGENT_READY_ACCEPTANCE.md), not inferred from this table.
18
-
1
+ # Choose and verify a Redweb release
2
+
3
+ Redweb is a Node.js HTTP/WebSocket library with server-rendered TSX, not a hosted service. Evaluate the exact package, runtime, application and deployment you intend to use. A passing test suite, a registry signature and a provenance statement answer different questions; none certifies an application as secure.
4
+
5
+ ## Runtime and compiler compatibility
6
+
7
+ | Area | Contract and verification boundary |
8
+ | --- | --- |
9
+ | Core runtime | The package declares Node `>=18`. This is an installation/compatibility floor, not a recommendation to deploy an end-of-life runtime. |
10
+ | Production Node | Use a currently maintained LTS release with current security patches. As checked on 2026-08-30, Node 22 and 24 are LTS; Node 18 and 20 are end-of-life. Recheck the official schedule when deploying. |
11
+ | CI coverage | The repository matrix targets Node 18, 20, 22 and 24 on Linux. The 18/20 jobs are legacy-compatibility checks, not security-support claims. A configured job is not a passing result; inspect checks for your exact commit. |
12
+ | TypeScript/TSX | The starter uses the package's tested TypeScript dependency and `redweb/tsconfig.json`. Standard decorators and legacy `experimentalDecorators` consumers have separate compile tests. Node's native TypeScript execution is not a replacement for compiling TSX/decorators with this configuration. |
13
+ | Persistent dashboard | This application recipe requires Node 22.13+ and native `node:sqlite`; it is not part of the core runtime requirement. Its database and account/session design are single-process. |
14
+ | Browser | The real-browser gates exercise Chromium. They are not a Firefox/Safari compatibility certification. Test the browsers you support, including reconnect and forms, before release. |
15
+ | Runtime platforms | This branch has local Windows evidence and Linux CI configuration. Neither proves every OS, architecture, proxy, container platform or serverless host works. Live pages require a long-lived Node listener with WebSocket upgrades. Static export is a separate deployment mode. |
16
+
17
+ Use the [official Node release schedule](https://nodejs.org/en/about/previous-releases) for maintained releases, the [TypeScript decorator documentation](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-5-0.html#decorators) for the distinction between decorator modes, and [Node's TypeScript limitations](https://nodejs.org/api/typescript.html) for native execution constraints. Current per-commit test evidence and uncompleted checks are recorded in the [release checklist](AGENT_READY_ACCEPTANCE.md), not inferred from this table.
18
+
19
19
  ## Pin the package and the documentation together
20
20
 
21
21
  ### Temporary Express 4 dependency mitigation
@@ -41,48 +41,48 @@ An ordinary installation without this root policy can still select affected
41
41
  dependencies. No Express 5 migration, bundled fork or published shrinkwrap is
42
42
  introduced. Audit results remain time-sensitive and application-specific.
43
43
 
44
- For a published application, select an exact release, commit its lockfile, and use `npm ci` in CI/deployment. This guide is versioned for 0.15.0. Before registry publication, verify the packed candidate; after publication, repeat these registry checks from a clean application:
45
-
46
- ```sh
47
- npm view redweb@0.15.0 version engines dist.integrity dist.signatures dist.attestations gitHead --json
48
- npm install --save-exact redweb@0.15.0
49
- npm audit signatures
50
- npm audit --omit=dev
51
- ```
52
-
53
- The signature command must run in the installed application directory. Keep TLS verification enabled and use a current npm CLI; a certificate/trust-store failure is not a reason to disable verification. A lockfile's integrity value detects changed package bytes; registry signatures authenticate registry metadata; provenance, when present and verified, links an artifact to a build/source identity. Vulnerability audit is a separate check against known advisories, not an application penetration test.
54
-
55
- Redweb 0.15.0 contains socket-bound TSX controls and connection-owned page state, unified application startup, server-rendered TSX, reactive state/actions, complete starters, shared socket contracts, authorization, diagnostics, lifecycle work, and bounded heartbeat grace described by these versioned guides. Keep the package and documentation version aligned; do not mix a development guide or a future checkout with 0.15.0 and assume newer APIs exist.
56
-
57
- Redweb is pre-1.0. Consult the changelog and versioned guide before upgrading, run your own real HTTP/WebSocket/browser tests, and keep a rollback artifact. Patch/minor numbers and a compatible TypeScript build alone do not prove wire compatibility, preserved sessions, database compatibility or application authorization. HTTP-created live-page sessions are process-owned; a restart or rolling replacement does not migrate them automatically. Raw socket protocol versions are negotiated only when the route opts in, and application payload compatibility remains your contract.
58
-
59
- ## Historical registry verification
60
-
61
- Read-only registry inspection after publication on **2026-09-01 UTC** reported `latest: 0.13.0`, with:
62
-
63
- - `gitHead`: `7196d504ee65dfaf5ac869ea4bda66d7cf86d015`, the verified merge commit on `main`.
64
- - SHA-512 integrity: `sha512-n5OQl214vC6ithpfg6QyhAmaOtjY8AYEGrWZGl8LxdSCyagD1K2bvplcxhQOruZP3exwkIyRPnhIuFe9rIcQFQ==`.
65
- - SHA-1 registry checksum: `1ff22dbd2a5c3d8eafad219055f01fe5b85b9d10`.
66
- - Registry signature present; **no `dist.attestations` field was returned**. Build provenance is therefore not claimed for this release.
67
-
68
- An independently created temporary application installed that exact package with lifecycle scripts disabled and ran `npm audit signatures --json` using Node 22.21.0/npm 11.6.2 and the Windows system trust store. It exited successfully with `invalid: []` and `missing: []`; `npm audit --omit=dev --json` reported zero vulnerabilities. All 215 published files matched content at the recorded `gitHead`: two byte-for-byte and 213 after normalizing Windows CRLF materialization to Git's LF blobs. The retained release audit receipt at `docs/releases/audit-0.13.0.json` records the archive hashes and every published/Git file hash. These checks authenticate and compare the observed artifact; they do not certify the application, prove every dependency has build provenance, or verify a future release.
69
-
70
- The immutable 0.13.0 tarball has a known documentation-only release-process defect. Its bundled `docs/generated.json` says `channel: "unreleased"`; its changelog says 0.13.0 was not yet published; and its README uses development-tarball setup, calls that setup prerelease/development-only, and later says Redweb remains unreleased. Runtime files and public declarations match the verified merge commit. The repository and website sources correct those labels. The repository's `docs/releases/0.13.0.json` is therefore a corrected **post-publication** documentation snapshot for 0.13.0, not the catalogue that shipped inside the immutable 0.13.0 tarball. A future patch release is required to deliver the corrected bundled documentation to npm consumers.
71
-
72
- Registry inspection after the later 0.13.1 publication reported `gitHead` `db64d5b655d5668a75b587122c9e1e9ef4c9bca1`, SHA-512 integrity `sha512-DCLcmiDj89kXf3+80H5/1W+nQEXIhF8RfiBlU6b/LA7418/ChkzhZ8oV4JmVLDL/nt7zFNcytyjavzrDT/XfoA==`, SHA-1 checksum `c05f3e0dc560d4bb379b8fbd6747c3470fcc31f0`, a registry signature, and no provenance attestation. Its runtime contains the heartbeat correction, but its 217-file immutable archive again labels `docs/generated.json` and the README as unreleased and contains no `docs/releases/0.13.1.json`. Its package version was materialized in the publication workspace rather than committed at the recorded `gitHead`, so 0.13.1 is not presented as a clean source-identical release.
73
-
74
- The 0.13.2 release candidate corrects that process: version metadata and lockfile, an empty Unreleased section, registry-pinned README setup, and `docs/releases/0.13.2.json` must exist in the reviewed commit before manual publication. Publish only that clean merged commit, then verify the registry metadata and installed archive before synchronizing the website.
75
-
76
- The commands above let you repeat the check. See npm's [signature and attestation verification](https://docs.npmjs.com/cli/v11/commands/npm-audit/) and [viewing provenance](https://docs.npmjs.com/viewing-package-provenance/) documentation for current verification behavior.
77
-
78
- ## Publishing provenance is a maintainer action
79
-
80
- The 0.13.0 and 0.13.1 registry metadata contain signatures but no provenance attestations. To add provenance to a future release, the maintainer must choose an authorized supported build/publish workflow, configure the correct repository identity and npm permissions, publish the exact tested artifact, and verify the resulting registry attestation afterward. A local `npm pack`, `gitHead`, checksum, badge or successful CI run is not a substitute for a verified attestation. Do not label older releases retroactively as provenance-verified.
81
-
82
- npm describes the supported providers and identity requirements in [generating provenance](https://docs.npmjs.com/generating-provenance-statements/) and [trusted publishing](https://docs.npmjs.com/trusted-publishers/). Provenance provides origin/build evidence, not proof that source code is safe.
83
-
84
- ## Support and reporting boundaries
85
-
86
- For ordinary bugs, provide a minimal reproducible project, exact Redweb/Node/npm/TypeScript versions, operating system, decorator mode, sanitized logs, and the failing HTTP/WebSocket sequence in the [issue tracker](https://github.com/lakam99/redweb/issues). Never include tokens, cookies, passwords, private database contents or customer traffic.
87
-
88
- There is no paid support contract, response-time SLA or long-term backport policy established by these files. No private vulnerability contact is invented here. The repository inspection on 2026-08-30 reported no published security policy; the maintainer still needs to establish a private reporting channel and its handling policy before the project claims one. Do not disclose a suspected vulnerability or working exploit in a public bug report merely because that is the only linked tracker.
44
+ For a published application, select an exact release, commit its lockfile, and use `npm ci` in CI/deployment. This guide is versioned for 0.16.2. Before registry publication, verify the packed candidate; after publication, repeat these registry checks from a clean application:
45
+
46
+ ```sh
47
+ npm view redweb@0.16.2 version engines dist.integrity dist.signatures dist.attestations gitHead --json
48
+ npm install --save-exact redweb@0.16.2
49
+ npm audit signatures
50
+ npm audit --omit=dev
51
+ ```
52
+
53
+ The signature command must run in the installed application directory. Keep TLS verification enabled and use a current npm CLI; a certificate/trust-store failure is not a reason to disable verification. A lockfile's integrity value detects changed package bytes; registry signatures authenticate registry metadata; provenance, when present and verified, links an artifact to a build/source identity. Vulnerability audit is a separate check against known advisories, not an application penetration test.
54
+
55
+ Redweb 0.16.2 contains neutral composable initialization, socket-bound TSX controls and connection-owned page state, unified application startup, server-rendered TSX, reactive state/actions, complete starters, shared socket contracts, authorization, diagnostics, lifecycle work, and bounded heartbeat grace described by these versioned guides. Keep the package and documentation version aligned; do not mix a development guide or a future checkout with 0.16.2 and assume newer APIs exist.
56
+
57
+ Redweb is pre-1.0. Consult the changelog and versioned guide before upgrading, run your own real HTTP/WebSocket/browser tests, and keep a rollback artifact. Patch/minor numbers and a compatible TypeScript build alone do not prove wire compatibility, preserved sessions, database compatibility or application authorization. HTTP-created live-page sessions are process-owned; a restart or rolling replacement does not migrate them automatically. Raw socket protocol versions are negotiated only when the route opts in, and application payload compatibility remains your contract.
58
+
59
+ ## Historical registry verification
60
+
61
+ Read-only registry inspection after publication on **2026-09-01 UTC** reported `latest: 0.13.0`, with:
62
+
63
+ - `gitHead`: `7196d504ee65dfaf5ac869ea4bda66d7cf86d015`, the verified merge commit on `main`.
64
+ - SHA-512 integrity: `sha512-n5OQl214vC6ithpfg6QyhAmaOtjY8AYEGrWZGl8LxdSCyagD1K2bvplcxhQOruZP3exwkIyRPnhIuFe9rIcQFQ==`.
65
+ - SHA-1 registry checksum: `1ff22dbd2a5c3d8eafad219055f01fe5b85b9d10`.
66
+ - Registry signature present; **no `dist.attestations` field was returned**. Build provenance is therefore not claimed for this release.
67
+
68
+ An independently created temporary application installed that exact package with lifecycle scripts disabled and ran `npm audit signatures --json` using Node 22.21.0/npm 11.6.2 and the Windows system trust store. It exited successfully with `invalid: []` and `missing: []`; `npm audit --omit=dev --json` reported zero vulnerabilities. All 215 published files matched content at the recorded `gitHead`: two byte-for-byte and 213 after normalizing Windows CRLF materialization to Git's LF blobs. The retained release audit receipt at `docs/releases/audit-0.13.0.json` records the archive hashes and every published/Git file hash. These checks authenticate and compare the observed artifact; they do not certify the application, prove every dependency has build provenance, or verify a future release.
69
+
70
+ The immutable 0.13.0 tarball has a known documentation-only release-process defect. Its bundled `docs/generated.json` says `channel: "unreleased"`; its changelog says 0.13.0 was not yet published; and its README uses development-tarball setup, calls that setup prerelease/development-only, and later says Redweb remains unreleased. Runtime files and public declarations match the verified merge commit. The repository and website sources correct those labels. The repository's `docs/releases/0.13.0.json` is therefore a corrected **post-publication** documentation snapshot for 0.13.0, not the catalogue that shipped inside the immutable 0.13.0 tarball. A future patch release is required to deliver the corrected bundled documentation to npm consumers.
71
+
72
+ Registry inspection after the later 0.13.1 publication reported `gitHead` `db64d5b655d5668a75b587122c9e1e9ef4c9bca1`, SHA-512 integrity `sha512-DCLcmiDj89kXf3+80H5/1W+nQEXIhF8RfiBlU6b/LA7418/ChkzhZ8oV4JmVLDL/nt7zFNcytyjavzrDT/XfoA==`, SHA-1 checksum `c05f3e0dc560d4bb379b8fbd6747c3470fcc31f0`, a registry signature, and no provenance attestation. Its runtime contains the heartbeat correction, but its 217-file immutable archive again labels `docs/generated.json` and the README as unreleased and contains no `docs/releases/0.13.1.json`. Its package version was materialized in the publication workspace rather than committed at the recorded `gitHead`, so 0.13.1 is not presented as a clean source-identical release.
73
+
74
+ The 0.13.2 release candidate corrects that process: version metadata and lockfile, an empty Unreleased section, registry-pinned README setup, and `docs/releases/0.13.2.json` must exist in the reviewed commit before manual publication. Publish only that clean merged commit, then verify the registry metadata and installed archive before synchronizing the website.
75
+
76
+ The commands above let you repeat the check. See npm's [signature and attestation verification](https://docs.npmjs.com/cli/v11/commands/npm-audit/) and [viewing provenance](https://docs.npmjs.com/viewing-package-provenance/) documentation for current verification behavior.
77
+
78
+ ## Publishing provenance is a maintainer action
79
+
80
+ The 0.13.0 and 0.13.1 registry metadata contain signatures but no provenance attestations. To add provenance to a future release, the maintainer must choose an authorized supported build/publish workflow, configure the correct repository identity and npm permissions, publish the exact tested artifact, and verify the resulting registry attestation afterward. A local `npm pack`, `gitHead`, checksum, badge or successful CI run is not a substitute for a verified attestation. Do not label older releases retroactively as provenance-verified.
81
+
82
+ npm describes the supported providers and identity requirements in [generating provenance](https://docs.npmjs.com/generating-provenance-statements/) and [trusted publishing](https://docs.npmjs.com/trusted-publishers/). Provenance provides origin/build evidence, not proof that source code is safe.
83
+
84
+ ## Support and reporting boundaries
85
+
86
+ For ordinary bugs, provide a minimal reproducible project, exact Redweb/Node/npm/TypeScript versions, operating system, decorator mode, sanitized logs, and the failing HTTP/WebSocket sequence in the [issue tracker](https://github.com/lakam99/redweb/issues). Never include tokens, cookies, passwords, private database contents or customer traffic.
87
+
88
+ There is no paid support contract, response-time SLA or long-term backport policy established by these files. No private vulnerability contact is invented here. The repository inspection on 2026-08-30 reported no published security policy; the maintainer still needs to establish a private reporting channel and its handling policy before the project claims one. Do not disclose a suspected vulnerability or working exploit in a public bug report merely because that is the only linked tracker.
@@ -1,78 +1,78 @@
1
- # Understand failures before retrying
2
-
3
- Status: included in `redweb@0.15.0`.
4
-
5
- Authentication identifies a visitor. Authorization decides what that visitor may do. Validation checks an input's shape. An application failure means server code or a dependency failed; it is not evidence that the visitor supplied bad credentials.
6
-
7
- Redweb keeps these boundaries separate. It does not automatically retry failed actions, undo application writes, or guarantee exactly-once delivery.
8
-
9
- ## Reading a failed connection
10
-
11
- Before a WebSocket opens, Redweb sends an HTTP rejection with a fixed `Redweb-Error` header and `Cache-Control: no-store`. There is no error body and no callback exception text. Node's `ws` client can inspect it:
12
-
13
- ```typescript
14
- import WebSocket from 'ws';
15
-
16
- const socket = new WebSocket('ws://127.0.0.1:8181/match?redwebVersion=1');
17
- socket.on('unexpected-response', (_request, response) => {
18
- console.error(response.statusCode, response.headers['redweb-error']);
19
- response.resume();
20
- socket.terminate();
21
- });
22
- socket.on('error', () => console.error('Connection did not open.'));
23
- ```
24
-
25
- This is a Node diagnostic example, not browser code. Native browser WebSocket JavaScript cannot inspect handshake status or response headers. Use the browser network inspector during development and your application's normal HTTP sign-in/status flow for user-facing guidance. A generic browser socket error alone cannot distinguish rejected credentials from networking, origin, protocol, or server failures. Proxies may replace or strip responses.
26
-
27
- | Code | HTTP status | Meaning and next step |
28
- | --- | --- | --- |
29
- | `REQUEST_INVALID` | 400 | The upgrade request cannot be represented safely. Correct the request or server middleware. |
30
- | `AUTHENTICATION_REQUIRED` | 401 | Identity was rejected, or the page session is missing, expired, already attached, or mismatched. Obtain valid credentials/a fresh page; do not retry the same rejected credentials in a loop. |
31
- | `ORIGIN_DENIED` | 403 | Browser origin was missing or not allowed. Correct the trusted-origin configuration; do not disable origin checks to hide the failure. |
32
- | `ACCESS_DENIED` | 403 | The page permission policy denied access. Obtain permission before retrying. |
33
- | `PLACEMENT_DENIED` | 403 | Placement explicitly rejected the connection. Follow application placement rules. |
34
- | `PROTOCOL_UNSUPPORTED` | 426 | Negotiation requires a supported version. `Redweb-Versions` lists supported versions; use a compatible client and contract. |
35
- | `AUTHENTICATION_FAILED` | 500 | The rendered-page identity callback failed. Investigate the application or identity provider. |
36
- | `ADMISSION_FAILED` | 500 | Admission/origin/placement code, a page upgrade policy, or the upgrade pipeline failed. This is not a bad-password response. |
37
- | `PLACEMENT_INVALID` | 500 | Placement returned an unsafe or disallowed redirect. Repair the server-side placement result/allowlist. |
38
- | `AUTHENTICATION_TIMEOUT`, `ACCESS_TIMEOUT`, `ADMISSION_TIMEOUT` | 503 | The relevant stage exceeded its deadline. Check the dependency and use bounded reconnect backoff only when appropriate. |
39
- | `AUTHENTICATION_CANCELLED`, `ACCESS_CANCELLED`, `ADMISSION_CANCELLED` | 503 | The relevant lifetime ended. Start a new permitted attempt rather than reusing a revoked page/session. A disconnected peer may receive no response. |
40
- | `ACCESS_CAPACITY`, `ADMISSION_CAPACITY` | 503 | Bounded authorization/admission work or connection capacity is exhausted. Wait and back off; do not retry in a tight loop. |
41
- | `SERVER_DRAINING`, `ROUTE_UNAVAILABLE` | 503 | The service is draining or the route is not ready. Reconnect to a ready instance according to the application's routing policy. |
42
-
43
- Accepted placement redirects remain HTTP 307 with the validated `Location`, no error code, and no-store caching. A redirect is not proof that the destination will admit the same credentials. Never forward credentials to arbitrary redirect destinations.
44
-
45
- Raw route authentication preserves its existing contract: only literal `false` rejects the identity; application-owned principal objects remain supported. Page authentication requires its documented primitive identity. Do not rely on a raw callback returning `undefined` to deny access.
46
-
47
- ## Page requests
48
-
49
- Page HTTP failures return `{ "error": { "code": "...", "message": "..." } }` with `Cache-Control: private, no-store`. Authentication and authorization use the categories above. `PAGE_CAPACITY` is 503; `PAGE_FAILED` is a sanitized 500 for construction, loading, or rendering failures, including public pages. Unknown application error text and Express development stacks are not returned. Typed errors are reconstructed from the fixed catalogue rather than trusting mutable status/message fields.
50
-
51
- If the response is already closed, Redweb does not write another response. If headers were already sent by application middleware, the connection is closed instead of appending a misleading JSON error. Redweb cannot retract content your middleware already sent or sanitize arbitrary HTTP routes you mount yourself.
52
-
53
- ## Actions and established sockets
54
-
55
- Once connected, failures use the existing protocol error envelope and request ID when available. Unversioned room-entry failures use `{ code, error }`; other legacy unversioned failures retain `{ error }` without a structured code. The client may still disconnect before receiving the response. Typed permission/input errors are normalized again at the final send boundary, so application catch/rethrow code cannot accidentally expose appended private exception text.
56
-
57
- | Boundary | Diagnostic | What Redweb guarantees |
58
- | --- | --- | --- |
59
- | Action input | `ACTION_INVALID_INPUT` | The action method was not invoked. Correct the form values. |
60
- | Action input lifetime | `ACTION_VALIDATION_TIMEOUT`, `ACTION_CANCELLED` | Validation did not complete within its lifetime; the action method was not invoked. |
61
- | Action/room permission | `ACCESS_DENIED`, `ACCESS_TIMEOUT`, `ACCESS_CANCELLED`, `ACCESS_CAPACITY` | That failed permission check did not commit room entry or invoke the guarded action. Existing memberships and prior actions are separate. These responses do not inherently close the socket. |
62
- | Browser send | `ACTION_OFFLINE`, `ACTION_CAPACITY` | This browser action was not sent. Reconnect or wait before deliberately trying again. |
63
- | Socket envelope/contract | `INVALID_MESSAGE`, `INVALID_PAYLOAD`, `UNKNOWN_HANDLER` | The requested handler callback was not invoked. Correct the message/contract. These paths generally close the connection; they are not automatic retry signals. |
64
- | Application/validator/output bug | `HANDLER_FAILED` | The operation failed; application effects may already have happened. Inspect authoritative state before resubmitting. |
65
-
66
- An input validator, identity lookup, or permission callback can itself perform external work. A “method was not invoked” result does not promise those callbacks had no side effects. Keep validators and policies free of writes where practical; use explicit idempotency keys and durable transactions for application operations that may be retried.
67
-
68
- Those non-invocation guarantees describe failures produced by Redweb's validation and permission gates. They do not apply to application code deliberately throwing an internal typed error or sending the same diagnostic after its own work has begun.
69
-
70
- ## Deadlines, cancellation, and disclosure limits
71
-
72
- Raw admission shares the bounded-operation implementation used by other policy/validation paths. It checks the deadline between origin, identity, and placement stages, so a timed-out or cancelled stage cannot start the next stage after eventually returning. It retains its actual evaluation promise in admission accounting until that evaluation settles. Synchronous JavaScript cannot be interrupted; a callback that blocks the event loop delays timeout observation, but an overdue result cannot admit a connection.
73
-
74
- Page identity and permission evaluation also have their own deadlines and session/revocation signals. The outer raw-admission deadline does not forcibly stop those nested callbacks or their external I/O. Cancellation of observation is not cancellation of database/network side effects. Honor available signals, set downstream timeouts, and never treat this as a sandbox for untrusted callback code.
75
-
76
- Default handler responses are sanitized. Raw routes deliberately configured with `exposeErrors: true` opt into disclosing handler exception text; do not enable that in production. Existing application/logger hooks may receive original errors and client metadata, so logs require access controls and redaction. The new upgrade pipeline logs only fixed admission failure details, and a throwing logger cannot prevent upgrade rejection or reservation cleanup.
77
-
78
- See [private rooms](ROOM_AUTHORIZATION.md), [socket contracts](SOCKET_CONTRACTS.md), and [operating socket services](MULTIPLAYER_OPERATIONS.md) for their complete limits. A successful `send` means accepted by the local transport, not acknowledged application delivery.
1
+ # Understand failures before retrying
2
+
3
+ Status: included in `redweb@0.16.2`.
4
+
5
+ Authentication identifies a visitor. Authorization decides what that visitor may do. Validation checks an input's shape. An application failure means server code or a dependency failed; it is not evidence that the visitor supplied bad credentials.
6
+
7
+ Redweb keeps these boundaries separate. It does not automatically retry failed actions, undo application writes, or guarantee exactly-once delivery.
8
+
9
+ ## Reading a failed connection
10
+
11
+ Before a WebSocket opens, Redweb sends an HTTP rejection with a fixed `Redweb-Error` header and `Cache-Control: no-store`. There is no error body and no callback exception text. Node's `ws` client can inspect it:
12
+
13
+ ```typescript
14
+ import WebSocket from 'ws';
15
+
16
+ const socket = new WebSocket('ws://127.0.0.1:8181/match?redwebVersion=1');
17
+ socket.on('unexpected-response', (_request, response) => {
18
+ console.error(response.statusCode, response.headers['redweb-error']);
19
+ response.resume();
20
+ socket.terminate();
21
+ });
22
+ socket.on('error', () => console.error('Connection did not open.'));
23
+ ```
24
+
25
+ This is a Node diagnostic example, not browser code. Native browser WebSocket JavaScript cannot inspect handshake status or response headers. Use the browser network inspector during development and your application's normal HTTP sign-in/status flow for user-facing guidance. A generic browser socket error alone cannot distinguish rejected credentials from networking, origin, protocol, or server failures. Proxies may replace or strip responses.
26
+
27
+ | Code | HTTP status | Meaning and next step |
28
+ | --- | --- | --- |
29
+ | `REQUEST_INVALID` | 400 | The upgrade request cannot be represented safely. Correct the request or server middleware. |
30
+ | `AUTHENTICATION_REQUIRED` | 401 | Identity was rejected, or the page session is missing, expired, already attached, or mismatched. Obtain valid credentials/a fresh page; do not retry the same rejected credentials in a loop. |
31
+ | `ORIGIN_DENIED` | 403 | Browser origin was missing or not allowed. Correct the trusted-origin configuration; do not disable origin checks to hide the failure. |
32
+ | `ACCESS_DENIED` | 403 | The page permission policy denied access. Obtain permission before retrying. |
33
+ | `PLACEMENT_DENIED` | 403 | Placement explicitly rejected the connection. Follow application placement rules. |
34
+ | `PROTOCOL_UNSUPPORTED` | 426 | Negotiation requires a supported version. `Redweb-Versions` lists supported versions; use a compatible client and contract. |
35
+ | `AUTHENTICATION_FAILED` | 500 | The rendered-page identity callback failed. Investigate the application or identity provider. |
36
+ | `ADMISSION_FAILED` | 500 | Admission/origin/placement code, a page upgrade policy, or the upgrade pipeline failed. This is not a bad-password response. |
37
+ | `PLACEMENT_INVALID` | 500 | Placement returned an unsafe or disallowed redirect. Repair the server-side placement result/allowlist. |
38
+ | `AUTHENTICATION_TIMEOUT`, `ACCESS_TIMEOUT`, `ADMISSION_TIMEOUT` | 503 | The relevant stage exceeded its deadline. Check the dependency and use bounded reconnect backoff only when appropriate. |
39
+ | `AUTHENTICATION_CANCELLED`, `ACCESS_CANCELLED`, `ADMISSION_CANCELLED` | 503 | The relevant lifetime ended. Start a new permitted attempt rather than reusing a revoked page/session. A disconnected peer may receive no response. |
40
+ | `ACCESS_CAPACITY`, `ADMISSION_CAPACITY` | 503 | Bounded authorization/admission work or connection capacity is exhausted. Wait and back off; do not retry in a tight loop. |
41
+ | `SERVER_DRAINING`, `ROUTE_UNAVAILABLE` | 503 | The service is draining or the route is not ready. Reconnect to a ready instance according to the application's routing policy. |
42
+
43
+ Accepted placement redirects remain HTTP 307 with the validated `Location`, no error code, and no-store caching. A redirect is not proof that the destination will admit the same credentials. Never forward credentials to arbitrary redirect destinations.
44
+
45
+ Raw route authentication preserves its existing contract: only literal `false` rejects the identity; application-owned principal objects remain supported. Page authentication requires its documented primitive identity. Do not rely on a raw callback returning `undefined` to deny access.
46
+
47
+ ## Page requests
48
+
49
+ Page HTTP failures return `{ "error": { "code": "...", "message": "..." } }` with `Cache-Control: private, no-store`. Authentication and authorization use the categories above. `PAGE_CAPACITY` is 503; `PAGE_FAILED` is a sanitized 500 for construction, loading, or rendering failures, including public pages. Unknown application error text and Express development stacks are not returned. Typed errors are reconstructed from the fixed catalogue rather than trusting mutable status/message fields.
50
+
51
+ If the response is already closed, Redweb does not write another response. If headers were already sent by application middleware, the connection is closed instead of appending a misleading JSON error. Redweb cannot retract content your middleware already sent or sanitize arbitrary HTTP routes you mount yourself.
52
+
53
+ ## Actions and established sockets
54
+
55
+ Once connected, failures use the existing protocol error envelope and request ID when available. Unversioned room-entry failures use `{ code, error }`; other legacy unversioned failures retain `{ error }` without a structured code. The client may still disconnect before receiving the response. Typed permission/input errors are normalized again at the final send boundary, so application catch/rethrow code cannot accidentally expose appended private exception text.
56
+
57
+ | Boundary | Diagnostic | What Redweb guarantees |
58
+ | --- | --- | --- |
59
+ | Action input | `ACTION_INVALID_INPUT` | The action method was not invoked. Correct the form values. |
60
+ | Action input lifetime | `ACTION_VALIDATION_TIMEOUT`, `ACTION_CANCELLED` | Validation did not complete within its lifetime; the action method was not invoked. |
61
+ | Action/room permission | `ACCESS_DENIED`, `ACCESS_TIMEOUT`, `ACCESS_CANCELLED`, `ACCESS_CAPACITY` | That failed permission check did not commit room entry or invoke the guarded action. Existing memberships and prior actions are separate. These responses do not inherently close the socket. |
62
+ | Browser send | `ACTION_OFFLINE`, `ACTION_CAPACITY` | This browser action was not sent. Reconnect or wait before deliberately trying again. |
63
+ | Socket envelope/contract | `INVALID_MESSAGE`, `INVALID_PAYLOAD`, `UNKNOWN_HANDLER` | The requested handler callback was not invoked. Correct the message/contract. These paths generally close the connection; they are not automatic retry signals. |
64
+ | Application/validator/output bug | `HANDLER_FAILED` | The operation failed; application effects may already have happened. Inspect authoritative state before resubmitting. |
65
+
66
+ An input validator, identity lookup, or permission callback can itself perform external work. A “method was not invoked” result does not promise those callbacks had no side effects. Keep validators and policies free of writes where practical; use explicit idempotency keys and durable transactions for application operations that may be retried.
67
+
68
+ Those non-invocation guarantees describe failures produced by Redweb's validation and permission gates. They do not apply to application code deliberately throwing an internal typed error or sending the same diagnostic after its own work has begun.
69
+
70
+ ## Deadlines, cancellation, and disclosure limits
71
+
72
+ Raw admission shares the bounded-operation implementation used by other policy/validation paths. It checks the deadline between origin, identity, and placement stages, so a timed-out or cancelled stage cannot start the next stage after eventually returning. It retains its actual evaluation promise in admission accounting until that evaluation settles. Synchronous JavaScript cannot be interrupted; a callback that blocks the event loop delays timeout observation, but an overdue result cannot admit a connection.
73
+
74
+ Page identity and permission evaluation also have their own deadlines and session/revocation signals. The outer raw-admission deadline does not forcibly stop those nested callbacks or their external I/O. Cancellation of observation is not cancellation of database/network side effects. Honor available signals, set downstream timeouts, and never treat this as a sandbox for untrusted callback code.
75
+
76
+ Default handler responses are sanitized. Raw routes deliberately configured with `exposeErrors: true` opt into disclosing handler exception text; do not enable that in production. Existing application/logger hooks may receive original errors and client metadata, so logs require access controls and redaction. The new upgrade pipeline logs only fixed admission failure details, and a throwing logger cannot prevent upgrade rejection or reservation cleanup.
77
+
78
+ See [private rooms](ROOM_AUTHORIZATION.md), [socket contracts](SOCKET_CONTRACTS.md), and [operating socket services](MULTIPLAYER_OPERATIONS.md) for their complete limits. A successful `send` means accepted by the local transport, not acknowledged application delivery.
@@ -1,42 +1,42 @@
1
- # Shared socket contracts
2
-
3
- Status: included in `redweb@0.15.0`.
4
-
5
- A contract declares message payloads once. The same schema supplies runtime validation and inferred TypeScript types for senders and handlers. The URL still selects the route (`/match`), and the envelope's `type` selects an individual handler (`join`, `move`, `resume`). No socket decorators or second action dispatcher are required.
6
-
7
- Start with `npx --yes redweb@0.15.0 init my-match --template socket`. The complete maintained example lives in [the socket recipe](../recipes/socket/README.md): [contract](../recipes/socket/contract.ts), [handlers](../recipes/socket/handlers.ts), [server](../recipes/socket/app.tsx), and [real-network tests](../recipes/socket/app.test.cjs).
8
-
9
- Session ownership is separate from room fan-out. For authenticated group delivery,
10
- see [room authorization](ROOM_AUTHORIZATION.md) and the complete
11
- [shared page/private-room example](snippets/room-access.tsx).
12
-
1
+ # Shared socket contracts
2
+
3
+ Status: included in `redweb@0.16.2`.
4
+
5
+ A contract declares message payloads once. The same schema supplies runtime validation and inferred TypeScript types for senders and handlers. The URL still selects the route (`/match`), and the envelope's `type` selects an individual handler (`join`, `move`, `resume`). No socket decorators or second action dispatcher are required.
6
+
7
+ Start with `npx --yes redweb@0.16.2 init my-match --template socket`. The complete maintained example lives in [the socket recipe](../recipes/socket/README.md): [contract](../recipes/socket/contract.ts), [handlers](../recipes/socket/handlers.ts), [server](../recipes/socket/app.tsx), and [real-network tests](../recipes/socket/app.test.cjs).
8
+
9
+ Session ownership is separate from room fan-out. For authenticated group delivery,
10
+ see [room authorization](ROOM_AUTHORIZATION.md) and the complete
11
+ [shared page/private-room example](snippets/room-access.tsx).
12
+
13
13
  ## One schema, two sides
14
14
 
15
15
  Redweb 0.15.0 also supports [typed handlers in server TSX](SOCKET_PAGES.md)
16
16
  with per-connection page state; earlier releases do not include that extension.
17
-
18
- Import `defineSocketContract` from `redweb/contract` for a shared module, or from `redweb` in server-only code. The standalone entry does not import the HTTP server or Node socket listener. Browser consumers need a bundler capable of consuming the CommonJS package; this is not a native browser script URL or a React integration.
19
-
20
- `defineSocketContract(version, schemas, options?)` accepts an object mapping message names to [Standard Schema v1](https://standardschema.dev/) validators. Zod is used by the starter, but is not a Redweb runtime dependency. Use your existing compatible schema library. The version must match the negotiated protocol version, and `error` is reserved for protocol errors. Contracts support 1–256 types, names up to 256 characters, and versions up to 64 characters.
21
-
22
- - `contract.handler(type, callback)` returns a `BaseHandler` subclass accepted by `SocketRoute.handlers`. The callback receives `(socket, payload, message)` after validation. Payload and message types are inferred from the schema output. Register one handler per inbound type; declaring an outbound type does not expose a handler for it.
23
- - `contract.protocol` supplies the immutable `{ versions: [version] }` route configuration. The route requires negotiation: a browser URL can use `?redwebVersion=1`. Contract handlers refuse a socket negotiated to a different version.
24
- - `contract.client(socket)` wraps an existing browser or Node WebSocket-like object with `send(data)`. It neither opens the connection nor reconnects it. Wait for the socket to open before sending.
25
- - `client.send(type, payload, metadata?)` validates and sends a JSON envelope. `client.envelope(...)` validates and returns the envelope without sending it. Senders use schema **input** types; receivers get schema **output** types. Metadata supports the existing `requestId` and `sequence` fields.
26
- - `client.parse(frame)` decodes and validates a response. It accepts text, byte arrays, ArrayBuffers, or a message event containing them. The result is a type-discriminated message union or protocol error. Catch parse failures in asynchronous message listeners.
27
- - `contract.send(serverSocket, type, payload, metadata?)` validates server output and uses the existing `sendEvent` transport path, preserving backpressure behavior. Its boolean result means the transport accepted the send, not that a peer received or acknowledged it.
28
- - `contract.parse(type, unknownPayload)` runs validation directly without sending. It returns inferred output; this method alone does not JSON-serialize its argument.
29
-
30
- ## Validation and wire behavior
31
-
32
- Socket payloads use JSON. Declare ISO strings rather than `Date` objects on the wire, and encode bigint values as strings. Top-level `undefined`, bigint, and cyclic values cannot be sent. JSON conversion occurs before sender validation, so the validator sees the representation that a receiver will actually get.
33
-
34
- Sender validation uses an isolated copy. The transmitted payload remains the original JSON input snapshot even if a validator mutates its argument. Receiver validation produces transformed output for the application. Validators execute on both sending and receiving sides; use deterministic validators and avoid side effects such as writing to a database inside a transform.
35
-
36
- Validation accepts asynchronous validators and awaits thenable outputs within the same error boundary/deadline. The default `validationTimeoutMs` is 5,000; configure a positive integer no greater than 2,147,483,647. Overdue validation is rejected, including synchronous work that finishes after its deadline. **This does not preempt synchronous JavaScript or cancel a validator's external work.** Validators are trusted application code, not a CPU sandbox. Keep expensive work out of validation and enforce transport payload/queue/rate limits separately.
37
-
38
- Invalid inbound payloads never reach the handler callback. The peer receives sanitized `INVALID_PAYLOAD` and closes with code 1008. Validator diagnostics are not exposed because they may contain private data. Unknown inbound handler types retain `UNKNOWN_HANDLER`; incompatible versions are rejected during negotiation. Ordinary uncontracted routes keep their existing behavior.
39
-
40
- Invalid output from `contract.send()` rejects locally. If that rejection escapes a handler, it is an application failure (`HANDLER_FAILED`, close 1011), not a client policy violation. Handle intentional application rejections explicitly if you want a recoverable protocol response; schema validation does not replace authentication, authorization, or game rules.
41
-
42
- The match recipe uses private, in-memory bearer sessions solely to demonstrate join/move/resume. Read its security, restart, expiry, and scaling boundaries before adapting it.
17
+
18
+ Import `defineSocketContract` from `redweb/contract` for a shared module, or from `redweb` in server-only code. The standalone entry does not import the HTTP server or Node socket listener. Browser consumers need a bundler capable of consuming the CommonJS package; this is not a native browser script URL or a React integration.
19
+
20
+ `defineSocketContract(version, schemas, options?)` accepts an object mapping message names to [Standard Schema v1](https://standardschema.dev/) validators. Zod is used by the starter, but is not a Redweb runtime dependency. Use your existing compatible schema library. The version must match the negotiated protocol version, and `error` is reserved for protocol errors. Contracts support 1–256 types, names up to 256 characters, and versions up to 64 characters.
21
+
22
+ - `contract.handler(type, callback)` returns a `BaseHandler` subclass accepted by `SocketRoute.handlers`. The callback receives `(socket, payload, message)` after validation. Payload and message types are inferred from the schema output. Register one handler per inbound type; declaring an outbound type does not expose a handler for it.
23
+ - `contract.protocol` supplies the immutable `{ versions: [version] }` route configuration. The route requires negotiation: a browser URL can use `?redwebVersion=1`. Contract handlers refuse a socket negotiated to a different version.
24
+ - `contract.client(socket)` wraps an existing browser or Node WebSocket-like object with `send(data)`. It neither opens the connection nor reconnects it. Wait for the socket to open before sending.
25
+ - `client.send(type, payload, metadata?)` validates and sends a JSON envelope. `client.envelope(...)` validates and returns the envelope without sending it. Senders use schema **input** types; receivers get schema **output** types. Metadata supports the existing `requestId` and `sequence` fields.
26
+ - `client.parse(frame)` decodes and validates a response. It accepts text, byte arrays, ArrayBuffers, or a message event containing them. The result is a type-discriminated message union or protocol error. Catch parse failures in asynchronous message listeners.
27
+ - `contract.send(serverSocket, type, payload, metadata?)` validates server output and uses the existing `sendEvent` transport path, preserving backpressure behavior. Its boolean result means the transport accepted the send, not that a peer received or acknowledged it.
28
+ - `contract.parse(type, unknownPayload)` runs validation directly without sending. It returns inferred output; this method alone does not JSON-serialize its argument.
29
+
30
+ ## Validation and wire behavior
31
+
32
+ Socket payloads use JSON. Declare ISO strings rather than `Date` objects on the wire, and encode bigint values as strings. Top-level `undefined`, bigint, and cyclic values cannot be sent. JSON conversion occurs before sender validation, so the validator sees the representation that a receiver will actually get.
33
+
34
+ Sender validation uses an isolated copy. The transmitted payload remains the original JSON input snapshot even if a validator mutates its argument. Receiver validation produces transformed output for the application. Validators execute on both sending and receiving sides; use deterministic validators and avoid side effects such as writing to a database inside a transform.
35
+
36
+ Validation accepts asynchronous validators and awaits thenable outputs within the same error boundary/deadline. The default `validationTimeoutMs` is 5,000; configure a positive integer no greater than 2,147,483,647. Overdue validation is rejected, including synchronous work that finishes after its deadline. **This does not preempt synchronous JavaScript or cancel a validator's external work.** Validators are trusted application code, not a CPU sandbox. Keep expensive work out of validation and enforce transport payload/queue/rate limits separately.
37
+
38
+ Invalid inbound payloads never reach the handler callback. The peer receives sanitized `INVALID_PAYLOAD` and closes with code 1008. Validator diagnostics are not exposed because they may contain private data. Unknown inbound handler types retain `UNKNOWN_HANDLER`; incompatible versions are rejected during negotiation. Ordinary uncontracted routes keep their existing behavior.
39
+
40
+ Invalid output from `contract.send()` rejects locally. If that rejection escapes a handler, it is an application failure (`HANDLER_FAILED`, close 1011), not a client policy violation. Handle intentional application rejections explicitly if you want a recoverable protocol response; schema validation does not replace authentication, authorization, or game rules.
41
+
42
+ The match recipe uses private, in-memory bearer sessions solely to demonstrate join/move/resume. Read its security, restart, expiry, and scaling boundaries before adapting it.