@timber-js/app 0.2.0-alpha.117 → 0.2.0-alpha.118
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/dist/fonts/virtual-modules.d.ts +0 -9
- package/dist/fonts/virtual-modules.d.ts.map +1 -1
- package/dist/index.js +9 -2
- package/dist/index.js.map +1 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/server/html-injector-core.d.ts +2 -1
- package/dist/server/html-injector-core.d.ts.map +1 -1
- package/dist/server/html-injectors.d.ts +1 -1
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/node-stream-transforms.d.ts +2 -0
- package/dist/server/node-stream-transforms.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +3 -0
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +7 -0
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/fonts/virtual-modules.ts +8 -2
- package/src/plugins/fonts.ts +2 -0
- package/src/server/html-injector-core.ts +15 -1
- package/src/server/html-injectors.ts +6 -4
- package/src/server/node-stream-transforms.ts +3 -1
- package/src/server/rsc-entry/rsc-stream.ts +4 -0
- package/src/server/rsc-entry/ssr-renderer.ts +16 -0
- package/src/server/ssr-entry.ts +15 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/plugins/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA0B1D,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAElF;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"fonts.d.ts","sourceRoot":"","sources":["../../src/plugins/fonts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAClD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA0B1D,OAAO,EAAE,YAAY,EAAE,oBAAoB,EAAE,KAAK,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAC7F,OAAO,EACL,cAAc,EACd,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAElF;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CA8KtD"}
|
|
@@ -182,9 +182,10 @@ export declare class FlightInjectorCore {
|
|
|
182
182
|
readonly pending: Uint8Array[];
|
|
183
183
|
private readonly rscReader;
|
|
184
184
|
private readonly timeoutMs;
|
|
185
|
+
private readonly errorSignal?;
|
|
185
186
|
private readonly decoder;
|
|
186
187
|
private pullPromise;
|
|
187
|
-
constructor(rscStream: ReadableStream<Uint8Array>, renderTimeoutMs?: number);
|
|
188
|
+
constructor(rscStream: ReadableStream<Uint8Array>, renderTimeoutMs?: number, errorSignal?: AbortSignal);
|
|
188
189
|
/** Tell the machine the first HTML chunk has arrived. Idempotent-ish: caller checks. */
|
|
189
190
|
notifyFirstChunk(): void;
|
|
190
191
|
/** Tell the machine HTML output is finished — pull loop will stop yielding. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-injector-core.d.ts","sourceRoot":"","sources":["../../src/server/html-injector-core.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"html-injector-core.d.ts","sourceRoot":"","sources":["../../src/server/html-injector-core.ts"],"names":[],"mappings":"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"}
|
|
@@ -94,7 +94,7 @@ export declare function createInlinedRscStream(rscStream: ReadableStream<Uint8Ar
|
|
|
94
94
|
* completion is signaled by the `DOMContentLoaded` event on the client
|
|
95
95
|
* side — no custom done flag needed.
|
|
96
96
|
*/
|
|
97
|
-
export declare function injectRscPayload(htmlStream: ReadableStream<Uint8Array>, rscStream: ReadableStream<Uint8Array> | undefined, renderTimeoutMs?: number): ReadableStream<Uint8Array>;
|
|
97
|
+
export declare function injectRscPayload(htmlStream: ReadableStream<Uint8Array>, rscStream: ReadableStream<Uint8Array> | undefined, renderTimeoutMs?: number, errorSignal?: AbortSignal): ReadableStream<Uint8Array>;
|
|
98
98
|
/**
|
|
99
99
|
* Client bootstrap configuration returned by buildClientScripts.
|
|
100
100
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"html-injectors.d.ts","sourceRoot":"","sources":["../../src/server/html-injectors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAmBH,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,wBAA6B,GACrC,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,CA8BzC;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,CAiBhF;AAuCD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,QAAQ,EAAE,MAAM,GACf,cAAc,CAAC,UAAU,CAAC,CAE5B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,WAAW,EAAE,MAAM,GAClB,cAAc,CAAC,UAAU,CAAC,CAE5B;AAID;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,eAAe,CAAC,EAAE,MAAM,GACvB,cAAc,CAAC,UAAU,CAAC,CA6B5B;
|
|
1
|
+
{"version":3,"file":"html-injectors.d.ts","sourceRoot":"","sources":["../../src/server/html-injectors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAmBH,MAAM,WAAW,wBAAwB;IACvC;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,wBAA6B,GACrC,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,CA8BzC;AAID;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,IAAI,eAAe,CAAC,UAAU,EAAE,UAAU,CAAC,CAiBhF;AAuCD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,QAAQ,EAAE,MAAM,GACf,cAAc,CAAC,UAAU,CAAC,CAE5B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,WAAW,EAAE,MAAM,GAClB,cAAc,CAAC,UAAU,CAAC,CAE5B;AAID;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,eAAe,CAAC,EAAE,MAAM,GACvB,cAAc,CAAC,UAAU,CAAC,CA6B5B;AAwED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,EACtC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,EACjD,eAAe,CAAC,EAAE,MAAM,EACxB,WAAW,CAAC,EAAE,WAAW,GACxB,cAAc,CAAC,UAAU,CAAC,CAS5B;AAID;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,qBAAqB;IACpC,sBAAsB,EAAE,MAAM,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;CACtB;AAqBD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,kBAAkB,CAAC,aAAa,EAAE;IAChD,MAAM,EAAE,MAAM,CAAC;IACf,gBAAgB,EAAE;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAC;IACjE,GAAG,EAAE,OAAO,CAAC;IACb,aAAa,CAAC,EAAE,OAAO,qBAAqB,EAAE,aAAa,CAAC;CAC7D,GAAG,qBAAqB,CA8DxB"}
|
|
@@ -68,6 +68,8 @@ export interface NodeFlightInjectorOptions {
|
|
|
68
68
|
* Default: 30000 (30s).
|
|
69
69
|
*/
|
|
70
70
|
renderTimeoutMs?: number;
|
|
71
|
+
/** Signal that fires when an unhandled RSC error is detected. */
|
|
72
|
+
errorSignal?: AbortSignal;
|
|
71
73
|
}
|
|
72
74
|
/**
|
|
73
75
|
* Node.js `Transform` that merges RSC script tags into the HTML stream.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-stream-transforms.d.ts","sourceRoot":"","sources":["../../src/server/node-stream-transforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,OAAO,EAGL,YAAY,EAOb,MAAM,yBAAyB,CAAC;AAMjC,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,4BAAiC,GAAG,SAAS,CA2BjG;AAID;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,IAAI,SAAS,CAoBzD;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC;AAIxB;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CA2BlE;AAID;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"node-stream-transforms.d.ts","sourceRoot":"","sources":["../../src/server/node-stream-transforms.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGxC,OAAO,EAGL,YAAY,EAOb,MAAM,yBAAyB,CAAC;AAMjC,MAAM,WAAW,4BAA4B;IAC3C;;;;OAIG;IACH,QAAQ,CAAC,mBAAmB,CAAC,EAAE,MAAM,CAAC;CACvC;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,GAAE,4BAAiC,GAAG,SAAS,CA2BjG;AAID;;;;;;;GAOG;AACH,wBAAgB,6BAA6B,IAAI,SAAS,CAoBzD;AAGD,OAAO,EAAE,YAAY,EAAE,CAAC;AAIxB;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,CA2BlE;AAID;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;OAKG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iEAAiE;IACjE,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,wBAAwB,CACtC,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,EACjD,OAAO,CAAC,EAAE,yBAAyB,GAClC,SAAS,CA6DX;AAOD;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAwBtE;AAmBD;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CACtC,cAAc,EAAE,OAAO,EACvB,eAAe,EAAE,OAAO,GACvB,SAAS,GAAG,IAAI,CA8BlB"}
|
|
@@ -40,6 +40,9 @@ export interface RenderSignals {
|
|
|
40
40
|
lastUnhandledError: unknown | null;
|
|
41
41
|
/** Callback fired when a redirect or deny signal is captured in onError. */
|
|
42
42
|
onSignal?: () => void;
|
|
43
|
+
/** Callback fired when an unhandled error (non-signal) is captured. Used
|
|
44
|
+
* to halt Flight data injection into the inline stream. */
|
|
45
|
+
onUnhandledError?: () => void;
|
|
43
46
|
}
|
|
44
47
|
export interface RscStreamResult {
|
|
45
48
|
rscStream: ReadableStream<Uint8Array> | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,kBAAkB,CAAC;AAG3E,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAItB;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,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;
|
|
1
|
+
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAOH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,kBAAkB,CAAC;AAG3E,OAAO,EAIL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAItB;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,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;CAClD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,CA6J1F"}
|
|
@@ -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;AAIlE,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;AAW/D,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAarD;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAiB,CAAC;AAEhF,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;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,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;AAIlE,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;AAW/D,OAAO,EAAmB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAE5E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAarD;;;;;;;;GAQG;AACH,eAAO,MAAM,gCAAgC,EAAE;IAAE,KAAK,EAAE,MAAM,CAAA;CAAiB,CAAC;AAEhF,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;CAC/B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAiSjF"}
|
|
@@ -76,6 +76,13 @@ export interface NavContext {
|
|
|
76
76
|
/** Whether the Node.js native stream path was used */
|
|
77
77
|
nodeStreams: boolean;
|
|
78
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Signal that fires when an unhandled RSC error is detected.
|
|
81
|
+
* The Flight injector checks this before writing each script tag —
|
|
82
|
+
* when aborted, it stops injecting Flight data to prevent corrupted
|
|
83
|
+
* chunks from crashing the client's Flight decoder.
|
|
84
|
+
*/
|
|
85
|
+
_errorSignal?: AbortSignal;
|
|
79
86
|
}
|
|
80
87
|
/**
|
|
81
88
|
* Handle SSR: decode an RSC stream and render it to hydration-ready HTML.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-entry.d.ts","sourceRoot":"","sources":["../../src/server/ssr-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,uCAAuC,CAAC;AA2E/C;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,eAAe,EAAE,OAAO,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qEAAqE;IACrE,SAAS,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC;;;0DAGsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;iFAE6E;IAC7E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;4DACwD;IACxD,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE;QACZ,gFAAgF;QAChF,QAAQ,EAAE,MAAM,CAAC;QACjB,uDAAuD;QACvD,OAAO,EAAE,MAAM,CAAC;QAChB,gEAAgE;QAChE,MAAM,EAAE,MAAM,CAAC;QACf,wEAAwE;QACxE,UAAU,EAAE,MAAM,CAAC;QACnB,+CAA+C;QAC/C,OAAO,EAAE,MAAM,CAAC;QAChB,sDAAsD;QACtD,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;
|
|
1
|
+
{"version":3,"file":"ssr-entry.d.ts","sourceRoot":"","sources":["../../src/server/ssr-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,uCAAuC,CAAC;AA2E/C;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,eAAe,EAAE,OAAO,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qEAAqE;IACrE,SAAS,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC;;;0DAGsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;iFAE6E;IAC7E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;4DACwD;IACxD,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;IAEjC;;;;;;;OAOG;IACH,WAAW,CAAC,EAAE;QACZ,gFAAgF;QAChF,QAAQ,EAAE,MAAM,CAAC;QACjB,uDAAuD;QACvD,OAAO,EAAE,MAAM,CAAC;QAChB,gEAAgE;QAChE,MAAM,EAAE,MAAM,CAAC;QACf,wEAAwE;QACxE,UAAU,EAAE,MAAM,CAAC;QACnB,+CAA+C;QAC/C,OAAO,EAAE,MAAM,CAAC;QAChB,sDAAsD;QACtD,WAAW,EAAE,OAAO,CAAC;KACtB,CAAC;IAEF;;;;;OAKG;IACH,YAAY,CAAC,EAAE,WAAW,CAAC;CAC5B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,QAAQ,CAAC,CA6LnB;AAED,eAAe,SAAS,CAAC"}
|
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.118",
|
|
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",
|
|
@@ -59,6 +59,12 @@ export const RESOLVED_FONT_CSS_PREFIX = '\0' + VIRTUAL_FONT_CSS_PREFIX;
|
|
|
59
59
|
* Scoped to a single `FontPipeline` instance to avoid cross-plugin-
|
|
60
60
|
* instance collisions during multi-build pipelines.
|
|
61
61
|
*/
|
|
62
|
+
function stripIdDecorations(id: string): string {
|
|
63
|
+
const bare = id.startsWith('\0') ? id.slice(1) : id;
|
|
64
|
+
const qIdx = bare.indexOf('?');
|
|
65
|
+
return qIdx === -1 ? bare : bare.slice(0, qIdx);
|
|
66
|
+
}
|
|
67
|
+
|
|
62
68
|
export class VirtualFontCssIdMap {
|
|
63
69
|
private readonly map = new Map<string, string>();
|
|
64
70
|
|
|
@@ -75,7 +81,7 @@ export class VirtualFontCssIdMap {
|
|
|
75
81
|
|
|
76
82
|
/** Decode the importer from a resolved (or unresolved) virtual css id. */
|
|
77
83
|
importerFor(id: string): string | undefined {
|
|
78
|
-
const body =
|
|
84
|
+
const body = stripIdDecorations(id);
|
|
79
85
|
if (!body.startsWith(VIRTUAL_FONT_CSS_PREFIX)) return undefined;
|
|
80
86
|
if (!body.endsWith(VIRTUAL_FONT_CSS_SUFFIX)) return undefined;
|
|
81
87
|
const hash = body.slice(
|
|
@@ -87,7 +93,7 @@ export class VirtualFontCssIdMap {
|
|
|
87
93
|
|
|
88
94
|
/** True if `id` is any form of the virtual font css module. */
|
|
89
95
|
matches(id: string): boolean {
|
|
90
|
-
const body =
|
|
96
|
+
const body = stripIdDecorations(id);
|
|
91
97
|
return body.startsWith(VIRTUAL_FONT_CSS_PREFIX) && body.endsWith(VIRTUAL_FONT_CSS_SUFFIX);
|
|
92
98
|
}
|
|
93
99
|
|
package/src/plugins/fonts.ts
CHANGED
|
@@ -97,6 +97,8 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
97
97
|
*/
|
|
98
98
|
resolveId(id: string) {
|
|
99
99
|
let cleanId = id.startsWith('\0') ? id.slice(1) : id;
|
|
100
|
+
const qIdx = cleanId.indexOf('?');
|
|
101
|
+
if (qIdx !== -1) cleanId = cleanId.slice(0, qIdx);
|
|
100
102
|
if (cleanId.startsWith(ctx.root)) {
|
|
101
103
|
const stripped = cleanId.slice(ctx.root.length);
|
|
102
104
|
if (stripped.startsWith('/') || stripped.startsWith('\\')) {
|
|
@@ -299,12 +299,18 @@ export class FlightInjectorCore {
|
|
|
299
299
|
|
|
300
300
|
private readonly rscReader: ReadableStreamDefaultReader<Uint8Array>;
|
|
301
301
|
private readonly timeoutMs: number;
|
|
302
|
+
private readonly errorSignal?: AbortSignal;
|
|
302
303
|
private readonly decoder = new TextDecoder('utf-8', { fatal: true });
|
|
303
304
|
private pullPromise: Promise<void> | null = null;
|
|
304
305
|
|
|
305
|
-
constructor(
|
|
306
|
+
constructor(
|
|
307
|
+
rscStream: ReadableStream<Uint8Array>,
|
|
308
|
+
renderTimeoutMs?: number,
|
|
309
|
+
errorSignal?: AbortSignal
|
|
310
|
+
) {
|
|
306
311
|
this.rscReader = rscStream.getReader();
|
|
307
312
|
this.timeoutMs = renderTimeoutMs ?? 30_000;
|
|
313
|
+
this.errorSignal = errorSignal;
|
|
308
314
|
this.machine = createMachine<FlightInjectionState, FlightInjectionEvent>({
|
|
309
315
|
initial: { phase: 'init' },
|
|
310
316
|
transitions: flightInjectionTransitions,
|
|
@@ -377,6 +383,14 @@ export class FlightInjectorCore {
|
|
|
377
383
|
return;
|
|
378
384
|
}
|
|
379
385
|
|
|
386
|
+
// If an unhandled RSC error was detected, stop injecting Flight
|
|
387
|
+
// data. Continue reading (to prevent tee buffer divergence) but
|
|
388
|
+
// discard the chunks so corrupted data never reaches the client.
|
|
389
|
+
// See TIM-938.
|
|
390
|
+
if (this.errorSignal?.aborted) {
|
|
391
|
+
continue;
|
|
392
|
+
}
|
|
393
|
+
|
|
380
394
|
const decoded = this.decoder.decode(value, { stream: true });
|
|
381
395
|
this.pending.push(encoder.encode(flightChunkScript(decoded)));
|
|
382
396
|
|
|
@@ -250,9 +250,10 @@ export function createInlinedRscStream(
|
|
|
250
250
|
*/
|
|
251
251
|
function createFlightInjectionTransform(
|
|
252
252
|
rscStream: ReadableStream<Uint8Array>,
|
|
253
|
-
renderTimeoutMs?: number
|
|
253
|
+
renderTimeoutMs?: number,
|
|
254
|
+
errorSignal?: AbortSignal
|
|
254
255
|
): TransformStream<Uint8Array, Uint8Array> {
|
|
255
|
-
const core = new FlightInjectorCore(rscStream, renderTimeoutMs);
|
|
256
|
+
const core = new FlightInjectorCore(rscStream, renderTimeoutMs, errorSignal);
|
|
256
257
|
// Controller reference — set on first transform() call so the pull
|
|
257
258
|
// loop can drain pending scripts between HTML chunks (after yielding).
|
|
258
259
|
let _controller: TransformStreamDefaultController<Uint8Array> | null = null;
|
|
@@ -322,7 +323,8 @@ function createFlightInjectionTransform(
|
|
|
322
323
|
export function injectRscPayload(
|
|
323
324
|
htmlStream: ReadableStream<Uint8Array>,
|
|
324
325
|
rscStream: ReadableStream<Uint8Array> | undefined,
|
|
325
|
-
renderTimeoutMs?: number
|
|
326
|
+
renderTimeoutMs?: number,
|
|
327
|
+
errorSignal?: AbortSignal
|
|
326
328
|
): ReadableStream<Uint8Array> {
|
|
327
329
|
if (!rscStream) return htmlStream;
|
|
328
330
|
// Pass the raw RSC stream directly to the flight injection transform.
|
|
@@ -330,7 +332,7 @@ export function injectRscPayload(
|
|
|
330
332
|
// <script> via flightChunkScript itself — do NOT pre-wrap with
|
|
331
333
|
// createInlinedRscStream here, that would double-wrap.
|
|
332
334
|
return htmlStream
|
|
333
|
-
.pipeThrough(createFlightInjectionTransform(rscStream, renderTimeoutMs))
|
|
335
|
+
.pipeThrough(createFlightInjectionTransform(rscStream, renderTimeoutMs, errorSignal))
|
|
334
336
|
.pipeThrough(createMoveSuffixStream());
|
|
335
337
|
}
|
|
336
338
|
|
|
@@ -172,6 +172,8 @@ export interface NodeFlightInjectorOptions {
|
|
|
172
172
|
* Default: 30000 (30s).
|
|
173
173
|
*/
|
|
174
174
|
renderTimeoutMs?: number;
|
|
175
|
+
/** Signal that fires when an unhandled RSC error is detected. */
|
|
176
|
+
errorSignal?: AbortSignal;
|
|
175
177
|
}
|
|
176
178
|
|
|
177
179
|
/**
|
|
@@ -204,7 +206,7 @@ export function createNodeFlightInjector(
|
|
|
204
206
|
});
|
|
205
207
|
}
|
|
206
208
|
|
|
207
|
-
const core = new FlightInjectorCore(rscStream, options?.renderTimeoutMs);
|
|
209
|
+
const core = new FlightInjectorCore(rscStream, options?.renderTimeoutMs, options?.errorSignal);
|
|
208
210
|
|
|
209
211
|
const drain = (): void => {
|
|
210
212
|
while (core.pending.length > 0) transform.push(Buffer.from(core.pending.shift()!));
|
|
@@ -53,6 +53,9 @@ export interface RenderSignals {
|
|
|
53
53
|
lastUnhandledError: unknown | null;
|
|
54
54
|
/** Callback fired when a redirect or deny signal is captured in onError. */
|
|
55
55
|
onSignal?: () => void;
|
|
56
|
+
/** Callback fired when an unhandled error (non-signal) is captured. Used
|
|
57
|
+
* to halt Flight data injection into the inline stream. */
|
|
58
|
+
onUnhandledError?: () => void;
|
|
56
59
|
}
|
|
57
60
|
|
|
58
61
|
export interface RscStreamResult {
|
|
@@ -165,6 +168,7 @@ export function renderRscStream(element: React.ReactElement, req: Request): RscS
|
|
|
165
168
|
// if SSR fails (SsrStreamError). This is NOT used for page-level
|
|
166
169
|
// error detection — only as a fallback when SSR actually fails.
|
|
167
170
|
signals.lastUnhandledError = error;
|
|
171
|
+
signals.onUnhandledError?.();
|
|
168
172
|
|
|
169
173
|
// Return a digest so React emits a per-row error in the Flight
|
|
170
174
|
// stream instead of leaving the lazy reference unresolved.
|
|
@@ -124,6 +124,14 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
124
124
|
[ssrStream, inlineStream] = teeWithErrorPropagation(rscStream);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// Wire an AbortController so the Flight injector stops writing <script>
|
|
128
|
+
// tags when an unhandled RSC error is detected. Without this, React's
|
|
129
|
+
// Flight encoder may write model data for a chunk that already received
|
|
130
|
+
// an error row, causing the client's Flight decoder to crash with
|
|
131
|
+
// "enqueueModel is not a function". See TIM-938.
|
|
132
|
+
const errorAbort = new AbortController();
|
|
133
|
+
signals.onUnhandledError = () => errorAbort.abort();
|
|
134
|
+
|
|
127
135
|
// Embed segment metadata in HTML for initial hydration.
|
|
128
136
|
// The client reads this to populate its segment cache before the
|
|
129
137
|
// first navigation, enabling state tree diffing from the start.
|
|
@@ -159,6 +167,7 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
159
167
|
deferSuspenseFor: deferSuspenseFor > 0 ? deferSuspenseFor : undefined,
|
|
160
168
|
signal: req.signal,
|
|
161
169
|
cookies: getCookiesForSsr(),
|
|
170
|
+
_errorSignal: errorAbort.signal,
|
|
162
171
|
};
|
|
163
172
|
|
|
164
173
|
// Helper: check if render-phase signals were captured and return the
|
|
@@ -280,6 +289,7 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
280
289
|
// Connection abort — the client disconnected (page refresh, navigation
|
|
281
290
|
// away). No response needed; return empty 499 (client closed request).
|
|
282
291
|
if (isAbortError(ssrError) || req.signal?.aborted) {
|
|
292
|
+
inlineStream?.cancel().catch(() => {});
|
|
283
293
|
return new Response(null, { status: 499 });
|
|
284
294
|
}
|
|
285
295
|
|
|
@@ -302,6 +312,12 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
302
312
|
ssrError instanceof SsrStreamError ||
|
|
303
313
|
(ssrError instanceof Error && ssrError.name === 'SsrStreamError');
|
|
304
314
|
if (isSsrStreamError) {
|
|
315
|
+
// Cancel the teed inline stream — SSR failed so this response will
|
|
316
|
+
// be replaced by renderErrorPage which creates its own clean streams.
|
|
317
|
+
// Without explicit cancellation the orphaned tee branch keeps the
|
|
318
|
+
// RSC source stream alive, preventing garbage collection.
|
|
319
|
+
inlineStream?.cancel().catch(() => {});
|
|
320
|
+
|
|
305
321
|
if (signals.redirectSignal) {
|
|
306
322
|
return buildRedirectResponse(req, signals.redirectSignal, responseHeaders);
|
|
307
323
|
}
|
package/src/server/ssr-entry.ts
CHANGED
|
@@ -157,6 +157,14 @@ export interface NavContext {
|
|
|
157
157
|
/** Whether the Node.js native stream path was used */
|
|
158
158
|
nodeStreams: boolean;
|
|
159
159
|
};
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Signal that fires when an unhandled RSC error is detected.
|
|
163
|
+
* The Flight injector checks this before writing each script tag —
|
|
164
|
+
* when aborted, it stops injecting Flight data to prevent corrupted
|
|
165
|
+
* chunks from crashing the client's Flight decoder.
|
|
166
|
+
*/
|
|
167
|
+
_errorSignal?: AbortSignal;
|
|
160
168
|
}
|
|
161
169
|
|
|
162
170
|
/**
|
|
@@ -291,6 +299,7 @@ export async function handleSsr(
|
|
|
291
299
|
const headInjector = createNodeHeadInjector(navContext.headHtml);
|
|
292
300
|
const flightInjector = createNodeFlightInjector(navContext.rscStream, {
|
|
293
301
|
renderTimeoutMs,
|
|
302
|
+
errorSignal: navContext._errorSignal,
|
|
294
303
|
});
|
|
295
304
|
const moveSuffix = createNodeMoveSuffixTransform();
|
|
296
305
|
|
|
@@ -350,7 +359,12 @@ export async function handleSsr(
|
|
|
350
359
|
// structure (TIM-527).
|
|
351
360
|
let outputStream = htmlStream.pipeThrough(createBufferedTransformStream());
|
|
352
361
|
outputStream = injectHead(outputStream, navContext.headHtml);
|
|
353
|
-
outputStream = injectRscPayload(
|
|
362
|
+
outputStream = injectRscPayload(
|
|
363
|
+
outputStream,
|
|
364
|
+
navContext.rscStream,
|
|
365
|
+
renderTimeoutMs,
|
|
366
|
+
navContext._errorSignal
|
|
367
|
+
);
|
|
354
368
|
const _pipelineEnd = performance.now();
|
|
355
369
|
|
|
356
370
|
navContext._ssrTimings = {
|