@timber-js/app 0.2.0-alpha.126 → 0.2.0-alpha.128
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/_chunks/{walkers-DMSGZeCk.js → walkers-E5ss0qES.js} +7 -5
- package/dist/_chunks/walkers-E5ss0qES.js.map +1 -0
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/routing/codegen-shared.d.ts +5 -2
- package/dist/routing/codegen-shared.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/server/deny-renderer.d.ts +1 -1
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts +5 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/ssr-bridge-types.d.ts +121 -0
- package/dist/server/ssr-bridge-types.d.ts.map +1 -0
- package/dist/server/ssr-entry.d.ts +1 -72
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/ssr-render.d.ts +15 -0
- package/dist/server/ssr-render.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/plugins/fonts.ts +9 -1
- package/src/routing/codegen-shared.ts +6 -3
- package/src/server/deny-renderer.ts +2 -2
- package/src/server/rsc-entry/error-renderer.ts +14 -4
- package/src/server/rsc-entry/ssr-bridge.ts +5 -1
- package/src/server/rsc-entry/ssr-renderer.ts +25 -21
- package/src/server/ssr-bridge-types.ts +124 -0
- package/src/server/ssr-entry.ts +9 -77
- package/src/server/ssr-render.ts +40 -4
- package/dist/_chunks/walkers-DMSGZeCk.js.map +0 -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,CAsLtD"}
|
|
@@ -48,8 +48,11 @@ export declare function buildCodecChainType(p: ParamEntry, importBase: string |
|
|
|
48
48
|
* schema's InferCodecType. Falls back to the param's base type when
|
|
49
49
|
* schema doesn't declare this param (schemas are opt-in per key).
|
|
50
50
|
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
51
|
+
* Uses `infer` to extract the codec value rather than direct indexing
|
|
52
|
+
* because TypeScript doesn't narrow index validity inside a conditional
|
|
53
|
+
* type's true branch — `typeof schema.segmentParams[K]` produces TS2538
|
|
54
|
+
* even when the condition proves K is a valid key. In .d.ts files that
|
|
55
|
+
* error is suppressed and the type silently becomes `any`.
|
|
53
56
|
*/
|
|
54
57
|
export declare function buildSchemaParamType(p: ParamEntry, fallback?: string): string;
|
|
55
58
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegen-shared.d.ts","sourceRoot":"","sources":["../../src/routing/codegen-shared.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAM7F;AAED,sEAAsE;AACtE,eAAO,MAAM,+BAA+B,+BAA+B,CAAC;AAE5E;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAOtD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,UAAU,EACb,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,QAAQ,EAAE,MAAM,GACf,MAAM,CAaR;AAED
|
|
1
|
+
{"version":3,"file":"codegen-shared.d.ts","sourceRoot":"","sources":["../../src/routing/codegen-shared.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEjE;;;GAGG;AACH,wBAAgB,eAAe,CAAC,aAAa,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAM7F;AAED,sEAAsE;AACtE,eAAO,MAAM,+BAA+B,+BAA+B,CAAC;AAE5E;;;;;;;;;;;;GAYG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAOtD;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,CAAC,EAAE,UAAU,EACb,UAAU,EAAE,MAAM,GAAG,SAAS,EAC9B,QAAQ,EAAE,MAAM,GACf,MAAM,CAaR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,UAAU,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAI7E;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,UAAU,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAOrF"}
|
package/dist/routing/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { i as INTERCEPTION_MARKERS, n as classifyUrlSegment, r as DEFAULT_PAGE_EXTENSIONS, t as classifySegment } from "../_chunks/segment-classify-BjfuctV2.js";
|
|
2
2
|
import { m as scanRoutes } from "../_chunks/cli-schema-sync-DFHBj6yZ.js";
|
|
3
|
-
import { a as generateRouteMap, i as collectInterceptionRewrites, n as collectDynamicSegmentsFromTree, r as validateSchemaAgainstRoutes, t as collectLeafRoutes } from "../_chunks/walkers-
|
|
3
|
+
import { a as generateRouteMap, i as collectInterceptionRewrites, n as collectDynamicSegmentsFromTree, r as validateSchemaAgainstRoutes, t as collectLeafRoutes } from "../_chunks/walkers-E5ss0qES.js";
|
|
4
4
|
export { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS, classifySegment, classifyUrlSegment, collectDynamicSegmentsFromTree, collectInterceptionRewrites, collectLeafRoutes, generateRouteMap, scanRoutes, validateSchemaAgainstRoutes };
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import { DenySignal } from './primitives.js';
|
|
18
18
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
19
19
|
import type { RouteMatch } from './pipeline.js';
|
|
20
|
-
import type { NavContext } from './ssr-
|
|
20
|
+
import type { NavContext } from './ssr-bridge-types.js';
|
|
21
21
|
import type { ClientBootstrapConfig } from './html-injectors.js';
|
|
22
22
|
/** Layout component entry for deny page wrapping. */
|
|
23
23
|
export interface LayoutEntry {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deny-renderer.d.ts","sourceRoot":"","sources":["../../src/server/deny-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAO7C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"deny-renderer.d.ts","sourceRoot":"","sources":["../../src/server/deny-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAO7C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAC9D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAExD,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAOjE,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,iEAAiE;AACjE,MAAM,MAAM,mBAAmB,GAAG,MAAM;IACtC,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;CAC1B,CAAC;AAEF,6DAA6D;AAC7D,MAAM,MAAM,SAAS,GAAG,CACtB,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,UAAU,EAAE,UAAU,KACnB,OAAO,CAAC,QAAQ,CAAC,CAAC;AAUvB;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,UAAU,EAChB,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,sBAAsB,EAAE,mBAAmB,EAC3C,OAAO,EAAE,SAAS,GACjB,OAAO,CAAC,QAAQ,CAAC,CAiGnB;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,IAAI,EAAE,UAAU,EAChB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,WAAW,EAAE,EAC/B,eAAe,EAAE,OAAO,EACxB,sBAAsB,EAAE,mBAAmB,GAC1C,OAAO,CAAC,QAAQ,CAAC,CA2CnB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/error-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGlE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAYvD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqHD;;;;;;GAMG;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,GAC5B,OAAO,CAAC,QAAQ,CAAC,CAwCnB;AAqID;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,OAAO,EACxB,eAAe,EAAE,qBAAqB,GACrC,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"error-renderer.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/error-renderer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEjD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAGlE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAYvD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAqHD;;;;;;GAMG;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,GAC5B,OAAO,CAAC,QAAQ,CAAC,CAwCnB;AAqID;;;;;;GAMG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,WAAW,EAAE,mBAAmB,EAChC,eAAe,EAAE,OAAO,EACxB,eAAe,EAAE,qBAAqB,GACrC,OAAO,CAAC,QAAQ,CAAC,CAuCnB"}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SSR Bridge — loads the SSR entry and passes the RSC stream for HTML rendering.
|
|
3
|
+
*
|
|
4
|
+
* This is the RSC → SSR environment hop. The two environments are separate
|
|
5
|
+
* Vite module graphs; `NavContext` is the serializable contract that crosses
|
|
6
|
+
* the boundary. See `../ssr-bridge-types.ts` for the contract definition.
|
|
3
7
|
*/
|
|
4
|
-
import type { NavContext } from '../ssr-
|
|
8
|
+
import type { NavContext } from '../ssr-bridge-types.js';
|
|
5
9
|
export declare function callSsr(rscStream: ReadableStream<Uint8Array>, navContext: NavContext): Promise<Response>;
|
|
6
10
|
//# sourceMappingURL=ssr-bridge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-bridge.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/ssr-bridge.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"ssr-bridge.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/ssr-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AAEzD,wBAAsB,OAAO,CAC3B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,QAAQ,CAAC,CAenB"}
|
|
@@ -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,CAqSjF"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RSC ↔ SSR Bridge Contract
|
|
3
|
+
*
|
|
4
|
+
* This file defines the payload that crosses the RSC → SSR environment
|
|
5
|
+
* boundary. The RSC environment calls `handleSsr(rscStream, navContext)`
|
|
6
|
+
* in the SSR environment via `import.meta.viteRsc.import(...)` (see
|
|
7
|
+
* `rsc-entry/ssr-bridge.ts`). RSC and SSR are separate Vite module graphs
|
|
8
|
+
* with separate module instances, so every per-request field that SSR
|
|
9
|
+
* needs must be declared here and passed explicitly.
|
|
10
|
+
*
|
|
11
|
+
* Rules for changes to this file:
|
|
12
|
+
*
|
|
13
|
+
* 1. **Structurally serializable shape.** Fields must be values that can
|
|
14
|
+
* cross the environment boundary as plain data or as platform-neutral
|
|
15
|
+
* primitives (`Headers`, `ReadableStream`, `AbortSignal`, `Map`). Do
|
|
16
|
+
* not add closures, class instances tied to RSC-only modules, or
|
|
17
|
+
* anything whose identity must be preserved across the bridge.
|
|
18
|
+
*
|
|
19
|
+
* 2. **No runtime imports of RSC-only modules.** This file is read by
|
|
20
|
+
* both environments at type-check time. Keep it type-only. Importing
|
|
21
|
+
* an RSC-only runtime module here couples SSR to RSC internals.
|
|
22
|
+
*
|
|
23
|
+
* 3. **Shape changes are public-surface changes.** Adding, removing, or
|
|
24
|
+
* renaming a field is a change to the contract between two
|
|
25
|
+
* independently-built bundles. Update every caller in the same PR —
|
|
26
|
+
* do not rely on back-compat shims.
|
|
27
|
+
*
|
|
28
|
+
* See `design/02-rendering-pipeline.md` §"RSC → SSR → Client Hydration"
|
|
29
|
+
* and `CLAUDE.md` §"RSC and SSR Are Separate Vite Environments".
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Navigation context passed from the RSC environment to SSR.
|
|
33
|
+
*
|
|
34
|
+
* Per-request state must be explicitly passed across the RSC→SSR
|
|
35
|
+
* environment boundary since they are separate Vite module graphs.
|
|
36
|
+
*/
|
|
37
|
+
export interface NavContext {
|
|
38
|
+
/** The requested pathname */
|
|
39
|
+
pathname: string;
|
|
40
|
+
/** Extracted route segment params (catch-all segments produce string[]) */
|
|
41
|
+
segmentParams: Record<string, string | string[]>;
|
|
42
|
+
/** Search params from the URL */
|
|
43
|
+
searchParams: Record<string, string>;
|
|
44
|
+
/** The committed HTTP status code */
|
|
45
|
+
statusCode: number;
|
|
46
|
+
/** Response headers from middleware/proxy */
|
|
47
|
+
responseHeaders: Headers;
|
|
48
|
+
/** Pre-rendered metadata HTML to inject before </head> */
|
|
49
|
+
headHtml: string;
|
|
50
|
+
/** Inline JS for React's bootstrapScriptContent — kicks off module loading */
|
|
51
|
+
bootstrapScriptContent: string;
|
|
52
|
+
/** Tee'd RSC stream for client-side hydration (inlined into HTML) */
|
|
53
|
+
rscStream?: ReadableStream<Uint8Array>;
|
|
54
|
+
/** Max Suspense hold window (ms). SSR delays the first flush by this
|
|
55
|
+
* duration, racing allReady so that fast-resolving boundaries render inline
|
|
56
|
+
* without ever showing a fallback. Derived from route `deferSuspenseFor` exports.
|
|
57
|
+
* See design/05-streaming.md §"deferSuspenseFor". */
|
|
58
|
+
deferSuspenseFor?: number;
|
|
59
|
+
/** Request abort signal. When the client disconnects (page refresh,
|
|
60
|
+
* navigation away), this signal fires. Passed to renderToReadableStream
|
|
61
|
+
* so React stops rendering and doesn't fire error boundaries for aborts. */
|
|
62
|
+
signal?: AbortSignal;
|
|
63
|
+
/** Request cookies as name→value pairs. Used by useCookie() during SSR
|
|
64
|
+
* to return correct cookie values before hydration. */
|
|
65
|
+
cookies?: Map<string, string>;
|
|
66
|
+
/**
|
|
67
|
+
* Mutable flag: set by TimberErrorBoundary during SSR when it catches
|
|
68
|
+
* a DenySignal (via digest). This tells the RSC entry that the denial
|
|
69
|
+
* was contained by a slot error boundary and should NOT be promoted
|
|
70
|
+
* to a page-level deny. See LOCAL-298.
|
|
71
|
+
*/
|
|
72
|
+
_denyHandledByBoundary?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* Mutable: SSR timing data populated by handleSsr().
|
|
75
|
+
* Read by the RSC entry to record sub-phase Server-Timing entries
|
|
76
|
+
* when `serverTiming: 'detailed'` is configured.
|
|
77
|
+
*
|
|
78
|
+
* This bridges the RSC→SSR environment boundary: the SSR entry populates
|
|
79
|
+
* these fields, the RSC entry reads them after callSsr() returns.
|
|
80
|
+
*/
|
|
81
|
+
_ssrTimings?: {
|
|
82
|
+
/** Time to decode RSC stream (createFromReadableStream/createFromNodeStream) */
|
|
83
|
+
decodeMs: number;
|
|
84
|
+
/** Time for Fizz to render the shell (onShellReady) */
|
|
85
|
+
shellMs: number;
|
|
86
|
+
/** Time for pipe() to flush shell bytes to the output stream */
|
|
87
|
+
pipeMs: number;
|
|
88
|
+
/** Time to set up Node.js Transform pipeline / Web Stream transforms */
|
|
89
|
+
pipelineMs: number;
|
|
90
|
+
/** Total SSR time (decode → response ready) */
|
|
91
|
+
totalMs: number;
|
|
92
|
+
/** Whether the Node.js native stream path was used */
|
|
93
|
+
nodeStreams: boolean;
|
|
94
|
+
};
|
|
95
|
+
/**
|
|
96
|
+
* Signal that fires when an unhandled RSC error is detected.
|
|
97
|
+
* The Flight injector checks this before writing each script tag —
|
|
98
|
+
* when aborted, it stops injecting Flight data to prevent corrupted
|
|
99
|
+
* chunks from crashing the client's Flight decoder.
|
|
100
|
+
*/
|
|
101
|
+
_errorSignal?: AbortSignal;
|
|
102
|
+
/**
|
|
103
|
+
* Mutable flag: set by the SSR entry when Fizz's `stream.allReady`
|
|
104
|
+
* settled before the `deferSuspenseFor` hold ended.
|
|
105
|
+
*
|
|
106
|
+
* When true, the RSC entry can skip its signal-promotion
|
|
107
|
+
* microtask-retry wait: Fizz allReady implies Flight closed its
|
|
108
|
+
* stream, which implies `onError` already fired for every rejected
|
|
109
|
+
* Flight task. Any DenySignal/RedirectSignal/RenderError in-tree has
|
|
110
|
+
* already been captured in `RenderSignals`.
|
|
111
|
+
*
|
|
112
|
+
* When false or undefined (hold timed out, no hold window, shell-only
|
|
113
|
+
* return, Node error path), no such guarantee — the RSC entry falls
|
|
114
|
+
* back to the bounded microtask retry loop.
|
|
115
|
+
*
|
|
116
|
+
* See design/05-streaming.md §"deferSuspenseFor and the Hold Window"
|
|
117
|
+
* and design/spike-signal-promotion-protocol.md (Option 1).
|
|
118
|
+
*/
|
|
119
|
+
_fizzAllReadyResolved?: boolean;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=ssr-bridge-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ssr-bridge-types.d.ts","sourceRoot":"","sources":["../../src/server/ssr-bridge-types.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,2EAA2E;IAC3E,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IACjD,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;IAE3B;;;;;;;;;;;;;;;;OAgBG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;CACjC"}
|
|
@@ -12,78 +12,7 @@
|
|
|
12
12
|
* Design docs: 18-build-system.md §"Entry Files", 02-rendering-pipeline.md
|
|
13
13
|
*/
|
|
14
14
|
import 'virtual:timber-search-params-registry';
|
|
15
|
-
|
|
16
|
-
* Navigation context passed from the RSC environment to SSR.
|
|
17
|
-
*
|
|
18
|
-
* Per-request state must be explicitly passed across the RSC→SSR
|
|
19
|
-
* environment boundary since they are separate Vite module graphs.
|
|
20
|
-
*/
|
|
21
|
-
export interface NavContext {
|
|
22
|
-
/** The requested pathname */
|
|
23
|
-
pathname: string;
|
|
24
|
-
/** Extracted route params (catch-all segments produce string[]) */
|
|
25
|
-
params: Record<string, string | string[]>;
|
|
26
|
-
/** Search params from the URL */
|
|
27
|
-
searchParams: Record<string, string>;
|
|
28
|
-
/** The committed HTTP status code */
|
|
29
|
-
statusCode: number;
|
|
30
|
-
/** Response headers from middleware/proxy */
|
|
31
|
-
responseHeaders: Headers;
|
|
32
|
-
/** Pre-rendered metadata HTML to inject before </head> */
|
|
33
|
-
headHtml: string;
|
|
34
|
-
/** Inline JS for React's bootstrapScriptContent — kicks off module loading */
|
|
35
|
-
bootstrapScriptContent: string;
|
|
36
|
-
/** Tee'd RSC stream for client-side hydration (inlined into HTML) */
|
|
37
|
-
rscStream?: ReadableStream<Uint8Array>;
|
|
38
|
-
/** Max Suspense hold window (ms). SSR delays the first flush by this
|
|
39
|
-
* duration, racing allReady so that fast-resolving boundaries render inline
|
|
40
|
-
* without ever showing a fallback. Derived from route `deferSuspenseFor` exports.
|
|
41
|
-
* See design/05-streaming.md §"deferSuspenseFor". */
|
|
42
|
-
deferSuspenseFor?: number;
|
|
43
|
-
/** Request abort signal. When the client disconnects (page refresh,
|
|
44
|
-
* navigation away), this signal fires. Passed to renderToReadableStream
|
|
45
|
-
* so React stops rendering and doesn't fire error boundaries for aborts. */
|
|
46
|
-
signal?: AbortSignal;
|
|
47
|
-
/** Request cookies as name→value pairs. Used by useCookie() during SSR
|
|
48
|
-
* to return correct cookie values before hydration. */
|
|
49
|
-
cookies?: Map<string, string>;
|
|
50
|
-
/**
|
|
51
|
-
* Mutable flag: set by TimberErrorBoundary during SSR when it catches
|
|
52
|
-
* a DenySignal (via digest). This tells the RSC entry that the denial
|
|
53
|
-
* was contained by a slot error boundary and should NOT be promoted
|
|
54
|
-
* to a page-level deny. See LOCAL-298.
|
|
55
|
-
*/
|
|
56
|
-
_denyHandledByBoundary?: boolean;
|
|
57
|
-
/**
|
|
58
|
-
* Mutable: SSR timing data populated by handleSsr().
|
|
59
|
-
* Read by the RSC entry to record sub-phase Server-Timing entries
|
|
60
|
-
* when `serverTiming: 'detailed'` is configured.
|
|
61
|
-
*
|
|
62
|
-
* This bridges the RSC→SSR environment boundary: the SSR entry populates
|
|
63
|
-
* these fields, the RSC entry reads them after callSsr() returns.
|
|
64
|
-
*/
|
|
65
|
-
_ssrTimings?: {
|
|
66
|
-
/** Time to decode RSC stream (createFromReadableStream/createFromNodeStream) */
|
|
67
|
-
decodeMs: number;
|
|
68
|
-
/** Time for Fizz to render the shell (onShellReady) */
|
|
69
|
-
shellMs: number;
|
|
70
|
-
/** Time for pipe() to flush shell bytes to the output stream */
|
|
71
|
-
pipeMs: number;
|
|
72
|
-
/** Time to set up Node.js Transform pipeline / Web Stream transforms */
|
|
73
|
-
pipelineMs: number;
|
|
74
|
-
/** Total SSR time (decode → response ready) */
|
|
75
|
-
totalMs: number;
|
|
76
|
-
/** Whether the Node.js native stream path was used */
|
|
77
|
-
nodeStreams: boolean;
|
|
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;
|
|
86
|
-
}
|
|
15
|
+
import type { NavContext } from './ssr-bridge-types.js';
|
|
87
16
|
/**
|
|
88
17
|
* Handle SSR: decode an RSC stream and render it to hydration-ready HTML.
|
|
89
18
|
*
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"ssr-entry.d.ts","sourceRoot":"","sources":["../../src/server/ssr-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,uCAAuC,CAAC;AA4B/C,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,uBAAuB,CAAC;AAsDxD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,QAAQ,CAAC,CAmMnB;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -39,6 +39,14 @@ export declare function renderSsrStream(element: ReactNode, options?: {
|
|
|
39
39
|
deferSuspenseFor?: number;
|
|
40
40
|
signal?: AbortSignal;
|
|
41
41
|
renderTimeoutMs?: number;
|
|
42
|
+
/**
|
|
43
|
+
* Fired synchronously when the render function is about to resolve
|
|
44
|
+
* (i.e. at hold-end / shell-ready). `resolved` reports whether Fizz's
|
|
45
|
+
* `stream.allReady` had already settled by that moment. Callers use
|
|
46
|
+
* this to decide whether signal promotion can be short-circuited.
|
|
47
|
+
* See NavContext._fizzAllReadyResolved.
|
|
48
|
+
*/
|
|
49
|
+
onFizzAllReadyResolved?: (resolved: boolean) => void;
|
|
42
50
|
}): Promise<ReadableStream<Uint8Array>>;
|
|
43
51
|
/** Whether the current platform uses native Node.js streams for SSR. */
|
|
44
52
|
export declare const useNodeStreams: boolean;
|
|
@@ -54,6 +62,13 @@ export declare function renderSsrNodeStream(element: ReactNode, options?: {
|
|
|
54
62
|
deferSuspenseFor?: number;
|
|
55
63
|
signal?: AbortSignal;
|
|
56
64
|
renderTimeoutMs?: number;
|
|
65
|
+
/**
|
|
66
|
+
* Fired synchronously at the moment `renderSsrNodeStream`'s returned
|
|
67
|
+
* Promise is about to resolve. `resolved` reports whether Fizz's
|
|
68
|
+
* `onAllReady` had already fired by then. See the twin callback on
|
|
69
|
+
* `renderSsrStream`.
|
|
70
|
+
*/
|
|
71
|
+
onFizzAllReadyResolved?: (resolved: boolean) => void;
|
|
57
72
|
}): Promise<import('node:stream').Readable>;
|
|
58
73
|
/** Convert a Node.js Readable to a Web ReadableStream (zero-copy bridge). */
|
|
59
74
|
export declare function nodeReadableToWeb(readable: import('node:stream').Readable): ReadableStream<Uint8Array>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-render.d.ts","sourceRoot":"","sources":["../../src/server/ssr-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAuFvC;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,SAAS,EAClB,OAAO,CAAC,EAAE;IACR,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"ssr-render.d.ts","sourceRoot":"","sources":["../../src/server/ssr-render.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAuFvC;;;;;;;;;;;;;GAaG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,SAAS,EAClB,OAAO,CAAC,EAAE;IACR,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;;OAMG;IACH,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;CACtD,GACA,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,CAAC,CAErC;AAED,wEAAwE;AACxE,eAAO,MAAM,cAAc,SAAkB,CAAC;AAU9C;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,SAAS,EAClB,OAAO,CAAC,EAAE;IACR,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;CACtD,GACA,OAAO,CAAC,OAAO,aAAa,EAAE,QAAQ,CAAC,CAgGzC;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,OAAO,aAAa,EAAE,QAAQ,GACvC,cAAc,CAAC,UAAU,CAAC,CAE5B;AAqGD;;;;;;;;;;;;GAYG;AACH,2CAA2C;AAC3C,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,MAAM,CAAC,EAAE,WAAW,GACnB,cAAc,CAAC,UAAU,CAAC,CA2B5B;AAWD;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,cAAc,CAAC,UAAU,CAAC,EACtC,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,OAAO,GACvB,QAAQ,CASV"}
|
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.128",
|
|
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",
|
package/src/plugins/fonts.ts
CHANGED
|
@@ -98,6 +98,7 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
98
98
|
resolveId(id: string) {
|
|
99
99
|
let cleanId = id.startsWith('\0') ? id.slice(1) : id;
|
|
100
100
|
const qIdx = cleanId.indexOf('?');
|
|
101
|
+
const query = qIdx !== -1 ? cleanId.slice(qIdx) : '';
|
|
101
102
|
if (qIdx !== -1) cleanId = cleanId.slice(0, qIdx);
|
|
102
103
|
if (cleanId.startsWith(ctx.root)) {
|
|
103
104
|
const stripped = cleanId.slice(ctx.root.length);
|
|
@@ -110,7 +111,14 @@ export function timberFonts(ctx: PluginContext): Plugin {
|
|
|
110
111
|
|
|
111
112
|
if (cleanId === VIRTUAL_GOOGLE) return RESOLVED_GOOGLE;
|
|
112
113
|
if (cleanId === VIRTUAL_LOCAL) return RESOLVED_LOCAL;
|
|
113
|
-
|
|
114
|
+
// Preserve query suffix (notably `?direct`) on the resolved CSS id.
|
|
115
|
+
// Vite's transform middleware appends `?direct` when the browser
|
|
116
|
+
// fetches the URL as a `<link rel="stylesheet">`, and the CSS plugin
|
|
117
|
+
// only skips its JS-wrapping step when `isDirectCSSRequest(id)` sees
|
|
118
|
+
// that query on the resolved id. Dropping it here caused virtual
|
|
119
|
+
// font CSS to be served as Vite's HMR JS shim, leaving the
|
|
120
|
+
// `<link>`-loaded stylesheet empty (TIM-937 follow-up).
|
|
121
|
+
if (pipeline.cssIdMap.matches(cleanId)) return '\0' + cleanId + query;
|
|
114
122
|
return null;
|
|
115
123
|
},
|
|
116
124
|
|
|
@@ -85,13 +85,16 @@ export function buildCodecChainType(
|
|
|
85
85
|
* schema's InferCodecType. Falls back to the param's base type when
|
|
86
86
|
* schema doesn't declare this param (schemas are opt-in per key).
|
|
87
87
|
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
88
|
+
* Uses `infer` to extract the codec value rather than direct indexing
|
|
89
|
+
* because TypeScript doesn't narrow index validity inside a conditional
|
|
90
|
+
* type's true branch — `typeof schema.segmentParams[K]` produces TS2538
|
|
91
|
+
* even when the condition proves K is a valid key. In .d.ts files that
|
|
92
|
+
* error is suppressed and the type silently becomes `any`.
|
|
90
93
|
*/
|
|
91
94
|
export function buildSchemaParamType(p: ParamEntry, fallback?: string): string {
|
|
92
95
|
const key = JSON.stringify(p.bracketName);
|
|
93
96
|
const fb = fallback ?? p.type;
|
|
94
|
-
return
|
|
97
|
+
return `typeof schema['segmentParams'] extends Record<${key}, infer V> ? InferCodecType<V> : ${fb}`;
|
|
95
98
|
}
|
|
96
99
|
|
|
97
100
|
/**
|
|
@@ -27,7 +27,7 @@ import { resolveMetadata, renderMetadataToElements } from './metadata.js';
|
|
|
27
27
|
import { resolveStatusFile } from './status-code-resolver.js';
|
|
28
28
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
29
29
|
import type { RouteMatch } from './pipeline.js';
|
|
30
|
-
import type { NavContext } from './ssr-
|
|
30
|
+
import type { NavContext } from './ssr-bridge-types.js';
|
|
31
31
|
import { flightInitScript } from './flight-scripts.js';
|
|
32
32
|
import type { ClientBootstrapConfig } from './html-injectors.js';
|
|
33
33
|
import type { Metadata } from './types.js';
|
|
@@ -166,7 +166,7 @@ export async function renderDenyPage(
|
|
|
166
166
|
|
|
167
167
|
const navContext: NavContext = {
|
|
168
168
|
pathname: new URL(req.url).pathname,
|
|
169
|
-
|
|
169
|
+
segmentParams: match.segmentParams,
|
|
170
170
|
searchParams: Object.fromEntries(new URL(req.url).searchParams),
|
|
171
171
|
statusCode: deny.status,
|
|
172
172
|
responseHeaders,
|
|
@@ -21,10 +21,10 @@ import type { ManifestSegmentNode } from '../route-matcher.js';
|
|
|
21
21
|
import { DenySignal, RenderError } from '../primitives.js';
|
|
22
22
|
import type { ClientBootstrapConfig } from '../html-injectors.js';
|
|
23
23
|
import { flightInitScript } from '../flight-scripts.js';
|
|
24
|
-
import { renderDenyPage } from '../deny-renderer.js';
|
|
24
|
+
import { renderDenyPage, renderDenyPageAsRsc } from '../deny-renderer.js';
|
|
25
25
|
import type { LayoutEntry } from '../deny-renderer.js';
|
|
26
|
-
import type { NavContext } from '../ssr-
|
|
27
|
-
import { createDebugChannelSink } from './helpers.js';
|
|
26
|
+
import type { NavContext } from '../ssr-bridge-types.js';
|
|
27
|
+
import { createDebugChannelSink, isRscPayloadRequest } from './helpers.js';
|
|
28
28
|
import { getCookiesForSsr } from '../cookie-context.js';
|
|
29
29
|
import { callSsr } from './ssr-bridge.js';
|
|
30
30
|
import { teeWithErrorPropagation } from '../stream-utils.js';
|
|
@@ -288,7 +288,7 @@ async function renderErrorPageViaRsc(
|
|
|
288
288
|
|
|
289
289
|
const navContext: NavContext = {
|
|
290
290
|
pathname: url.pathname,
|
|
291
|
-
|
|
291
|
+
segmentParams: match.segmentParams,
|
|
292
292
|
searchParams: Object.fromEntries(url.searchParams),
|
|
293
293
|
statusCode: status,
|
|
294
294
|
responseHeaders,
|
|
@@ -379,6 +379,16 @@ export async function renderNoMatchPage(
|
|
|
379
379
|
const deny = new DenySignal(404);
|
|
380
380
|
const match: RouteMatch = { segments, segmentParams: {}, middlewareChain: [] };
|
|
381
381
|
|
|
382
|
+
if (isRscPayloadRequest(req)) {
|
|
383
|
+
return renderDenyPageAsRsc(
|
|
384
|
+
deny,
|
|
385
|
+
segments,
|
|
386
|
+
layoutComponents,
|
|
387
|
+
responseHeaders,
|
|
388
|
+
createDebugChannelSink
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
|
|
382
392
|
return renderDenyPage(
|
|
383
393
|
deny,
|
|
384
394
|
segments,
|
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SSR Bridge — loads the SSR entry and passes the RSC stream for HTML rendering.
|
|
3
|
+
*
|
|
4
|
+
* This is the RSC → SSR environment hop. The two environments are separate
|
|
5
|
+
* Vite module graphs; `NavContext` is the serializable contract that crosses
|
|
6
|
+
* the boundary. See `../ssr-bridge-types.ts` for the contract definition.
|
|
3
7
|
*/
|
|
4
8
|
|
|
5
9
|
/// <reference types="@vitejs/plugin-rsc/types" />
|
|
6
10
|
|
|
7
|
-
import type { NavContext } from '../ssr-
|
|
11
|
+
import type { NavContext } from '../ssr-bridge-types.js';
|
|
8
12
|
|
|
9
13
|
export async function callSsr(
|
|
10
14
|
rscStream: ReadableStream<Uint8Array>,
|
|
@@ -20,7 +20,7 @@ import type { RouteMatch } from '../pipeline.js';
|
|
|
20
20
|
import { SsrStreamError } from '../primitives.js';
|
|
21
21
|
import type { LayoutComponentEntry } from '../route-element-builder.js';
|
|
22
22
|
import type { ManifestSegmentNode } from '../route-matcher.js';
|
|
23
|
-
import type { NavContext } from '../ssr-
|
|
23
|
+
import type { NavContext } from '../ssr-bridge-types.js';
|
|
24
24
|
|
|
25
25
|
import {
|
|
26
26
|
buildRedirectResponse,
|
|
@@ -149,7 +149,7 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
149
149
|
|
|
150
150
|
const navContext: NavContext = {
|
|
151
151
|
pathname: new URL(req.url).pathname,
|
|
152
|
-
|
|
152
|
+
segmentParams: match.segmentParams,
|
|
153
153
|
searchParams: Object.fromEntries(new URL(req.url).searchParams),
|
|
154
154
|
statusCode: 200,
|
|
155
155
|
responseHeaders,
|
|
@@ -235,33 +235,37 @@ export async function renderSsrResponse(opts: SsrRenderOptions): Promise<Respons
|
|
|
235
235
|
}
|
|
236
236
|
|
|
237
237
|
// Signal promotion: check if any signals were captured during rendering
|
|
238
|
-
// inside Suspense boundaries. If no signals are present yet,
|
|
239
|
-
//
|
|
240
|
-
// the full rejection chain to the RSC onError callback before
|
|
241
|
-
// commit the response.
|
|
238
|
+
// inside Suspense boundaries. If no signals are present yet, we may
|
|
239
|
+
// need to yield microtasks so async component rejections propagate
|
|
240
|
+
// through the full rejection chain to the RSC onError callback before
|
|
241
|
+
// we commit the response.
|
|
242
242
|
//
|
|
243
|
-
//
|
|
243
|
+
// Option 1 short-circuit: when Fizz's `stream.allReady` settled before
|
|
244
|
+
// the `deferSuspenseFor` hold ended (navContext._fizzAllReadyResolved),
|
|
245
|
+
// Flight has closed its stream, every `onError` already fired, and the
|
|
246
|
+
// signals object is fully populated. The retry loop would be a no-op.
|
|
247
|
+
// See design/spike-signal-promotion-protocol.md §"Option 1".
|
|
248
|
+
//
|
|
249
|
+
// Fallback path (hold timed out, no hold window, or shell-only return):
|
|
250
|
+
// the known rejection chain depth for a withSpan-wrapped page is 3+
|
|
251
|
+
// microtasks —
|
|
244
252
|
// 1. PageComponent throws DenySignal/RedirectSignal
|
|
245
253
|
// 2. withSpan catches and re-throws (microtask 1)
|
|
246
254
|
// 3. TracedPage promise rejects (microtask 2)
|
|
247
255
|
// 4. React Flight rejection handler → onError (microtask 3+)
|
|
248
|
-
//
|
|
249
|
-
//
|
|
250
|
-
//
|
|
251
|
-
//
|
|
252
|
-
// signal is detected. This tolerates future wrappers adding depth
|
|
253
|
-
// without requiring code changes.
|
|
254
|
-
//
|
|
255
|
-
// When signals are already captured (onSignal already fired), skip the
|
|
256
|
-
// yield entirely — react immediately. Uses queueMicrotask instead of
|
|
257
|
-
// setTimeout(0) to avoid yielding to the full event loop (timers phase).
|
|
256
|
+
// so a bounded retry loop (max 5) is required to catch signals whose
|
|
257
|
+
// propagation is still in-flight when callSsr returns. The loop exits
|
|
258
|
+
// early as soon as a signal is detected. Uses queueMicrotask instead
|
|
259
|
+
// of setTimeout(0) to avoid yielding to the full event loop.
|
|
258
260
|
// See design/05-streaming.md §"deferSuspenseFor and the Hold Window"
|
|
259
261
|
if (!signals.redirectSignal && !signals.denySignal && !signals.renderError) {
|
|
260
262
|
let yieldsConsumed = 0;
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
263
|
+
if (!navContext._fizzAllReadyResolved) {
|
|
264
|
+
for (let i = 0; i < SIGNAL_PROMOTION_MAX_YIELDS; i++) {
|
|
265
|
+
await new Promise<void>((r) => queueMicrotask(r));
|
|
266
|
+
yieldsConsumed++;
|
|
267
|
+
if (signals.redirectSignal || signals.denySignal || signals.renderError) break;
|
|
268
|
+
}
|
|
265
269
|
}
|
|
266
270
|
__test_only_signalPromotionDepth.value = yieldsConsumed;
|
|
267
271
|
}
|