redweb 0.13.5 → 0.15.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.
- package/CHANGELOG.md +20 -3
- package/README.md +289 -288
- package/contract.d.ts +11 -3
- package/docs/APPLICATION.md +98 -0
- package/docs/CLI.md +1 -1
- package/docs/CLIENT_DEVELOPMENT.md +9 -5
- package/docs/COVERAGE_SCOPE_AUDIT.md +7 -0
- package/docs/DEFINE_APP_VERIFICATION.md +101 -0
- package/docs/DEVELOPMENT.md +1 -1
- package/docs/GETTING_STARTED.md +1 -1
- package/docs/LIVE_HTML.md +2 -2
- package/docs/MIGRATION.md +1 -1
- package/docs/MULTIPLAYER_OPERATIONS.md +6 -0
- package/docs/RELEASE_TRUST.md +29 -6
- package/docs/RUNTIME_DIAGNOSTICS.md +1 -1
- package/docs/SOCKET_CONTRACTS.md +6 -3
- package/docs/SOCKET_PAGES.md +99 -0
- package/docs/SOCKET_PAGE_RELEASE_PREPARATION.md +120 -0
- package/docs/SOCKET_PAGE_VERIFICATION.md +85 -0
- package/docs/STARTER_LIFECYCLE_VERIFICATION.md +9 -0
- package/docs/generated.json +2217 -2154
- package/docs/guides/http-websocket.md +4 -4
- package/docs/guides/jsx-without-react.md +1 -1
- package/docs/reference.json +40 -1
- package/docs/releases/0.14.0.json +2208 -0
- package/docs/releases/0.15.0.json +2217 -0
- package/docs/topics.json +3 -1
- package/examples/live-html/cards.js +87 -86
- package/examples/live-html/cards.ts +3 -2
- package/examples/live-html/chatroom.js +210 -207
- package/examples/live-html/chatroom.tsx +6 -2
- package/examples/live-html/components.js +103 -102
- package/examples/live-html/components.ts +3 -2
- package/examples/live-html/counter.js +74 -73
- package/examples/live-html/counter.ts +3 -2
- package/examples/live-html/jsx-page.js +2 -1
- package/examples/live-html/jsx-page.tsx +3 -2
- package/index.d.ts +59 -7
- package/index.js +3 -0
- package/package.json +8 -5
- package/recipes/chat/app.test.cjs +3 -1
- package/recipes/chat/app.tsx +4 -7
- package/recipes/dashboard/app.test.cjs +10 -10
- package/recipes/dashboard/app.tsx +29 -29
- package/recipes/http-ws/README.md +1 -1
- package/recipes/http-ws/app.test.cjs +8 -10
- package/recipes/http-ws/app.tsx +9 -20
- package/recipes/realtime/app.tsx +3 -6
- package/recipes/shared/README.md +10 -1
- package/recipes/shared/lifecycle.test.cjs +81 -0
- package/recipes/shared/network.cjs +10 -5
- package/recipes/site/app.tsx +3 -6
- package/recipes/socket/app.tsx +3 -10
- package/src/Application.js +239 -0
- package/src/StartupCleanup.js +24 -0
- package/src/cli/SourceInspector.js +5 -0
- package/src/cli/templates.js +6 -6
- package/src/htmx/Jsx.js +2 -2
- package/src/htmx/LiveHtmlServer.js +14 -5
- package/src/htmx/PageManager.js +13 -8
- package/src/htmx/PageSocketRoute.js +132 -0
- package/src/htmx/ReactiveRenderer.js +8 -2
- package/src/htmx/SocketAction.js +19 -0
- package/src/htmx/metadata.js +6 -2
- package/src/ws/BaseHandler.js +6 -4
- package/src/ws/BaseSocketServer.js +13 -13
- package/src/ws/HandlerGuard.js +4 -0
- package/src/ws/SocketAction.js +16 -0
- package/src/ws/SocketContract.js +3 -2
- package/src/ws/SocketRoute.js +9 -4
- package/recipes/shared/run-app.test.cjs +0 -158
- package/recipes/shared/run-app.ts +0 -50
|
@@ -8,12 +8,12 @@ Imagine one front door with two signs. Ordinary HTTP visitors ask for a page or
|
|
|
8
8
|
|
|
9
9
|
## Follow the design
|
|
10
10
|
|
|
11
|
-
1. `
|
|
12
|
-
2.
|
|
11
|
+
1. `defineApp` describes one application without opening a port. `httpServices` registers `/health`; `publicPaths: []` avoids exposing an incidental working-directory folder.
|
|
12
|
+
2. Register `ChatRoute` in `sockets`, then call `app.run()`. Redweb creates one HTTP server and attaches its WebSocket upgrade listener before opening the port.
|
|
13
13
|
3. The URL selects `ChatRoute`. A raw JSON message with `type: "hello"` selects `Hello`; there is no secondary action dispatcher.
|
|
14
|
-
4.
|
|
14
|
+
4. The application is the one cleanup owner. Its `shutdown()` processes route failures and still closes the shared HTTP peers. Signal handling and cleanup deadlines are built into Redweb rather than copied into the generated project.
|
|
15
15
|
|
|
16
|
-
The
|
|
16
|
+
The low-level server APIs still support caller-owned listeners. Use [application composition](../APPLICATION.md) for the unified entry point and [migration and ownership guidance](../MIGRATION.md) when adapting an existing application; do not let two independent services compete to close the same listener.
|
|
17
17
|
|
|
18
18
|
## Check that it works
|
|
19
19
|
|
|
@@ -11,7 +11,7 @@ The page class is a recipe and the server is the kitchen. `render()` prepares HT
|
|
|
11
11
|
1. The initializer supplies `redweb/tsconfig.json` inheritance, TypeScript, the stylesheet and the entrypoint helper. Keep the file as `.tsx`; do not point its JSX settings at `react/jsx-runtime`.
|
|
12
12
|
2. `defineSite()` supplies one layout and CSS declaration. Its page decorators register `/` and `/about`, with metadata beside each page.
|
|
13
13
|
3. Each `render()` returns ordinary TSX. Function components can share presentation; page-specific data remains in your server code. Text and attribute values are escaped, and URL protocols are restricted.
|
|
14
|
-
4. `
|
|
14
|
+
4. `defineApp({ pages: [HomePage, AboutPage] })` combines both pages on one listener. `app.run()` owns startup and bounded shutdown; importing the definition starts nothing.
|
|
15
15
|
|
|
16
16
|
Keep CSS in external files. The [rendering reference](../LIVE_HTML.md) covers components, templates, assets and static export. For interactive pages, start from the [realtime counter](../../recipes/realtime/README.md): assignments to decorated state update the browser through Redweb's runtime. Non-live site pages do not acquire that behavior just because their markup is JSX.
|
|
17
17
|
|
package/docs/reference.json
CHANGED
|
@@ -1,5 +1,44 @@
|
|
|
1
1
|
{
|
|
2
2
|
"api": [
|
|
3
|
+
{
|
|
4
|
+
"id": "defineapp",
|
|
5
|
+
"name": "defineApp / Application",
|
|
6
|
+
"type": "Application",
|
|
7
|
+
"summary": "Define pages, socket routes and application services together. Nothing listens until run(); one owner starts and stops the shared HTTP/WebSocket listener.",
|
|
8
|
+
"usage": "import { defineApp } from 'redweb';\nimport { HomePage, DashboardPage } from './pages';\nimport { MatchRoute, ChatRoute } from './sockets';\nimport { GameSimulation } from './simulation';\n\nconst app = defineApp({\n pages: [HomePage, DashboardPage],\n sockets: [MatchRoute, ChatRoute],\n services: [GameSimulation],\n port: 8181,\n});\n\nawait app.run();",
|
|
9
|
+
"options": [
|
|
10
|
+
"pages: decorated page classes (default [])",
|
|
11
|
+
"sockets: SocketRoute classes (default [])",
|
|
12
|
+
"services: application-wide classes with onInit(app, signal) and onShutdown() (default [])",
|
|
13
|
+
"port: number (default 8181); use 0 for an ephemeral test port",
|
|
14
|
+
"bind: string (default 0.0.0.0)",
|
|
15
|
+
"httpServices: existing Express service descriptors; route-specific SocketService classes remain on socket routes",
|
|
16
|
+
"startupTimeoutMs / shutdownTimeoutMs: total lifecycle budgets (default 5000 each)",
|
|
17
|
+
"signals: install owned process signal handling when run begins (default true); embedded applications/tests can set false",
|
|
18
|
+
"Existing live-page/HTTP options, including templateRoot, authentication, origins, server (Express app), development and ssl",
|
|
19
|
+
"Static export remains exportStatic(); defineApp does not accept a static export flag"
|
|
20
|
+
],
|
|
21
|
+
"methods": [
|
|
22
|
+
{ "name": "defineApp(options) / new Application(options)", "detail": "Create a deferred definition. Registration arrays are copied; imports and definitions open no port or process handlers." },
|
|
23
|
+
{ "name": "run(): Promise<Application>", "detail": "Initialize services in order and bind one HTTP/WS listener. Repeated calls share startup while running. A stopped application cannot restart." },
|
|
24
|
+
{ "name": "shutdown(): Promise<void>", "detail": "Cancel pending startup and perform bounded, idempotent cleanup. Close HTTP/socket resources before releasing application services in reverse order. Preserve cleanup errors." },
|
|
25
|
+
{ "name": "options", "detail": "Copied definition, available for defining independent test applications with port: 0 and signals: false. Captured objects and supplied Express apps are not deep-cloned." },
|
|
26
|
+
{ "name": "app / server / http / sockets / services", "detail": "Runtime Express application, native listener, HTTP adapter, optional WebSocket server and service instances. HTTP members are null before startup; await run before use." },
|
|
27
|
+
{ "name": "revoke(principal): Promise<number>", "detail": "Revoke matching live-page sessions; zero before live pages have been initialized." },
|
|
28
|
+
{ "name": "inspect(): DevelopmentSnapshot | null", "detail": "Return opt-in live-page inspection metadata, or null when unavailable/disabled." }
|
|
29
|
+
],
|
|
30
|
+
"article": {
|
|
31
|
+
"eli5": "One front door serves pages and ongoing socket conversations. The application prepares its staff before opening that door, then closes the door and sends the staff home in order.",
|
|
32
|
+
"useWhen": "Use it as the entry point for a multi-page site, a realtime UI, a routed socket backend, or their combination. Lower-level server classes remain available for custom ownership.",
|
|
33
|
+
"walkthrough": [
|
|
34
|
+
"Declare pages with decorators and socket routes with message-type handlers, then register their classes in one definition.",
|
|
35
|
+
"Acquire app-wide resources in service onInit(app, signal), not constructors. onInit can register Express endpoints through app.app before listening.",
|
|
36
|
+
"Await run to know startup succeeded; no separately stored HTTP server or second socket startup call is necessary. CommonJS entry points use an async function or handle the returned promise; top-level await requires a suitable ESM configuration.",
|
|
37
|
+
"For tests, use an ephemeral port, disable process signal ownership and await shutdown in cleanup. The generated applications ship real HTTP/socket and process tests."
|
|
38
|
+
],
|
|
39
|
+
"watchFor": "This is lifecycle composition, not dependency injection or durable/distributed state. Services must cooperate with cancellation and release partially acquired resources. Deadlines cannot interrupt synchronous event-loop blocking. Shared page-class closure objects stay shared; use separate classes/rooms when isolation is required."
|
|
40
|
+
}
|
|
41
|
+
},
|
|
3
42
|
{
|
|
4
43
|
"id": "httpserver",
|
|
5
44
|
"name": "HttpServer",
|
|
@@ -187,7 +226,7 @@
|
|
|
187
226
|
"handlers: array of handler classes (required)",
|
|
188
227
|
"services: array of SocketService subclasses (optional)",
|
|
189
228
|
"allowDuplicateConnections: allow multiple clients from the same IP",
|
|
190
|
-
"websocketOptions: options passed to ws WebSocketServer, such as maxPayload or perMessageDeflate",
|
|
229
|
+
"websocketOptions: options passed to ws WebSocketServer, such as maxPayload or perMessageDeflate; closeTimeout defaults to 5000 milliseconds (integer 1..2147483647) and bounds an already-started closing handshake, not healthy idle connections",
|
|
191
230
|
"admission: authenticate, validate origins, and optionally place a client before upgrade",
|
|
192
231
|
"maxPendingUpgrades: finite concurrent admission/negotiation work (default 64)",
|
|
193
232
|
"limits: connection, message-rate, pending-message, and outbound-buffer ceilings",
|