@timber-js/app 0.2.0-alpha.127 → 0.2.0-alpha.129

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.
Files changed (48) hide show
  1. package/dist/_chunks/{actions-DX2gkoOZ.js → actions-CdzSSeTh.js} +2 -2
  2. package/dist/_chunks/{actions-DX2gkoOZ.js.map → actions-CdzSSeTh.js.map} +1 -1
  3. package/dist/_chunks/{cli-schema-sync-vdobDWwX.js → cli-schema-sync-CObqjGWF.js} +1 -1
  4. package/dist/_chunks/{cli-schema-sync-DFHBj6yZ.js → cli-schema-sync-q-Ce6-iG.js} +2 -2
  5. package/dist/_chunks/{cli-schema-sync-DFHBj6yZ.js.map → cli-schema-sync-q-Ce6-iG.js.map} +1 -1
  6. package/dist/_chunks/{logger-DDmK5skc.js → logger-CMd9P1xQ.js} +2 -2
  7. package/dist/_chunks/{logger-DDmK5skc.js.map → logger-CMd9P1xQ.js.map} +1 -1
  8. package/dist/_chunks/{tracing-DvKLzCFa.js → tracing-DP5djRq5.js} +43 -14
  9. package/dist/_chunks/tracing-DP5djRq5.js.map +1 -0
  10. package/dist/_chunks/{walkers-E5ss0qES.js → walkers-BbEu2_Pp.js} +2 -2
  11. package/dist/_chunks/{walkers-E5ss0qES.js.map → walkers-BbEu2_Pp.js.map} +1 -1
  12. package/dist/_chunks/{warnings-B30wpfaS.js → warnings-CAzunaGo.js} +2 -2
  13. package/dist/_chunks/{warnings-B30wpfaS.js.map → warnings-CAzunaGo.js.map} +1 -1
  14. package/dist/cache/index.js +2 -2
  15. package/dist/cli.js +1 -1
  16. package/dist/index.js +21 -7
  17. package/dist/index.js.map +1 -1
  18. package/dist/plugins/fonts.d.ts.map +1 -1
  19. package/dist/plugins/routing.d.ts.map +1 -1
  20. package/dist/routing/index.js +2 -2
  21. package/dist/server/als-registry.d.ts +17 -6
  22. package/dist/server/als-registry.d.ts.map +1 -1
  23. package/dist/server/deny-renderer.d.ts +1 -1
  24. package/dist/server/deny-renderer.d.ts.map +1 -1
  25. package/dist/server/index.js +2 -2
  26. package/dist/server/internal.js +4 -4
  27. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  28. package/dist/server/rsc-entry/ssr-bridge.d.ts +5 -1
  29. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  30. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  31. package/dist/server/ssr-bridge-types.d.ts +121 -0
  32. package/dist/server/ssr-bridge-types.d.ts.map +1 -0
  33. package/dist/server/ssr-entry.d.ts +1 -72
  34. package/dist/server/ssr-entry.d.ts.map +1 -1
  35. package/dist/server/ssr-render.d.ts +15 -0
  36. package/dist/server/ssr-render.d.ts.map +1 -1
  37. package/package.json +1 -1
  38. package/src/plugins/fonts.ts +9 -1
  39. package/src/plugins/routing.ts +15 -2
  40. package/src/server/als-registry.ts +53 -13
  41. package/src/server/deny-renderer.ts +2 -2
  42. package/src/server/rsc-entry/error-renderer.ts +14 -4
  43. package/src/server/rsc-entry/ssr-bridge.ts +5 -1
  44. package/src/server/rsc-entry/ssr-renderer.ts +25 -21
  45. package/src/server/ssr-bridge-types.ts +124 -0
  46. package/src/server/ssr-entry.ts +9 -77
  47. package/src/server/ssr-render.ts +40 -4
  48. package/dist/_chunks/tracing-DvKLzCFa.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,CA8KtD"}
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"}
@@ -1 +1 @@
1
- {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/plugins/routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAoBlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA2F1D,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAuNxD"}
1
+ {"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/plugins/routing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,MAAM,EAAiB,MAAM,MAAM,CAAC;AAoBlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAwG1D,wBAAgB,aAAa,CAAC,GAAG,EAAE,aAAa,GAAG,MAAM,CAuNxD"}
@@ -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
- 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-E5ss0qES.js";
2
+ import { m as scanRoutes } from "../_chunks/cli-schema-sync-q-Ce6-iG.js";
3
+ import { a as generateRouteMap, i as collectInterceptionRewrites, n as collectDynamicSegmentsFromTree, r as validateSchemaAgainstRoutes, t as collectLeafRoutes } from "../_chunks/walkers-BbEu2_Pp.js";
4
4
  export { DEFAULT_PAGE_EXTENSIONS, INTERCEPTION_MARKERS, classifySegment, classifyUrlSegment, collectDynamicSegmentsFromTree, collectInterceptionRewrites, collectLeafRoutes, generateRouteMap, scanRoutes, validateSchemaAgainstRoutes };
@@ -6,18 +6,29 @@
6
6
  * this registry and re-export public accessor functions.
7
7
  *
8
8
  * Why: ALS instances require singleton semantics — if two copies of the
9
- * same ALS exist (one from a relative import, one from a barrel import),
10
- * one module writes to its copy and another reads from an empty copy.
11
- * Centralizing ALS creation in a single module eliminates this class of bug.
9
+ * same ALS exist (one from a relative import, one from a barrel import,
10
+ * or the same file re-evaluated by Vite after an HMR invalidation), one
11
+ * module writes to its copy and another reads from an empty copy.
12
+ * Centralizing ALS creation in a single module + anchoring each instance
13
+ * on `globalThis` under a `Symbol.for(...)` key eliminates this class of
14
+ * bug, including the Vite-dev case where module instance split would
15
+ * otherwise hand two copies of this file out of a single evaluation cycle.
12
16
  *
13
- * The `timber-shims` plugin ensures `@timber-js/app/server` resolves to
14
- * src/ in RSC and SSR environments, so all import paths converge here.
17
+ * The `timber-shims` plugin remaps `@timber-js/app/server` to src/ in
18
+ * RSC and SSR environments so import-specifier paths converge here, and
19
+ * the `globalThis[SYMBOL_FOR]` anchor below closes the remaining gap: any
20
+ * second evaluation of this module picks up the ALS the first evaluation
21
+ * already stored rather than instantiating a fresh one. Same pattern the
22
+ * Cloudflare bindings ALS uses in `adapters/cloudflare.ts`.
15
23
  *
16
24
  * DO NOT create ALS instances outside this file. If you need a new ALS,
17
25
  * add it here and import from `./als-registry.js` in the consuming module.
26
+ * Inside this file, always route through `getOrCreateAls(symbol)` — a raw
27
+ * `new AsyncLocalStorage()` reintroduces the instance-split hazard.
18
28
  *
19
29
  * See design/18-build-system.md §"Module Singleton Strategy" and
20
- * §"Singleton State Registry".
30
+ * §"Singleton State Registry". Regression test:
31
+ * `tests/als-registry-singleton.test.ts`.
21
32
  */
22
33
  import { AsyncLocalStorage } from 'node:async_hooks';
23
34
  import type { DebugComponentEntry } from './rsc-entry/helpers.js';
@@ -1 +1 @@
1
- {"version":3,"file":"als-registry.d.ts","sourceRoot":"","sources":["../../src/server/als-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AAMlE,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,wCAA+C,CAAC;AAE9E,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,uEAAuE;IACvE,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,YAAY,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAClD;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/D,wFAAwF;IACxF,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,mBAAmB,EAAE,CAAC;CACrD;AAED,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,qBAAqB,EAAE,aAAa,CAAC;CACtD;AAMD,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mDAAmD;AACnD,eAAO,MAAM,QAAQ,+BAAsC,CAAC;AAM5D,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,oBAAoB,EAAE,WAAW,EAAE,CAAC;CACrD;AAED,yDAAyD;AACzD,eAAO,MAAM,SAAS,gCAAuC,CAAC;AAM9D,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,mDAAmD;AACnD,eAAO,MAAM,eAAe,sCAA6C,CAAC;AAM1E,sDAAsD;AACtD,eAAO,MAAM,YAAY,4DAAmE,CAAC;AAM7F,4EAA4E;AAC5E,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;AAE3D,8DAA8D;AAC9D,eAAO,MAAM,mBAAmB,uCAA8C,CAAC;AAM/E,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;AAE9D,4DAA4D;AAC5D,eAAO,MAAM,YAAY,gCAAuC,CAAC"}
1
+ {"version":3,"file":"als-registry.d.ts","sourceRoot":"","sources":["../../src/server/als-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AA2BlE,2DAA2D;AAC3D,eAAO,MAAM,iBAAiB,wCAE7B,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,uEAAuE;IACvE,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,YAAY,EAAE,eAAe,CAAC;IAC9B;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;;;;;;OAOG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAClD;;;;;;OAMG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;;;;;;;;;;OAUG;IACH,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/D,wFAAwF;IACxF,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,cAAc,EAAE,OAAO,CAAC;IACxB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,mBAAmB,EAAE,CAAC;CACrD;AAED,wDAAwD;AACxD,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,qBAAqB,EAAE,aAAa,CAAC;CACtD;AAMD,MAAM,WAAW,UAAU;IACzB,8DAA8D;IAC9D,OAAO,EAAE,MAAM,CAAC;IAChB,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,mDAAmD;AACnD,eAAO,MAAM,QAAQ,+BAA6D,CAAC;AAMnF,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,oBAAoB,EAAE,WAAW,EAAE,CAAC;CACrD;AAED,yDAAyD;AACzD,eAAO,MAAM,SAAS,gCAA+D,CAAC;AAMtF,MAAM,WAAW,iBAAiB;IAChC,8DAA8D;IAC9D,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,6DAA6D;IAC7D,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,mDAAmD;AACnD,eAAO,MAAM,eAAe,sCAE3B,CAAC;AAMF,sDAAsD;AACtD,eAAO,MAAM,YAAY,4DAExB,CAAC;AAMF,4EAA4E;AAC5E,MAAM,MAAM,kBAAkB,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;AAE3D,8DAA8D;AAC9D,eAAO,MAAM,mBAAmB,uCAE/B,CAAC;AAMF,6EAA6E;AAC7E,MAAM,MAAM,WAAW,GAAG,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;AAE9D,4DAA4D;AAC5D,eAAO,MAAM,YAAY,gCAAmE,CAAC"}
@@ -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-entry.js';
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,gBAAgB,CAAC;AAEjD,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
+ {"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,6 +1,6 @@
1
- import { a as getSpanId, d as withSpan, o as getTraceId, p as formFlashAls, t as addSpanEvent, v as isDebug, y as isDevMode } from "../_chunks/tracing-DvKLzCFa.js";
1
+ import { a as getSpanId, d as withSpan, o as getTraceId, p as formFlashAls, t as addSpanEvent, v as isDebug, y as isDevMode } from "../_chunks/tracing-DP5djRq5.js";
2
2
  import { t as formatSize } from "../_chunks/format-BjN9HLu9.js";
3
- import { D as getCookieJar, a as revalidateTag, b as getSegmentParams, c as DenySignal, f as deny, h as waitUntil, i as revalidatePath, l as RedirectSignal, m as redirectExternal, o as coerce, p as redirect, s as parseFormData, u as RedirectType, v as getHeaders } from "../_chunks/actions-DX2gkoOZ.js";
3
+ import { D as getCookieJar, a as revalidateTag, b as getSegmentParams, c as DenySignal, f as deny, h as waitUntil, i as revalidatePath, l as RedirectSignal, m as redirectExternal, o as coerce, p as redirect, s as parseFormData, u as RedirectType, v as getHeaders } from "../_chunks/actions-CdzSSeTh.js";
4
4
  //#region src/server/sensitive-fields.ts
5
5
  /**
6
6
  * Sensitive field stripping — removes password/token/CVV-style fields
@@ -1,9 +1,9 @@
1
- import { c as replaceTraceId, d as withSpan, f as earlyHintsSenderAls, g as timingAls, i as getOtelTraceId, l as runWithTraceId, m as requestContextAls, o as getTraceId, r as generateTraceId, u as setSpanAttribute, v as isDebug } from "../_chunks/tracing-DvKLzCFa.js";
2
- import { a as warnRedirectInSuspense, c as warnSuspenseWrappingChildren, i as warnRedirectInAccess, n as setViteServer, o as warnSlowSlotWithoutSuspense, r as warnDenyInSuspense, s as warnStaticRequestApi, t as WarningId } from "../_chunks/warnings-B30wpfaS.js";
1
+ import { c as replaceTraceId, d as withSpan, f as earlyHintsSenderAls, g as timingAls, i as getOtelTraceId, l as runWithTraceId, m as requestContextAls, o as getTraceId, r as generateTraceId, u as setSpanAttribute, v as isDebug } from "../_chunks/tracing-DP5djRq5.js";
2
+ import { a as warnRedirectInSuspense, c as warnSuspenseWrappingChildren, i as warnRedirectInAccess, n as setViteServer, o as warnSlowSlotWithoutSuspense, r as warnDenyInSuspense, s as warnStaticRequestApi, t as WarningId } from "../_chunks/warnings-CAzunaGo.js";
3
3
  import { i as getMetadataRouteServePath, n as classifyMetadataRoute, r as getMetadataRouteAutoLink, t as METADATA_ROUTE_CONVENTIONS } from "../_chunks/metadata-routes-DESG8uk5.js";
4
4
  import { n as classifyUrlSegment } from "../_chunks/segment-classify-BjfuctV2.js";
5
- import { a as logProxyError, c as logRequestReceived, d as logSwrRefetchFailed, f as logWaitUntilRejected, h as swallow, i as logMiddlewareShortCircuit, l as logRouteError, m as setLogger, n as logCacheMiss, o as logRenderError, p as logWaitUntilUnsupported, r as logMiddlewareError, s as logRequestCompleted, t as getLogger, u as logSlowRequest } from "../_chunks/logger-DDmK5skc.js";
6
- import { C as setMatchedSegmentPath, E as getCookie, O as getSetCookieHeaders, S as runWithRequestContext, T as setSegmentParams, _ as getHeader, b as getSegmentParams, c as DenySignal, d as RenderError, g as applyRequestHeaderOverlay, l as RedirectSignal, n as executeAction, o as coerce, r as isRscActionRequest, t as buildNoJsResponse, w as setMutableCookieContext, x as markResponseFlushed, y as getSearchParams } from "../_chunks/actions-DX2gkoOZ.js";
5
+ import { a as logProxyError, c as logRequestReceived, d as logSwrRefetchFailed, f as logWaitUntilRejected, h as swallow, i as logMiddlewareShortCircuit, l as logRouteError, m as setLogger, n as logCacheMiss, o as logRenderError, p as logWaitUntilUnsupported, r as logMiddlewareError, s as logRequestCompleted, t as getLogger, u as logSlowRequest } from "../_chunks/logger-CMd9P1xQ.js";
6
+ import { C as setMatchedSegmentPath, E as getCookie, O as getSetCookieHeaders, S as runWithRequestContext, T as setSegmentParams, _ as getHeader, b as getSegmentParams, c as DenySignal, d as RenderError, g as applyRequestHeaderOverlay, l as RedirectSignal, n as executeAction, o as coerce, r as isRscActionRequest, t as buildNoJsResponse, w as setMutableCookieContext, x as markResponseFlushed, y as getSearchParams } from "../_chunks/actions-CdzSSeTh.js";
7
7
  import "../client/error-boundary.js";
8
8
  import { n as toBracketKey } from "../_chunks/resolve-schema-DU2nbVOi.js";
9
9
  import "../_chunks/segment-context-Bg0pFbLT.js";
@@ -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,CA6BnB"}
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-entry.js';
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;;GAEG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAElD,wBAAsB,OAAO,CAC3B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,QAAQ,CAAC,CAenB"}
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,CAiSjF"}
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;AAiF/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"}
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;CAC1B,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;CAC1B,GACA,OAAO,CAAC,OAAO,aAAa,EAAE,QAAQ,CAAC,CAyFzC;AAED,6EAA6E;AAC7E,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,OAAO,aAAa,EAAE,QAAQ,GACvC,cAAc,CAAC,UAAU,CAAC,CAE5B;AAuFD;;;;;;;;;;;;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"}
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.127",
3
+ "version": "0.2.0-alpha.129",
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",
@@ -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
- if (pipeline.cssIdMap.matches(cleanId)) return '\0' + cleanId;
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
 
@@ -84,12 +84,25 @@ const CODEGEN_OUTPUT = '.timber/timber-routes.d.ts';
84
84
  * Uses a triple-slash reference so TypeScript auto-discovers the generated
85
85
  * route map without the user needing to edit tsconfig.json — same pattern
86
86
  * as Next.js's next-env.d.ts.
87
+ *
88
+ * Also references `vite/client` so side-effect imports like
89
+ * `import './globals.css'` type-check without ts(2882), and so
90
+ * `import.meta.env`, `import.meta.hot`, `import.meta.glob`, asset
91
+ * imports (`*.png`, `*.svg`, …), CSS modules, and `?url`/`?raw`/
92
+ * `?inline` query variants all resolve without the user editing
93
+ * tsconfig.json themselves. Next.js's next-env.d.ts plays the same
94
+ * role via `next/types/global`.
95
+ *
96
+ * `vite` is a peer dep of `@timber-js/app`, so the reference always
97
+ * resolves in a correctly-installed project.
87
98
  */
88
99
  const TIMBER_ENV_DTS = [
89
100
  '// This file is auto-generated by timber.js. Do not edit.',
90
- '// It ensures TypeScript picks up the generated route types.',
91
- '// eslint-disable-next-line @typescript-eslint/triple-slash-reference',
101
+ '// It ensures TypeScript picks up the generated route types and',
102
+ '// Vite-provided ambient types (CSS, assets, import.meta.env, HMR).',
103
+ '/* eslint-disable @typescript-eslint/triple-slash-reference */',
92
104
  '/// <reference path=".timber/timber-routes.d.ts" />',
105
+ '/// <reference types="vite/client" />',
93
106
  '',
94
107
  ].join('\n');
95
108
 
@@ -6,29 +6,63 @@
6
6
  * this registry and re-export public accessor functions.
7
7
  *
8
8
  * Why: ALS instances require singleton semantics — if two copies of the
9
- * same ALS exist (one from a relative import, one from a barrel import),
10
- * one module writes to its copy and another reads from an empty copy.
11
- * Centralizing ALS creation in a single module eliminates this class of bug.
9
+ * same ALS exist (one from a relative import, one from a barrel import,
10
+ * or the same file re-evaluated by Vite after an HMR invalidation), one
11
+ * module writes to its copy and another reads from an empty copy.
12
+ * Centralizing ALS creation in a single module + anchoring each instance
13
+ * on `globalThis` under a `Symbol.for(...)` key eliminates this class of
14
+ * bug, including the Vite-dev case where module instance split would
15
+ * otherwise hand two copies of this file out of a single evaluation cycle.
12
16
  *
13
- * The `timber-shims` plugin ensures `@timber-js/app/server` resolves to
14
- * src/ in RSC and SSR environments, so all import paths converge here.
17
+ * The `timber-shims` plugin remaps `@timber-js/app/server` to src/ in
18
+ * RSC and SSR environments so import-specifier paths converge here, and
19
+ * the `globalThis[SYMBOL_FOR]` anchor below closes the remaining gap: any
20
+ * second evaluation of this module picks up the ALS the first evaluation
21
+ * already stored rather than instantiating a fresh one. Same pattern the
22
+ * Cloudflare bindings ALS uses in `adapters/cloudflare.ts`.
15
23
  *
16
24
  * DO NOT create ALS instances outside this file. If you need a new ALS,
17
25
  * add it here and import from `./als-registry.js` in the consuming module.
26
+ * Inside this file, always route through `getOrCreateAls(symbol)` — a raw
27
+ * `new AsyncLocalStorage()` reintroduces the instance-split hazard.
18
28
  *
19
29
  * See design/18-build-system.md §"Module Singleton Strategy" and
20
- * §"Singleton State Registry".
30
+ * §"Singleton State Registry". Regression test:
31
+ * `tests/als-registry-singleton.test.ts`.
21
32
  */
22
33
 
23
34
  import { AsyncLocalStorage } from 'node:async_hooks';
24
35
  import type { DebugComponentEntry } from './rsc-entry/helpers.js';
25
36
 
37
+ /**
38
+ * Return a process-wide singleton `AsyncLocalStorage` keyed by `symbol`.
39
+ *
40
+ * `Symbol.for(...)` keys live in the cross-realm symbol registry, and
41
+ * `globalThis` is shared across every module evaluation inside the same
42
+ * Node.js process. Together they give a stable anchor that survives
43
+ * re-evaluation of this file — the second evaluation observes the
44
+ * `globalThis[symbol]` slot already populated by the first and hands
45
+ * back the identical ALS instance.
46
+ */
47
+ function getOrCreateAls<T>(symbol: symbol): AsyncLocalStorage<T> {
48
+ const g = globalThis as unknown as Record<symbol, unknown>;
49
+ const existing = g[symbol];
50
+ if (existing instanceof AsyncLocalStorage) {
51
+ return existing as AsyncLocalStorage<T>;
52
+ }
53
+ const created = new AsyncLocalStorage<T>();
54
+ g[symbol] = created;
55
+ return created;
56
+ }
57
+
26
58
  // ─── Request Context ──────────────────────────────────────────────────────
27
59
  // Used by: request-context.ts (getHeaders(), getCookies(), getSearchParams())
28
60
  // Design doc: design/04-authorization.md
29
61
 
30
62
  /** @internal — import via request-context.ts public API */
31
- export const requestContextAls = new AsyncLocalStorage<RequestContextStore>();
63
+ export const requestContextAls = getOrCreateAls<RequestContextStore>(
64
+ Symbol.for('timber:request-context-als')
65
+ );
32
66
 
33
67
  export interface RequestContextStore {
34
68
  /** Incoming request headers (read-only view). */
@@ -119,7 +153,7 @@ export interface TraceStore {
119
153
  }
120
154
 
121
155
  /** @internal — import via tracing.ts public API */
122
- export const traceAls = new AsyncLocalStorage<TraceStore>();
156
+ export const traceAls = getOrCreateAls<TraceStore>(Symbol.for('timber:trace-als'));
123
157
 
124
158
  // ─── Server-Timing ────────────────────────────────────────────────────────
125
159
  // Used by: server-timing.ts (recordTiming(), withTiming())
@@ -130,7 +164,7 @@ export interface TimingStore {
130
164
  }
131
165
 
132
166
  /** @internal — import via server-timing.ts public API */
133
- export const timingAls = new AsyncLocalStorage<TimingStore>();
167
+ export const timingAls = getOrCreateAls<TimingStore>(Symbol.for('timber:timing-als'));
134
168
 
135
169
  // ─── Revalidation ─────────────────────────────────────────────────────────
136
170
  // Used by: actions.ts (revalidatePath(), revalidateTag())
@@ -144,14 +178,18 @@ export interface RevalidationState {
144
178
  }
145
179
 
146
180
  /** @internal — import via actions.ts public API */
147
- export const revalidationAls = new AsyncLocalStorage<RevalidationState>();
181
+ export const revalidationAls = getOrCreateAls<RevalidationState>(
182
+ Symbol.for('timber:revalidation-als')
183
+ );
148
184
 
149
185
  // ─── Form Flash ───────────────────────────────────────────────────────────
150
186
  // Used by: form-flash.ts (getFormFlash())
151
187
  // Design doc: design/08-forms-and-actions.md §"No-JS Error Round-Trip"
152
188
 
153
189
  /** @internal — import via form-flash.ts public API */
154
- export const formFlashAls = new AsyncLocalStorage<import('./form-flash.js').FormFlashData>();
190
+ export const formFlashAls = getOrCreateAls<import('./form-flash.js').FormFlashData>(
191
+ Symbol.for('timber:form-flash-als')
192
+ );
155
193
 
156
194
  // ─── Early Hints Sender ──────────────────────────────────────────────────
157
195
  // Used by: early-hints-sender.ts (sendEarlyHints103())
@@ -161,7 +199,9 @@ export const formFlashAls = new AsyncLocalStorage<import('./form-flash.js').Form
161
199
  export type EarlyHintsSenderFn = (links: string[]) => void;
162
200
 
163
201
  /** @internal — import via early-hints-sender.ts public API */
164
- export const earlyHintsSenderAls = new AsyncLocalStorage<EarlyHintsSenderFn>();
202
+ export const earlyHintsSenderAls = getOrCreateAls<EarlyHintsSenderFn>(
203
+ Symbol.for('timber:early-hints-sender-als')
204
+ );
165
205
 
166
206
  // ─── waitUntil Bridge ────────────────────────────────────────────────────
167
207
  // Used by: waituntil-bridge.ts (waitUntil())
@@ -171,4 +211,4 @@ export const earlyHintsSenderAls = new AsyncLocalStorage<EarlyHintsSenderFn>();
171
211
  export type WaitUntilFn = (promise: Promise<unknown>) => void;
172
212
 
173
213
  /** @internal — import via waituntil-bridge.ts public API */
174
- export const waitUntilAls = new AsyncLocalStorage<WaitUntilFn>();
214
+ export const waitUntilAls = getOrCreateAls<WaitUntilFn>(Symbol.for('timber:wait-until-als'));
@@ -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-entry.js';
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
- params: match.segmentParams,
169
+ segmentParams: match.segmentParams,
170
170
  searchParams: Object.fromEntries(new URL(req.url).searchParams),
171
171
  statusCode: deny.status,
172
172
  responseHeaders,