@timber-js/app 0.2.0-alpha.200 → 0.2.0-alpha.201
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/bin/timber.mjs +15 -1
- package/dist/_chunks/{actions-d1hCqnU3.js → actions-HUdJADAD.js} +3 -3
- package/dist/_chunks/{actions-d1hCqnU3.js.map → actions-HUdJADAD.js.map} +1 -1
- package/dist/_chunks/{build-manifest-DTmSGLRz.js → build-manifest-DWppEdLB.js} +2 -51
- package/dist/_chunks/build-manifest-DWppEdLB.js.map +1 -0
- package/dist/_chunks/{cache-api-ByagcC-J.js → cache-api-CAPbZTga.js} +2 -2
- package/dist/_chunks/{cache-api-ByagcC-J.js.map → cache-api-CAPbZTga.js.map} +1 -1
- package/dist/_chunks/{chains-Bpb0W4ax.js → chains-CBNA0Ozj.js} +3 -3
- package/dist/_chunks/{chains-Bpb0W4ax.js.map → chains-CBNA0Ozj.js.map} +1 -1
- package/dist/_chunks/{cli-check-D6VolrDV.js → cli-check-BzMGuIH6.js} +3 -3
- package/dist/_chunks/{cli-check-D6VolrDV.js.map → cli-check-BzMGuIH6.js.map} +1 -1
- package/dist/_chunks/{cli-schema-sync-D6rO-VcS.js → cli-schema-sync-DnXqcIIj.js} +2 -2
- package/dist/_chunks/{cli-schema-sync-D6rO-VcS.js.map → cli-schema-sync-DnXqcIIj.js.map} +1 -1
- package/dist/_chunks/{cloudflare-BFb__LYG.js → cloudflare-DxX1SU0g.js} +3 -3
- package/dist/_chunks/{cloudflare-BFb__LYG.js.map → cloudflare-DxX1SU0g.js.map} +1 -1
- package/dist/_chunks/{convention-lint-fRkwVwEH.js → convention-lint-DHOFvX5s.js} +5 -95
- package/dist/_chunks/convention-lint-DHOFvX5s.js.map +1 -0
- package/dist/_chunks/csp-nonce-hOGniaG4.js +227 -0
- package/dist/_chunks/csp-nonce-hOGniaG4.js.map +1 -0
- package/dist/_chunks/dev-server-DioP7tkQ.js +2288 -0
- package/dist/_chunks/dev-server-DioP7tkQ.js.map +1 -0
- package/dist/_chunks/{error-boundary-BfPHZjm0.js → error-boundary-BQKxl6EX.js} +11 -17
- package/dist/_chunks/{error-boundary-BfPHZjm0.js.map → error-boundary-BQKxl6EX.js.map} +1 -1
- package/dist/_chunks/{graph-cache-CP4GEmf9.js → graph-cache-Cv3njEH8.js} +2 -2
- package/dist/_chunks/{graph-cache-CP4GEmf9.js.map → graph-cache-Cv3njEH8.js.map} +1 -1
- package/dist/_chunks/{live-graph-D_2D32Ad.js → live-graph-VjHFF5EV.js} +3 -3
- package/dist/_chunks/{live-graph-D_2D32Ad.js.map → live-graph-VjHFF5EV.js.map} +1 -1
- package/dist/_chunks/{logger-uLBuGKDI.js → logger-DqJ2VoAY.js} +450 -458
- package/dist/_chunks/logger-DqJ2VoAY.js.map +1 -0
- package/dist/_chunks/{segment-keys-lqtdookO.js → metadata-routes-DSDjM_hJ.js} +2 -61
- package/dist/_chunks/metadata-routes-DSDjM_hJ.js.map +1 -0
- package/dist/_chunks/{poison-scan-Bm9Yyqk9.js → poison-scan-lEbz4pQE.js} +2 -2
- package/dist/_chunks/{poison-scan-Bm9Yyqk9.js.map → poison-scan-lEbz4pQE.js.map} +1 -1
- package/dist/_chunks/{scanner-AiazgH_f.js → scanner-B_tnqFcF.js} +37 -137
- package/dist/_chunks/scanner-B_tnqFcF.js.map +1 -0
- package/dist/_chunks/segment-keys-D5hu1hz4.js +62 -0
- package/dist/_chunks/segment-keys-D5hu1hz4.js.map +1 -0
- package/dist/_chunks/tree-match-CdbvYTBz.js +122 -0
- package/dist/_chunks/tree-match-CdbvYTBz.js.map +1 -0
- package/dist/_chunks/{walkers-B6XUtmqK.js → walkers-Cm3PC5JT.js} +2 -2
- package/dist/_chunks/{walkers-B6XUtmqK.js.map → walkers-Cm3PC5JT.js.map} +1 -1
- package/dist/adapters/cloudflare-dev.js +1 -1
- package/dist/adapters/cloudflare-kv-cache.js +1 -1
- package/dist/adapters/cloudflare.js +1 -1
- package/dist/analyze/crawl-entry.js +2 -2
- package/dist/analyze/graph-command.js +3 -3
- package/dist/cache/index.js +1 -1
- package/dist/cli.d.ts +7 -2
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +44 -7
- package/dist/cli.js.map +1 -1
- package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
- package/dist/client/browser-entry/action-queue.d.ts +20 -1
- package/dist/client/browser-entry/action-queue.d.ts.map +1 -1
- package/dist/client/browser-entry/rsc-stream.d.ts.map +1 -1
- package/dist/client/error-boundary.d.ts +3 -15
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +1 -1
- package/dist/client/error-reconstituter.d.ts +4 -4
- package/dist/client/error-reconstituter.d.ts.map +1 -1
- package/dist/client/internal.js +1 -1
- package/dist/dev-tools/debug-channel.d.ts +55 -0
- package/dist/dev-tools/debug-channel.d.ts.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -2119
- package/dist/index.js.map +1 -1
- package/dist/plugins/dev-server.d.ts +7 -0
- package/dist/plugins/dev-server.d.ts.map +1 -1
- package/dist/plugins/mdx.d.ts.map +1 -1
- package/dist/routing/convention-lint.d.ts.map +1 -1
- package/dist/routing/index.js +2 -2
- package/dist/routing/scanner.d.ts +4 -4
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/server/access-gate.d.ts +2 -2
- package/dist/server/deny-boundary.d.ts +3 -5
- package/dist/server/deny-boundary.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts +0 -1
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts +5 -12
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/index.js +2 -2
- package/dist/server/internal.js +20 -195
- package/dist/server/internal.js.map +1 -1
- package/dist/server/pipeline.d.ts +8 -0
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +15 -13
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts +3 -7
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/helpers.d.ts +6 -27
- package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/render-route.d.ts +1 -0
- package/dist/server/rsc-entry/render-route.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +4 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts +1 -0
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/docs/api/30-api-server.mdx +5 -5
- package/docs/api/34-api-config.mdx +2 -2
- package/docs/api/36-cli.mdx +1 -1
- package/docs/learn/12-error-handling.mdx +7 -8
- package/package.json +1 -2
- package/src/cli.ts +62 -8
- package/src/client/browser-entry/action-dispatch.ts +12 -0
- package/src/client/browser-entry/action-queue.ts +70 -8
- package/src/client/browser-entry/rsc-stream.ts +78 -22
- package/src/client/error-boundary.tsx +13 -39
- package/src/client/error-reconstituter.tsx +5 -5
- package/src/dev-tools/debug-channel.ts +151 -0
- package/src/index.ts +8 -12
- package/src/plugins/dev-server.ts +58 -7
- package/src/plugins/mdx.ts +2 -1
- package/src/routing/convention-lint.ts +4 -111
- package/src/routing/scanner.ts +33 -22
- package/src/server/access-gate.tsx +3 -3
- package/src/server/deny-boundary.ts +5 -23
- package/src/server/deny-renderer.ts +4 -7
- package/src/server/error-boundary-wrapper.ts +11 -35
- package/src/server/pipeline.ts +9 -0
- package/src/server/primitives.ts +20 -26
- package/src/server/rsc-entry/error-renderer.ts +15 -43
- package/src/server/rsc-entry/helpers.ts +10 -67
- package/src/server/rsc-entry/index.ts +1 -0
- package/src/server/rsc-entry/render-route.ts +12 -1
- package/src/server/rsc-entry/rsc-stream.ts +27 -24
- package/src/server/rsc-entry/ssr-renderer.ts +7 -1
- package/dist/_chunks/build-manifest-DTmSGLRz.js.map +0 -1
- package/dist/_chunks/convention-lint-fRkwVwEH.js.map +0 -1
- package/dist/_chunks/logger-uLBuGKDI.js.map +0 -1
- package/dist/_chunks/scanner-AiazgH_f.js.map +0 -1
- package/dist/_chunks/segment-keys-lqtdookO.js.map +0 -1
- package/dist/server/utils/mdx-file.d.ts +0 -17
- package/dist/server/utils/mdx-file.d.ts.map +0 -1
- package/src/server/utils/mdx-file.ts +0 -22
|
@@ -173,6 +173,14 @@ export interface PipelineConfig {
|
|
|
173
173
|
* Undefined in production — zero overhead.
|
|
174
174
|
*/
|
|
175
175
|
devHmrOptions?: import('../dev-tools/dev-page-shell.ts').DevErrorHmrOptions;
|
|
176
|
+
/**
|
|
177
|
+
* Dev debug channel transport — sends RSC Flight debug data to the
|
|
178
|
+
* browser via HMR WebSocket for owner stack resolution in console
|
|
179
|
+
* warnings. Set by the dev server. Undefined in production.
|
|
180
|
+
*
|
|
181
|
+
* See TIM-1507, design/13-security.md §7.
|
|
182
|
+
*/
|
|
183
|
+
devDebugRegistry?: import('../dev-tools/debug-channel.ts').DebugChannelRegistry;
|
|
176
184
|
/**
|
|
177
185
|
* Fallback error renderer — called when a catastrophic error escapes the
|
|
178
186
|
* render phase. Produces an HTML Response instead of a bare empty 500.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -62,14 +62,17 @@ export declare class DenySignal extends Error {
|
|
|
62
62
|
*/
|
|
63
63
|
get sourceFile(): string | undefined;
|
|
64
64
|
}
|
|
65
|
-
/** Options for deny()
|
|
65
|
+
/** Options for deny(). */
|
|
66
66
|
export interface DenyOptions {
|
|
67
|
-
/** HTTP status code (4xx or 5xx). Default: 403. */
|
|
68
|
-
status?: number;
|
|
69
67
|
/** Human-readable message (logged server-side, not sent to client). */
|
|
70
68
|
message?: string;
|
|
71
|
-
/**
|
|
72
|
-
|
|
69
|
+
/**
|
|
70
|
+
* JSON-serializable data forwarded as the `data` prop to status-code files
|
|
71
|
+
* and `denied.tsx`. Named `dangerouslyPassData` because this data crosses
|
|
72
|
+
* the RSC → client serialization boundary — do not pass sensitive server
|
|
73
|
+
* state (tokens, internal IDs, database rows).
|
|
74
|
+
*/
|
|
75
|
+
dangerouslyPassData?: JsonSerializable;
|
|
73
76
|
}
|
|
74
77
|
/**
|
|
75
78
|
* Universal denial/error primitive. Throws a `DenySignal` that the framework catches.
|
|
@@ -79,22 +82,21 @@ export interface DenyOptions {
|
|
|
79
82
|
* - Inside Suspense (hold window): promoted to pre-flush behavior
|
|
80
83
|
* - Inside Suspense (after flush): error boundary + noindex meta
|
|
81
84
|
*
|
|
82
|
-
* Supports both positional and object signatures:
|
|
83
85
|
* ```ts
|
|
84
|
-
* deny()
|
|
85
|
-
* deny(404)
|
|
86
|
-
* deny(503, {
|
|
87
|
-
* deny({
|
|
86
|
+
* deny() // 403 (default)
|
|
87
|
+
* deny(404) // 404
|
|
88
|
+
* deny(503, { message: 'Maintenance' }) // server-only log message
|
|
89
|
+
* deny(404, { dangerouslyPassData: { resourceId: params.id } }) // explicit client opt-in
|
|
88
90
|
* ```
|
|
89
91
|
*
|
|
90
92
|
* Accepts any 4xx or 5xx status code. This replaces the need for
|
|
91
93
|
* `throw new RenderError(...)` in user code — RenderError is now an
|
|
92
94
|
* internal pipeline detail.
|
|
93
95
|
*
|
|
94
|
-
* @param
|
|
95
|
-
* @param
|
|
96
|
+
* @param status - HTTP status code (4xx or 5xx). Default: 403.
|
|
97
|
+
* @param options - Optional message and/or data to pass to the client.
|
|
96
98
|
*/
|
|
97
|
-
export declare function deny(
|
|
99
|
+
export declare function deny(status?: number, options?: DenyOptions): never;
|
|
98
100
|
export { RedirectType } from '../shared/redirect-type.ts';
|
|
99
101
|
/**
|
|
100
102
|
* Render-phase signal thrown by `redirect()` and `redirectExternal()`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAYnD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAS,GAAG,MAAM,GAAG,IAAI,CA8DhF;AAuCD,QAAA,MAAM,UAAU,EAAE,OAAO,MAAyC,CAAC;AACnE,QAAA,MAAM,cAAc,EAAE,OAAO,MAA6C,CAAC;AAC3E,QAAA,MAAM,kBAAkB,EAAE,OAAO,MAAiD,CAAC;AACnF,QAAA,MAAM,sBAAsB,EAAE,OAAO,MAAqD,CAAC;AAM3F,mFAAmF;AACnF,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED,uFAAuF;AACvF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAExE;AAED,oFAAoF;AACpF,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,CAElE;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,cAAc,CAExE;AAID;;;;;GAKG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,CAAC,UAAU,CAAC,QAAQ;IAC7B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAAC;IAE5C;;;;;;;;;;;;OAYG;IACH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAElB;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IAExB,YAAY,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB,EAKlD;IAED;;;;OAIG;IACH,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAqBnC;CACF;AAED,
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* RSC Error & No-Match Renderers — handles error pages and 404s.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
* - MDX (server component): Receives plain props ({ status }), no wrapper needed.
|
|
8
|
-
*
|
|
9
|
-
* This unified approach replaces the former SSR-only bypass for TSX error
|
|
10
|
-
* pages. See design/spike-TIM-565-unify-error-pages.md for the full analysis.
|
|
4
|
+
* Error pages are 'use client' components rendered through the RSC → SSR
|
|
5
|
+
* pipeline: the Error is converted to SerializableError, wrapped with
|
|
6
|
+
* ErrorReconstituter to reconstitute a real Error on the client.
|
|
11
7
|
*
|
|
12
8
|
* Design docs: 10-error-handling.md §"Three-Tier Error Page Rendering"
|
|
13
9
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/error-renderer.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"error-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/error-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAIjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAIlE,OAAO,KAAK,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAgB5E;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AA6GD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,eAAe,CACnC,KAAK,EAAE,OAAO,EACd,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,WAAW,EAAE,EAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,EAAE,qBAAqB,EACtC,WAAW,CAAC,EAAE,eAAe,EAC7B,gBAAgB,SAAW,GAC1B,OAAO,CAAC,QAAQ,CAAC,CA4DnB;AA4HD;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,OAAO,EACxB,eAAe,EAAE,qBAAqB,EACtC,WAAW,CAAC,EAAE,mBAAmB,GAChC,OAAO,CAAC,QAAQ,CAAC,CA2CnB"}
|
|
@@ -9,16 +9,15 @@ import type { SlotSkipEntry } from '../slot-resolver.ts';
|
|
|
9
9
|
/**
|
|
10
10
|
* Create a debug channel sink that discards all debug data.
|
|
11
11
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
* stream that we drain and discard.
|
|
12
|
+
* Used in production to divert debug rows ($E source entries, component
|
|
13
|
+
* info) away from the main Flight stream. In dev mode, the debug channel
|
|
14
|
+
* is omitted entirely so debug rows (owner stacks) ride the main stream
|
|
15
|
+
* and reach the browser for console warning resolution.
|
|
17
16
|
*
|
|
18
|
-
*
|
|
17
|
+
* Only provides `writable` — omitting `readable` avoids Flight's
|
|
18
|
+
* keepDebugAlive mode which holds deferred debug refs open per request.
|
|
19
19
|
*/
|
|
20
20
|
export declare function createDebugChannelSink(): {
|
|
21
|
-
readable: ReadableStream;
|
|
22
21
|
writable: WritableStream;
|
|
23
22
|
};
|
|
24
23
|
/**
|
|
@@ -34,26 +33,6 @@ export interface DebugComponentEntry {
|
|
|
34
33
|
key: string | null;
|
|
35
34
|
stack: unknown[] | null;
|
|
36
35
|
}
|
|
37
|
-
/**
|
|
38
|
-
* A debug channel that collects Flight debug rows instead of discarding them.
|
|
39
|
-
*
|
|
40
|
-
* Used in dev mode to capture server component tree information for the
|
|
41
|
-
* Vite error overlay. The collector provides the same `{ readable, writable }`
|
|
42
|
-
* shape as the discard sink, plus methods to retrieve collected data.
|
|
43
|
-
*
|
|
44
|
-
* Security: only component names, environments, and stack frames are
|
|
45
|
-
* extracted — props and source code are stripped. In production builds,
|
|
46
|
-
* use `createDebugChannelSink()` instead (this function is never called).
|
|
47
|
-
*/
|
|
48
|
-
export interface DebugChannelCollector {
|
|
49
|
-
readable: ReadableStream;
|
|
50
|
-
writable: WritableStream;
|
|
51
|
-
/** Get the raw collected text from the debug channel. */
|
|
52
|
-
getCollectedText(): string;
|
|
53
|
-
/** Get parsed component entries (names, stacks — no props or source). */
|
|
54
|
-
getComponents(): DebugComponentEntry[];
|
|
55
|
-
}
|
|
56
|
-
export declare function createDebugChannelCollector(): DebugChannelCollector;
|
|
57
36
|
/**
|
|
58
37
|
* Parse React Flight debug rows into component entries.
|
|
59
38
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,QAAQ,EAAE,cAAc,
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAG/D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAIzD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,QAAQ,EAAE,cAAc,CAAA;CAAE,CAOrE;AAID;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA8ClE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,KAAK,CAAC;IACtB,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC,EACF,YAAY,CAAC,EAAE,aAAa,EAAE,EAC9B,kBAAkB,CAAC,EAAE,MAAM,EAAE,EAC7B,gBAAgB,SAAW,GAC1B,WAAW,EAAE,CAsEf;AAMD,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAuB,cAAc,EAAc,MAAM,gBAAgB,CAAC;AAsCtF;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAE5E;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AA+CA,OAAO,KAAK,EAAuB,cAAc,EAAc,MAAM,gBAAgB,CAAC;AAsCtF;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAE5E;AA0VD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAK1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AAItE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,OAAO,wBAAwB,EAAE,cAAc,GACvD,OAAO,CAAC,OAAO,wBAAwB,EAAE,cAAc,CAAC,CAE1D;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CACzC,OAAO,EAAE,OAAO,wBAAwB,EAAE,uBAAuB,GAChE,OAAO,CAAC,OAAO,wBAAwB,EAAE,uBAAuB,CAAC,CAQnE;AAgDD;;;GAGG;AACH,eAAO,MAAM,cAAc,gBAAmB,CAAC;8BAb1B,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC"}
|
|
@@ -36,6 +36,7 @@ export interface RenderRouteDeps {
|
|
|
36
36
|
load: () => Promise<unknown>;
|
|
37
37
|
filePath: string;
|
|
38
38
|
};
|
|
39
|
+
devDebugRegistry?: import('../../dev-tools/debug-channel.ts').DebugChannelRegistry;
|
|
39
40
|
}
|
|
40
41
|
/**
|
|
41
42
|
* Render a matched route to an HTML Response via RSC → SSR pipeline,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-route.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/render-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAW1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAe/D;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,mBAAmB,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"render-route.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/render-route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAW1D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAClE,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAGtE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAe/D;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,WAAW,EAAE,mBAAmB,CAAC;IACjC,aAAa,EAAE,aAAa,CAAC;IAC7B,WAAW,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC;IACjE,gBAAgB,CAAC,EAAE,OAAO,kCAAkC,EAAE,oBAAoB,CAAC;CACpF;AAED;;;;;;;;;GASG;AACH,wBAAsB,WAAW,CAC/B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,IAAI,EAAE,eAAe,EACrB,YAAY,CAAC,EAAE,mBAAmB,GACjC,OAAO,CAAC,QAAQ,CAAC,CAyOnB"}
|
|
@@ -13,6 +13,7 @@ import type { RscPayloadRoot } from '../../shared/payload-root.ts';
|
|
|
13
13
|
import { type DenyPageEntry } from '../deny-boundary.ts';
|
|
14
14
|
import { DenySignal, RedirectSignal } from '../primitives.ts';
|
|
15
15
|
import { type DebugComponentEntry } from './helpers.ts';
|
|
16
|
+
import { type DebugChannelRegistry } from '../../dev-tools/debug-channel.ts';
|
|
16
17
|
/**
|
|
17
18
|
* Mutable signal state captured during RSC rendering.
|
|
18
19
|
*
|
|
@@ -63,6 +64,8 @@ export interface RscStreamResult {
|
|
|
63
64
|
signals: RenderSignals;
|
|
64
65
|
/** Dev-only: server component debug info from the Flight debug channel. */
|
|
65
66
|
getDebugComponents?: () => DebugComponentEntry[];
|
|
67
|
+
/** Dev-only: request ID for the debug channel HMR transport. */
|
|
68
|
+
debugRequestId?: string;
|
|
66
69
|
}
|
|
67
70
|
/**
|
|
68
71
|
* Render a payload root (tree plus its params) to an RSC Flight stream.
|
|
@@ -75,5 +78,5 @@ export interface RscStreamResult {
|
|
|
75
78
|
* fires onError during stream consumption. Signals are captured in the
|
|
76
79
|
* returned `signals` object for the caller to handle.
|
|
77
80
|
*/
|
|
78
|
-
export declare function renderRscStream(payload: RscPayloadRoot, req: Request, leafDenyChain?: DenyPageEntry[]): RscStreamResult;
|
|
81
|
+
export declare function renderRscStream(payload: RscPayloadRoot, req: Request, leafDenyChain?: DenyPageEntry[], devDebugRegistry?: DebugChannelRegistry): RscStreamResult;
|
|
79
82
|
//# sourceMappingURL=rsc-stream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAInE,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAIL,UAAU,EACV,cAAc,EAEf,MAAM,kBAAkB,CAAC;AAG1B,OAAO,
|
|
1
|
+
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAInE,OAAO,EAAoB,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE3E,OAAO,EAIL,UAAU,EACV,cAAc,EAEf,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAwC,KAAK,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAC9F,OAAO,EAAyB,KAAK,oBAAoB,EAAE,MAAM,kCAAkC,CAAC;AAIpG;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B;;;;;;;;;;OAUG;IACH,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,WAAW,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvD;;;;;;;;OAQG;IACH,kBAAkB,EAAE,OAAO,GAAG,IAAI,CAAC;IACnC,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB;gEAC4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IAClD,OAAO,EAAE,aAAa,CAAC;IACvB,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,mBAAmB,EAAE,CAAC;IACjD,gEAAgE;IAChE,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,cAAc,EACvB,GAAG,EAAE,OAAO,EACZ,aAAa,CAAC,EAAE,aAAa,EAAE,EAC/B,gBAAgB,CAAC,EAAE,oBAAoB,GACtC,eAAe,CA6LjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/ssr-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAOlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAYzD,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA4BrD;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAiB,CAAC;AAEhF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAqB,CAAC;AAEtF,UAAU,gBAAgB;IACxB,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"ssr-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/ssr-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAOlE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACxE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAYzD,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AA4BrD;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAiB,CAAC;AAEhF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,iCAAiC,EAAE;IAAE,KAAK,EAAE,OAAO,CAAA;CAAqB,CAAC;AAEtF,UAAU,gBAAgB;IACxB,GAAG,EAAE,OAAO,CAAC;IACb,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACtC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,KAAK,EAAE,UAAU,CAAC;IAClB,eAAe,EAAE,OAAO,CAAC;IACzB,eAAe,EAAE,qBAAqB,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,EAAE,MAAM,CAAC;IACzB,wDAAwD;IACxD,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,YAAY,CAAC,EAAE,aAAa,EAAE,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAyWjF"}
|
|
@@ -10,17 +10,17 @@ Server-side utilities and types. Import from `@timber-js/app/server`.
|
|
|
10
10
|
|
|
11
11
|
## Navigation & Status
|
|
12
12
|
|
|
13
|
-
### `deny(
|
|
13
|
+
### `deny(status?, options?)`
|
|
14
14
|
|
|
15
15
|
Universal denial/error primitive. Produces an HTTP error status and renders the matching status file. Accepts any 4xx or 5xx status code. Default status is 403.
|
|
16
16
|
|
|
17
17
|
```ts
|
|
18
18
|
import { deny } from '@timber-js/app/server';
|
|
19
19
|
|
|
20
|
-
deny();
|
|
21
|
-
deny(404);
|
|
22
|
-
deny(503, {
|
|
23
|
-
deny({
|
|
20
|
+
deny(); // 403 (default)
|
|
21
|
+
deny(404); // 404 Not Found
|
|
22
|
+
deny(503, { message: 'Maintenance' }); // server-only log message
|
|
23
|
+
deny(404, { dangerouslyPassData: { resourceId: params.id } }); // data forwarded as `data` prop
|
|
24
24
|
```
|
|
25
25
|
|
|
26
26
|
### `redirect(url, type?)`
|
|
@@ -158,9 +158,9 @@ Strip sensitive fields (passwords, tokens, CVV, SSN, etc.) from the `submittedVa
|
|
|
158
158
|
- **Type:** `string[]`
|
|
159
159
|
- **Default:** `['tsx', 'ts', 'jsx', 'js']`
|
|
160
160
|
|
|
161
|
-
File extensions recognized for
|
|
161
|
+
File extensions recognized for content conventions (`page.*`, `layout.*`, `default.*`, `denied.*`). Add `'mdx'` for MDX pages.
|
|
162
162
|
|
|
163
|
-
Code-only conventions (`middleware.*`, `access.*`, `route.*`, `params.*`) always use `.ts`/`.tsx`/`.js`/`.jsx
|
|
163
|
+
Status/error conventions (`error.*`, `global-error.*`, status files like `404.*`) always use `.tsx`/`.jsx`/`.ts`/`.js` (or `.json` for status files) — they do not follow `pageExtensions`. Code-only conventions (`middleware.*`, `access.*`, `route.*`, `params.*`) also always use `.ts`/`.tsx`/`.js`/`.jsx`. `.mts`/`.cts`/`.mjs`/`.cjs` are not recognized for any convention.
|
|
164
164
|
|
|
165
165
|
Two files claiming the same convention in one directory (e.g. `page.tsx` + `page.jsx`) are a build error — filesystem order is platform-dependent, so timber refuses to pick one silently.
|
|
166
166
|
|
package/docs/api/36-cli.mdx
CHANGED
|
@@ -44,7 +44,7 @@ To override the default, use any of the following (highest precedence first):
|
|
|
44
44
|
|
|
45
45
|
For `timber dev`, an occupied port produces a notice and the server tries the next free port. Set `server.strictPort: true` in `vite.config.ts` to fail on a conflict instead. Preview and the production Node preview server report a conflict for an explicit port.
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
Editing `timber.config.ts` triggers a full process restart so the updated config takes effect. The dev server briefly shuts down and restarts on the same port. Changing the configured port takes effect on restart.
|
|
48
48
|
|
|
49
49
|
### `timber build`
|
|
50
50
|
|
|
@@ -87,9 +87,9 @@ export default function NotFound({ status }: { status: number }) {
|
|
|
87
87
|
}
|
|
88
88
|
```
|
|
89
89
|
|
|
90
|
-
timber hands these components to its error boundary — a client component — as a prop, so a server component there cannot cross the RSC boundary. It is not a degraded error page: every page under that segment fails to render. The build catches it and names the file, so you will not discover it as a serialization error on a page you did not touch.
|
|
90
|
+
timber hands these components to its error boundary — a client component — as a prop, so a server component there cannot cross the RSC boundary. It is not a degraded error page: every page under that segment fails to render. The build catches it and names the file, so you will not discover it as a serialization error on a page you did not touch.
|
|
91
91
|
|
|
92
|
-
**MDX
|
|
92
|
+
> **Note:** MDX pages and layouts remain fully supported, but status-code files (`404.tsx`, `4xx.tsx`, etc.), `error.tsx`, and `global-error.tsx` must be script files (`.tsx`/`.jsx`/`.ts`/`.js`). MDX status and error files are not recognized.
|
|
93
93
|
|
|
94
94
|
**JSON status files** (`401.json`, `4xx.json`) return the file contents verbatim — no React rendering, no layout wrapping. `dangerouslyPassData` from `deny()` is silently dropped. They are useful for API routes that need a structured JSON error body:
|
|
95
95
|
|
|
@@ -132,7 +132,7 @@ A status page renders inside the layouts **above and including the segment it li
|
|
|
132
132
|
|
|
133
133
|
One exception: **the segment that denied never contributes its own layout**, even when it owns the matched status file. If its `access.ts` denied, that layout sits behind the failed auth check, so running it would let it fetch and serialize data the request was not allowed to see. If the layout itself called `deny()`, it threw instead of returning its chrome, so there is nothing to render. A `deny()` from a page is unaffected — the page's own layout still renders.
|
|
134
134
|
|
|
135
|
-
When a `deny()` has no matching status-code file, it falls through to the nearest `error.tsx`. The component still receives a real `error` (its message is `Access denied with status <N>`), and additionally receives `status` and `
|
|
135
|
+
When a `deny()` has no matching status-code file, it falls through to the nearest `error.tsx`. The component still receives a real `error` (its message is `Access denied with status <N>`), and additionally receives `status` and `data` so you can render denial-specific UI:
|
|
136
136
|
|
|
137
137
|
```tsx title="app/error.tsx"
|
|
138
138
|
'use client';
|
|
@@ -172,17 +172,16 @@ A page refresh during streaming never shows a flash of an error boundary. This i
|
|
|
172
172
|
|
|
173
173
|
## Structured Error Data
|
|
174
174
|
|
|
175
|
-
`deny()` accepts optional JSON-serializable data that is passed to the error page
|
|
175
|
+
`deny()` accepts optional JSON-serializable data that is passed to the error page as the `data` prop. The opt-in is explicit at the call site — `dangerouslyPassData` signals that this data crosses the RSC → client serialization boundary:
|
|
176
176
|
|
|
177
177
|
```tsx
|
|
178
178
|
import { deny } from '@timber-js/app/server';
|
|
179
179
|
|
|
180
180
|
if (!product) {
|
|
181
|
-
deny({
|
|
182
|
-
|
|
183
|
-
data: { title: 'Product not found', resourceId: params.id },
|
|
181
|
+
deny(404, {
|
|
182
|
+
dangerouslyPassData: { title: 'Product not found', resourceId: params.id },
|
|
184
183
|
});
|
|
185
184
|
}
|
|
186
185
|
```
|
|
187
186
|
|
|
188
|
-
The
|
|
187
|
+
The status-code file receives the structured data as the `data` prop, surviving the RSC → client boundary where plain error properties are stripped.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.201",
|
|
4
4
|
"description": "Vite-native React framework built for Servers and Serverless Platforms — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -167,7 +167,6 @@
|
|
|
167
167
|
"nuqs": "^2.0.0",
|
|
168
168
|
"react": "19.3.0",
|
|
169
169
|
"react-dom": "19.3.0",
|
|
170
|
-
"react-server-dom-webpack": "19.3.0",
|
|
171
170
|
"satteri": "^0.9.5",
|
|
172
171
|
"vite": "8.3.0",
|
|
173
172
|
"vite-plugin-satteri": "^0.2.15",
|
package/src/cli.ts
CHANGED
|
@@ -143,21 +143,75 @@ export interface ViteDeps {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
/**
|
|
146
|
-
* Start the Vite dev server
|
|
146
|
+
* Start the Vite dev server with a supervisor that respawns the process
|
|
147
|
+
* when timber.config.ts changes. Node's require cache for ESM modules
|
|
148
|
+
* loaded via require() cannot be evicted, so an in-process restart
|
|
149
|
+
* serves stale config. The supervisor forks a worker; when the worker
|
|
150
|
+
* exits with RESTART_EXIT_CODE (set by timber-dev-server on config file
|
|
151
|
+
* change), the supervisor spawns a fresh worker with a clean cache.
|
|
147
152
|
*
|
|
148
153
|
* The timber plugin binds the port immediately with a holding page
|
|
149
154
|
* (in rootSync's config hook) so browsers see a "starting..." page
|
|
150
155
|
* instead of ERR_CONNECTION_REFUSED during initialization.
|
|
151
156
|
*
|
|
152
|
-
* See design/21-dev-server.md, TIM-665.
|
|
157
|
+
* See design/21-dev-server.md, TIM-665, TIM-1444.
|
|
153
158
|
*/
|
|
154
159
|
export async function runDev(options: CommandOptions, _deps?: ViteDeps): Promise<void> {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
// Worker mode: run the dev server directly (forked by supervisor below)
|
|
161
|
+
if (process.env.__TIMBER_DEV_WORKER) {
|
|
162
|
+
const createServer = _deps?.createServer ?? (await import('vite')).createServer;
|
|
163
|
+
const server = await createServer({
|
|
164
|
+
configFile: options.config,
|
|
165
|
+
});
|
|
166
|
+
await server.listen();
|
|
167
|
+
server.printUrls();
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Supervisor mode: fork a worker and respawn on config changes.
|
|
172
|
+
const { fork } = await import('node:child_process');
|
|
173
|
+
const { RESTART_EXIT_CODE } = await import('./plugins/dev-server.ts');
|
|
174
|
+
|
|
175
|
+
// eslint-disable-next-line no-constant-condition
|
|
176
|
+
while (true) {
|
|
177
|
+
const result = await new Promise<{ code: number | null; signal: NodeJS.Signals | null }>(
|
|
178
|
+
(resolve) => {
|
|
179
|
+
const child = fork(process.argv[1], process.argv.slice(2), {
|
|
180
|
+
stdio: 'inherit',
|
|
181
|
+
env: { ...process.env, __TIMBER_DEV_WORKER: '1' },
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
// Forward signals to the child. SIGINT from Ctrl+C is sent to
|
|
185
|
+
// the entire process group, but a targeted SIGTERM (from a
|
|
186
|
+
// process manager or test teardown) only reaches the parent.
|
|
187
|
+
const onSigint = () => child.kill('SIGINT');
|
|
188
|
+
const onSigterm = () => child.kill('SIGTERM');
|
|
189
|
+
process.on('SIGINT', onSigint);
|
|
190
|
+
process.on('SIGTERM', onSigterm);
|
|
191
|
+
|
|
192
|
+
child.on('exit', (code, signal) => {
|
|
193
|
+
process.off('SIGINT', onSigint);
|
|
194
|
+
process.off('SIGTERM', onSigterm);
|
|
195
|
+
resolve({ code, signal });
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
);
|
|
199
|
+
|
|
200
|
+
if (result.code === RESTART_EXIT_CODE) {
|
|
201
|
+
continue;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
// Child was killed by a signal (e.g. SIGTERM) — re-raise on ourselves
|
|
205
|
+
if (result.signal) {
|
|
206
|
+
process.kill(process.pid, result.signal);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
if (result.code != null && result.code !== 0) {
|
|
210
|
+
process.exit(result.code);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
161
215
|
}
|
|
162
216
|
|
|
163
217
|
/**
|
|
@@ -45,6 +45,18 @@ export function setupServerActions(): void {
|
|
|
45
45
|
if (!router) return;
|
|
46
46
|
router.runWhenIdle(() => void router.refresh());
|
|
47
47
|
},
|
|
48
|
+
// Every hold below is `applyActionResult` — the router's own refresh
|
|
49
|
+
// or piggybacked commit. If it has not settled in `holdTimeoutMs`, the
|
|
50
|
+
// router is stuck non-idle on that very work (a user navigation would
|
|
51
|
+
// have superseded it and settled the hold), so `runWhenIdle` would
|
|
52
|
+
// park forever. A fresh `refresh()` supersedes the stuck owner —
|
|
53
|
+
// aborting its fetch, settling its uncommitted tree — and re-fetches
|
|
54
|
+
// the current URL (TIM-1485).
|
|
55
|
+
recoverStalledHold(): void {
|
|
56
|
+
const router = getRouterOrNull();
|
|
57
|
+
if (!router) return;
|
|
58
|
+
void router.refresh();
|
|
59
|
+
},
|
|
48
60
|
});
|
|
49
61
|
|
|
50
62
|
setServerCallback((id: string, args: unknown[]) => {
|
|
@@ -13,10 +13,54 @@
|
|
|
13
13
|
|
|
14
14
|
export interface ActionQueueDeps {
|
|
15
15
|
refreshWhenIdle: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Called once when an action's holds exceed `holdTimeoutMs`. The chain
|
|
18
|
+
* releases regardless; this is the recovery hook. It must not wait on
|
|
19
|
+
* the same thing the hold is stuck on — in dispatch the hold IS the
|
|
20
|
+
* router's own refresh/commit, so a deferred `refreshWhenIdle` would
|
|
21
|
+
* park forever. Dispatch forces a fresh `router.refresh()` instead,
|
|
22
|
+
* which supersedes the stuck owner (TIM-1485).
|
|
23
|
+
*/
|
|
24
|
+
recoverStalledHold: () => void;
|
|
25
|
+
/**
|
|
26
|
+
* Maximum time (ms) the queue stays blocked on held promises after an
|
|
27
|
+
* action's result has been returned. A hung hold (e.g. a refresh commit
|
|
28
|
+
* awaiting a stalled flight stream) would otherwise brick the chain for
|
|
29
|
+
* the life of the page. `0` disables the guard. Default: 30s.
|
|
30
|
+
*/
|
|
31
|
+
holdTimeoutMs?: number;
|
|
16
32
|
}
|
|
17
33
|
|
|
34
|
+
const DEFAULT_HOLD_TIMEOUT_MS = 30_000;
|
|
35
|
+
|
|
18
36
|
const noop = (): void => {};
|
|
19
37
|
|
|
38
|
+
/**
|
|
39
|
+
* Resolve when every hold settles, or when `timeoutMs` elapses — whichever
|
|
40
|
+
* comes first. Never rejects. `onTimeout` runs only if the timer wins.
|
|
41
|
+
* Same race-against-timer shape as `cache/singleflight.ts` (TIM-518),
|
|
42
|
+
* minus the AbortSignal: holds are fire-and-forget side effects with no
|
|
43
|
+
* cancellation contract.
|
|
44
|
+
*/
|
|
45
|
+
function awaitHolds(
|
|
46
|
+
holds: Promise<unknown>[],
|
|
47
|
+
timeoutMs: number,
|
|
48
|
+
onTimeout: () => void
|
|
49
|
+
): Promise<void> {
|
|
50
|
+
const all = Promise.all(holds).then(noop);
|
|
51
|
+
if (holds.length === 0 || timeoutMs <= 0) return all;
|
|
52
|
+
return new Promise<void>((resolve) => {
|
|
53
|
+
const timer = setTimeout(() => {
|
|
54
|
+
onTimeout();
|
|
55
|
+
resolve();
|
|
56
|
+
}, timeoutMs);
|
|
57
|
+
void all.then(() => {
|
|
58
|
+
clearTimeout(timer);
|
|
59
|
+
resolve();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
20
64
|
/**
|
|
21
65
|
* Passed into `work` so it can return a result to React immediately
|
|
22
66
|
* while keeping the queue blocked on a side effect (e.g. a refresh
|
|
@@ -41,7 +85,10 @@ export interface ActionQueue {
|
|
|
41
85
|
run: <T>(work: (q: ActionQueueRun) => Promise<T>) => Promise<T>;
|
|
42
86
|
/**
|
|
43
87
|
* Mark that a discarded action would have revalidated. When the queue
|
|
44
|
-
* drains, one refresh fires via `deps.refreshWhenIdle`.
|
|
88
|
+
* drains, one refresh fires via `deps.refreshWhenIdle`. If the queue is
|
|
89
|
+
* already idle — a hold settling after its timeout released the chain —
|
|
90
|
+
* the refresh fires immediately rather than waiting for a future
|
|
91
|
+
* action's drain (TIM-1485).
|
|
45
92
|
*/
|
|
46
93
|
markNeedsRefresh: () => void;
|
|
47
94
|
}
|
|
@@ -49,6 +96,8 @@ export interface ActionQueue {
|
|
|
49
96
|
export function createActionQueue(deps: ActionQueueDeps): ActionQueue {
|
|
50
97
|
let tail: Promise<void> = Promise.resolve();
|
|
51
98
|
let needsRefresh = false;
|
|
99
|
+
let idle = true;
|
|
100
|
+
const holdTimeoutMs = deps.holdTimeoutMs ?? DEFAULT_HOLD_TIMEOUT_MS;
|
|
52
101
|
|
|
53
102
|
function drain(): void {
|
|
54
103
|
if (!needsRefresh) return;
|
|
@@ -56,6 +105,16 @@ export function createActionQueue(deps: ActionQueueDeps): ActionQueue {
|
|
|
56
105
|
deps.refreshWhenIdle();
|
|
57
106
|
}
|
|
58
107
|
|
|
108
|
+
// The caller's promise is untouched: React already has the action
|
|
109
|
+
// result. Recovery is delegated — the queue cannot know what the hold
|
|
110
|
+
// is stuck on, and a deferred drain refresh would wait on exactly that.
|
|
111
|
+
function onHoldTimeout(): void {
|
|
112
|
+
if (process.env.NODE_ENV === 'development') {
|
|
113
|
+
console.warn(`[timber] action queue: hold exceeded ${holdTimeoutMs}ms — releasing chain`);
|
|
114
|
+
}
|
|
115
|
+
deps.recoverStalledHold();
|
|
116
|
+
}
|
|
117
|
+
|
|
59
118
|
function run<T>(work: (q: ActionQueueRun) => Promise<T>): Promise<T> {
|
|
60
119
|
const holds: Promise<unknown>[] = [];
|
|
61
120
|
const hold = (p: Promise<unknown>): void => {
|
|
@@ -63,27 +122,30 @@ export function createActionQueue(deps: ActionQueueDeps): ActionQueue {
|
|
|
63
122
|
};
|
|
64
123
|
// `p` is the caller-visible promise — it resolves/rejects with work's
|
|
65
124
|
// result (React sees this). `settled` is the chain link: work settled
|
|
66
|
-
// AND every held promise settled
|
|
67
|
-
// breaks and the next action always runs.
|
|
125
|
+
// AND every held promise settled (or the hold timeout fired). It never
|
|
126
|
+
// rejects, so the chain never breaks and the next action always runs.
|
|
68
127
|
const p = tail.then(
|
|
69
128
|
() => work({ hold }),
|
|
70
129
|
() => work({ hold })
|
|
71
130
|
);
|
|
72
|
-
const settled = p
|
|
73
|
-
.then(noop, noop)
|
|
74
|
-
.then(() => Promise.all(holds))
|
|
75
|
-
.then(noop);
|
|
131
|
+
const settled = p.then(noop, noop).then(() => awaitHolds(holds, holdTimeoutMs, onHoldTimeout));
|
|
76
132
|
tail = settled;
|
|
133
|
+
idle = false;
|
|
77
134
|
// Drain when the queue empties: tail identity means nobody enqueued
|
|
78
135
|
// behind this action between its start and its settlement.
|
|
79
136
|
void settled.then(() => {
|
|
80
|
-
if (tail
|
|
137
|
+
if (tail !== settled) return;
|
|
138
|
+
idle = true;
|
|
139
|
+
drain();
|
|
81
140
|
});
|
|
82
141
|
return p;
|
|
83
142
|
}
|
|
84
143
|
|
|
85
144
|
function markNeedsRefresh(): void {
|
|
86
145
|
needsRefresh = true;
|
|
146
|
+
// Nothing is queued to drain this — act now rather than strand the
|
|
147
|
+
// flag until an unrelated future action fires it.
|
|
148
|
+
if (idle) drain();
|
|
87
149
|
}
|
|
88
150
|
|
|
89
151
|
return { run, markNeedsRefresh };
|