@timber-js/app 0.2.0-alpha.110 → 0.2.0-alpha.112

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 (156) hide show
  1. package/dist/_chunks/{actions-D6gyxlGQ.js → actions-ILhDUzES.js} +46 -10
  2. package/dist/_chunks/actions-ILhDUzES.js.map +1 -0
  3. package/dist/_chunks/{build-output-helper-5TK2Emwp.js → build-output-helper-DhxiT18k.js} +1 -1
  4. package/dist/_chunks/{build-output-helper-5TK2Emwp.js.map → build-output-helper-DhxiT18k.js.map} +1 -1
  5. package/dist/_chunks/cli-schema-sync-BhXdbmgS.js +2 -0
  6. package/dist/_chunks/cli-schema-sync-DFZmnmqG.js +357 -0
  7. package/dist/_chunks/cli-schema-sync-DFZmnmqG.js.map +1 -0
  8. package/dist/_chunks/codec-registry-V7ARyeLN.js +21 -0
  9. package/dist/_chunks/codec-registry-V7ARyeLN.js.map +1 -0
  10. package/dist/_chunks/{define-Dn98bPbb.js → define-8zQ8Vm7x.js} +3 -3
  11. package/dist/_chunks/{define-Dn98bPbb.js.map → define-8zQ8Vm7x.js.map} +1 -1
  12. package/dist/_chunks/{define-BflNsrwD.js → define-a0CCE6Nx.js} +3 -3
  13. package/dist/_chunks/{define-BflNsrwD.js.map → define-a0CCE6Nx.js.map} +1 -1
  14. package/dist/_chunks/{format-CYBGxKtc.js → format-CR6v1pWE.js} +1 -1
  15. package/dist/_chunks/{format-CYBGxKtc.js.map → format-CR6v1pWE.js.map} +1 -1
  16. package/dist/_chunks/{handler-store-B_df5Npe.js → handler-store-iqnt2ghN.js} +1 -1
  17. package/dist/_chunks/{handler-store-B_df5Npe.js.map → handler-store-iqnt2ghN.js.map} +1 -1
  18. package/dist/_chunks/{merge-search-params-Cm_KIWDX.js → merge-search-params-CwxJzBLS.js} +1 -1
  19. package/dist/_chunks/{merge-search-params-Cm_KIWDX.js.map → merge-search-params-CwxJzBLS.js.map} +1 -1
  20. package/dist/_chunks/{navigation-root-2ypaZQDx.js → navigation-root-CY3pRMxF.js} +2 -2
  21. package/dist/_chunks/{navigation-root-2ypaZQDx.js.map → navigation-root-CY3pRMxF.js.map} +1 -1
  22. package/dist/_chunks/{registry-DB93kT5c.js → registry-Dp_hJL4s.js} +1 -1
  23. package/dist/_chunks/{registry-DB93kT5c.js.map → registry-Dp_hJL4s.js.map} +1 -1
  24. package/dist/_chunks/resolve-schema-DO8B0mO9.js +65 -0
  25. package/dist/_chunks/resolve-schema-DO8B0mO9.js.map +1 -0
  26. package/dist/_chunks/{router-ref-TkUdmqtM.js → router-ref-sektkr-t.js} +2 -2
  27. package/dist/_chunks/{router-ref-TkUdmqtM.js.map → router-ref-sektkr-t.js.map} +1 -1
  28. package/dist/_chunks/scanner-DmfoB7iK.js +336 -0
  29. package/dist/_chunks/scanner-DmfoB7iK.js.map +1 -0
  30. package/dist/_chunks/{schema-bridge-C3xl_vfb.js → schema-bridge-eL5vQDSA.js} +1 -1
  31. package/dist/_chunks/{schema-bridge-C3xl_vfb.js.map → schema-bridge-eL5vQDSA.js.map} +1 -1
  32. package/dist/_chunks/{segment-context-Dc-GbSTe.js → segment-context-EsfQpS--.js} +1 -1
  33. package/dist/_chunks/{segment-context-Dc-GbSTe.js.map → segment-context-EsfQpS--.js.map} +1 -1
  34. package/dist/_chunks/{ssr-data-DzuI0bIV.js → ssr-data-BO5OvEvg.js} +1 -1
  35. package/dist/_chunks/{ssr-data-DzuI0bIV.js.map → ssr-data-BO5OvEvg.js.map} +1 -1
  36. package/dist/_chunks/{stale-reload-D6FlD3xn.js → stale-reload-BCPRG0Cv.js} +1 -1
  37. package/dist/_chunks/{stale-reload-D6FlD3xn.js.map → stale-reload-BCPRG0Cv.js.map} +1 -1
  38. package/dist/_chunks/tracing-DvKLzCFa.js.map +1 -1
  39. package/dist/_chunks/{use-query-states-B-cLl8mx.js → use-query-states-D9SBlAfp.js} +2 -2
  40. package/dist/_chunks/{use-query-states-B-cLl8mx.js.map → use-query-states-D9SBlAfp.js.map} +1 -1
  41. package/dist/_chunks/{use-segment-params-07V1TIxL.js → use-segment-params-BSt_O2cb.js} +2 -2
  42. package/dist/_chunks/{use-segment-params-07V1TIxL.js.map → use-segment-params-BSt_O2cb.js.map} +1 -1
  43. package/dist/_chunks/{validation-DfyuMoK2.js → validation-Bm3Je-09.js} +1 -1
  44. package/dist/_chunks/{validation-DfyuMoK2.js.map → validation-Bm3Je-09.js.map} +1 -1
  45. package/dist/_chunks/{walkers-DQn5NNrf.js → walkers-DGTmJT0f.js} +109 -353
  46. package/dist/_chunks/walkers-DGTmJT0f.js.map +1 -0
  47. package/dist/adapters/cloudflare.js +1 -1
  48. package/dist/adapters/nitro.js +1 -1
  49. package/dist/cache/index.js +3 -2
  50. package/dist/cache/index.js.map +1 -1
  51. package/dist/cache/sizeof.d.ts.map +1 -1
  52. package/dist/cli-schema-sync.d.ts +37 -0
  53. package/dist/cli-schema-sync.d.ts.map +1 -0
  54. package/dist/cli.d.ts +8 -1
  55. package/dist/cli.d.ts.map +1 -1
  56. package/dist/cli.js +34 -3
  57. package/dist/cli.js.map +1 -1
  58. package/dist/client/browser-entry/action-dispatch.d.ts.map +1 -1
  59. package/dist/client/error-boundary.js +5 -3
  60. package/dist/client/error-boundary.js.map +1 -1
  61. package/dist/client/index.js +27 -9
  62. package/dist/client/index.js.map +1 -1
  63. package/dist/client/internal.js +7 -7
  64. package/dist/client/link.d.ts.map +1 -1
  65. package/dist/codec.js +1 -1
  66. package/dist/cookies/index.js +3 -3
  67. package/dist/dev-tools/browser-logs.d.ts.map +1 -1
  68. package/dist/dev-tools/error-page.d.ts.map +1 -1
  69. package/dist/dev-tools/logs.d.ts.map +1 -1
  70. package/dist/dev-tools/overlay.d.ts +1 -1
  71. package/dist/dev-tools/overlay.d.ts.map +1 -1
  72. package/dist/index.d.ts +1 -0
  73. package/dist/index.d.ts.map +1 -1
  74. package/dist/index.js +98 -236
  75. package/dist/index.js.map +1 -1
  76. package/dist/params/codec-registry.d.ts +26 -0
  77. package/dist/params/codec-registry.d.ts.map +1 -0
  78. package/dist/params/define-schema.d.ts +52 -0
  79. package/dist/params/define-schema.d.ts.map +1 -0
  80. package/dist/params/index.d.ts +5 -0
  81. package/dist/params/index.d.ts.map +1 -0
  82. package/dist/params/index.js +33 -0
  83. package/dist/params/index.js.map +1 -0
  84. package/dist/params/resolve-schema.d.ts +34 -0
  85. package/dist/params/resolve-schema.d.ts.map +1 -0
  86. package/dist/plugins/mdx.d.ts.map +1 -1
  87. package/dist/plugins/routing.d.ts.map +1 -1
  88. package/dist/routing/codegen-shared.d.ts +8 -0
  89. package/dist/routing/codegen-shared.d.ts.map +1 -1
  90. package/dist/routing/codegen-types.d.ts +5 -0
  91. package/dist/routing/codegen-types.d.ts.map +1 -1
  92. package/dist/routing/codegen.d.ts +5 -0
  93. package/dist/routing/codegen.d.ts.map +1 -1
  94. package/dist/routing/index.js +2 -1
  95. package/dist/routing/link-codegen.d.ts +2 -2
  96. package/dist/routing/link-codegen.d.ts.map +1 -1
  97. package/dist/search-params/index.js +3 -3
  98. package/dist/segment-params/index.js +1 -1
  99. package/dist/server/als-registry.d.ts +7 -0
  100. package/dist/server/als-registry.d.ts.map +1 -1
  101. package/dist/server/coalesce-tick.d.ts +40 -0
  102. package/dist/server/coalesce-tick.d.ts.map +1 -0
  103. package/dist/server/fallback-error.d.ts.map +1 -1
  104. package/dist/server/html-injectors.d.ts.map +1 -1
  105. package/dist/server/index.js +2 -2
  106. package/dist/server/internal.js +30 -4
  107. package/dist/server/internal.js.map +1 -1
  108. package/dist/server/node-stream-transforms.d.ts.map +1 -1
  109. package/dist/server/param-coercion.d.ts +12 -2
  110. package/dist/server/param-coercion.d.ts.map +1 -1
  111. package/dist/server/pipeline-phases.d.ts.map +1 -1
  112. package/dist/server/pipeline.d.ts +18 -0
  113. package/dist/server/pipeline.d.ts.map +1 -1
  114. package/dist/server/request-context.d.ts +17 -3
  115. package/dist/server/request-context.d.ts.map +1 -1
  116. package/dist/server/rsc-entry/helpers.d.ts.map +1 -1
  117. package/dist/server/rsc-entry/index.d.ts +8 -14
  118. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  119. package/package.json +11 -6
  120. package/src/cache/sizeof.ts +3 -1
  121. package/src/cli-schema-sync.ts +206 -0
  122. package/src/cli.ts +49 -2
  123. package/src/client/browser-entry/action-dispatch.ts +15 -5
  124. package/src/client/browser-entry/index.ts +6 -0
  125. package/src/client/error-boundary.tsx +2 -2
  126. package/src/client/link.tsx +25 -1
  127. package/src/dev-tools/browser-logs.ts +5 -2
  128. package/src/dev-tools/error-page.ts +3 -6
  129. package/src/dev-tools/logs.ts +6 -2
  130. package/src/dev-tools/overlay.ts +18 -5
  131. package/src/index.ts +5 -0
  132. package/src/params/codec-registry.ts +34 -0
  133. package/src/params/define-schema.ts +72 -0
  134. package/src/params/index.ts +11 -0
  135. package/src/params/resolve-schema.ts +88 -0
  136. package/src/plugins/dev-server.ts +24 -16
  137. package/src/plugins/mdx.ts +5 -1
  138. package/src/plugins/routing.ts +107 -2
  139. package/src/routing/codegen-shared.ts +11 -0
  140. package/src/routing/codegen-types.ts +5 -0
  141. package/src/routing/codegen.ts +129 -21
  142. package/src/routing/link-codegen.ts +19 -5
  143. package/src/server/als-registry.ts +7 -0
  144. package/src/server/coalesce-tick.ts +75 -0
  145. package/src/server/fallback-error.ts +3 -3
  146. package/src/server/html-injectors.ts +11 -22
  147. package/src/server/node-stream-transforms.ts +6 -16
  148. package/src/server/param-coercion.ts +55 -2
  149. package/src/server/pipeline-phases.ts +8 -0
  150. package/src/server/pipeline.ts +19 -0
  151. package/src/server/request-context.ts +58 -3
  152. package/src/server/rsc-entry/helpers.ts +3 -2
  153. package/src/server/rsc-entry/index.ts +28 -35
  154. package/LICENSE +0 -8
  155. package/dist/_chunks/actions-D6gyxlGQ.js.map +0 -1
  156. package/dist/_chunks/walkers-DQn5NNrf.js.map +0 -1
@@ -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;AAKjC,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,CAsCjG;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;CAC1B;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"}
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;CAC1B;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"}
@@ -11,16 +11,26 @@
11
11
  * on any codec failure; the pipeline catches that and dispatches to the
12
12
  * 404 page. See design/07-routing.md §"Where Coercion Runs".
13
13
  */
14
+ import type { Codec } from '../codec.js';
14
15
  import type { RouteMatch } from './pipeline.js';
16
+ /**
17
+ * Register the global schema codecs. Called once from the RSC entry
18
+ * at server startup when app/schema.ts provides segment param codecs.
19
+ * @internal
20
+ */
21
+ export declare function setGlobalSchemaCodecs(codecs: Record<string, Codec<unknown>> | null): void;
15
22
  /**
16
23
  * Run segment param coercion on the matched route's segments.
17
24
  *
18
- * Loads params.ts modules from segments that have them, extracts the
19
- * segmentParams definition, and coerces raw string params through codecs.
25
+ * When `globalCodecs` is provided (from app/schema.ts), uses the global
26
+ * codec map keyed by bare param name. Otherwise falls back to loading
27
+ * per-segment params.ts modules.
28
+ *
20
29
  * Throws ParamCoercionError if any codec fails (→ 404).
21
30
  *
22
31
  * This runs BEFORE middleware, so ctx.segmentParams is already typed.
23
32
  * See design/07-routing.md §"Where Coercion Runs"
33
+ * See design/41-global-params.md §"Pipeline Integration"
24
34
  */
25
35
  export declare function coerceSegmentParams(match: RouteMatch): Promise<void>;
26
36
  //# sourceMappingURL=param-coercion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"param-coercion.d.ts","sourceRoot":"","sources":["../../src/server/param-coercion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAMhD;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgE1E"}
1
+ {"version":3,"file":"param-coercion.d.ts","sourceRoot":"","sources":["../../src/server/param-coercion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAahD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAEzF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgG1E"}
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAmBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAID;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAavB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,QAAQ,CAAC,CAmPnB"}
1
+ {"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAID;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAavB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,QAAQ,CAAC,CA0PnB"}
@@ -125,6 +125,24 @@ export interface PipelineConfig {
125
125
  * Undefined in production — zero overhead.
126
126
  */
127
127
  onPipelineError?: (error: Error, phase: string) => void;
128
+ /**
129
+ * Dev error handler with RSC debug context — set by the dev server after
130
+ * the RSC entry module is imported. `onPipelineError` resolves debug
131
+ * components from ALS and delegates to this handler.
132
+ *
133
+ * This is a mutable property (not a constructor argument) because the dev
134
+ * server imports the RSC entry module first (which constructs the config),
135
+ * then wires in the overlay handler. Moving the state here (from a
136
+ * module-level `let`) keeps it co-located with the config it belongs to
137
+ * and makes it visible in tests without module-level mutation.
138
+ *
139
+ * Undefined in production — zero overhead.
140
+ */
141
+ devPipelineErrorHandler?: (error: Error, phase: string, debugComponents?: Array<{
142
+ name: string;
143
+ env: string | null;
144
+ stack: unknown[] | null;
145
+ }>) => void;
128
146
  /**
129
147
  * Fallback error renderer — called when a catastrophic error escapes the
130
148
  * render phase. Produces an HTML Response instead of a bare empty 500.
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"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"}
@@ -40,16 +40,30 @@ export declare function getSearchParams(): URLSearchParams;
40
40
  /**
41
41
  * Returns the current request's coerced segment params.
42
42
  *
43
- * @internal — not part of the public API. Use `defineSegmentParams().get()` instead.
43
+ * The optional `_route` argument exists only for TypeScript narrowing —
44
+ * it does not affect the runtime return value. Pass a route pattern
45
+ * (e.g. `'/[artistSlug]/[year]'`) to narrow the return type to the
46
+ * exact params shape for that route.
47
+ *
48
+ * Without a route argument, returns all coerced params with optional types.
49
+ *
50
+ * See design/41-global-params.md §Function Signatures
44
51
  */
45
- export declare function getSegmentParams(): Record<string, string | string[]>;
52
+ export declare function getSegmentParams(route?: string): Record<string, string | string[]>;
46
53
  /**
47
- * Set the segment params promise on the current request context.
54
+ * Set the segment params on the current request context.
48
55
  * Called by the pipeline after route matching and param coercion.
49
56
  *
50
57
  * @internal — framework use only
51
58
  */
52
59
  export declare function setSegmentParams(params: Record<string, string | string[]>): void;
60
+ /**
61
+ * Store the matched route pattern (e.g. '/[artistSlug]/[year]') for
62
+ * dev-mode route mismatch validation in getSegmentParams().
63
+ *
64
+ * @internal — framework use only
65
+ */
66
+ export declare function setMatchedRoutePattern(pattern: string): void;
53
67
  /**
54
68
  * Returns the raw search string from the current request URL (e.g. "?foo=bar").
55
69
  * Synchronous — safe for use in `redirect()` which throws synchronously.
@@ -1 +1 @@
1
- {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,iBAAiB,EAA4B,MAAM,mBAAmB,CAAC;AAMhF,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAQ7B;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAS5C;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,eAAe,CASjD;AAaD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAepE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,IAAI,CAMhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAG/C;AAID;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,OAAO,EACP,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,MAAM,CAAC,QAAQ,CACnF,CAAC;AAIF;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAmBrE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAK9D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmBhE"}
1
+ {"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,iBAAiB,EAA4B,MAAM,mBAAmB,CAAC;AAOhF,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAQ7B;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAS5C;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,eAAe,CASjD;AAaD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAkClF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,IAAI,CAMhF;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAI5D;AAkBD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAG/C;AAID;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,OAAO,EACP,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,MAAM,CAAC,QAAQ,CACnF,CAAC;AAIF;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAmBrE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAK9D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmBhE"}
@@ -1 +1 @@
1
- {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAElD,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,CAQ/F;AAID;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,yDAAyD;IACzD,gBAAgB,IAAI,MAAM,CAAC;IAC3B,yEAAyE;IACzE,aAAa,IAAI,mBAAmB,EAAE,CAAC;CACxC;AAED,wBAAgB,2BAA2B,IAAI,qBAAqB,CAkCnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA8ClE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,KAAK,CAAC;IACtB,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC,GACD,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CA0B3C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGzD;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,cAAc,EACtB,eAAe,EAAE,OAAO,GACvB,QAAQ,CAOV;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIpD;AAGD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAW1E"}
1
+ {"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/helpers.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAGlD,+DAA+D;AAC/D,eAAO,MAAM,gBAAgB,qBAAqB,CAAC;AAEnD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI;IAAE,QAAQ,EAAE,cAAc,CAAC;IAAC,QAAQ,EAAE,cAAc,CAAA;CAAE,CAQ/F;AAID;;;;;;GAMG;AACH,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnB,KAAK,EAAE,OAAO,EAAE,GAAG,IAAI,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,cAAc,CAAC;IACzB,QAAQ,EAAE,cAAc,CAAC;IACzB,yDAAyD;IACzD,gBAAgB,IAAI,MAAM,CAAC;IAC3B,yEAAyE;IACzE,aAAa,IAAI,mBAAmB,EAAE,CAAC;CACxC;AAED,wBAAgB,2BAA2B,IAAI,qBAAqB,CAkCnE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,mBAAmB,EAAE,CA8ClE;AAED;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,KAAK,CAAC;IACtB,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B,CAAC,GACD,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAA;CAAE,CAAC,CA0B3C;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,OAAO,CAGzD;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,cAAc,EACtB,eAAe,EAAE,OAAO,GACvB,QAAQ,CAOV;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAIpD;AAGD,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAErD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAW1E"}
@@ -1,16 +1,5 @@
1
1
  import 'virtual:timber-search-params-registry';
2
- import { type DebugComponentEntry } from './helpers.js';
3
- /**
4
- * Set the dev pipeline error handler.
5
- *
6
- * Called by the dev server after importing this module to wire pipeline
7
- * errors into the Vite browser error overlay. No-op in production.
8
- *
9
- * The handler receives an optional third argument with RSC debug component
10
- * info — component names, environments, and stack frames from the Flight
11
- * debug channel. This is only populated for render-phase errors.
12
- */
13
- export declare function setDevPipelineErrorHandler(handler: (error: Error, phase: string, debugComponents?: DebugComponentEntry[]) => void): void;
2
+ import type { PipelineConfig } from '../pipeline.js';
14
3
  /**
15
4
  * Set the dev source-map handler.
16
5
  *
@@ -24,6 +13,11 @@ export declare function setDevPipelineErrorHandler(handler: (error: Error, phase
24
13
  export declare function setDevSourceMapHandler(handler: (error: Error) => void): void;
25
14
  export { runWithEarlyHintsSender } from '../early-hints-sender.js';
26
15
  export { runWithWaitUntil } from '../waituntil-bridge.js';
27
- declare const _default: (req: Request) => Promise<Response>;
28
- export default _default;
16
+ declare const _handler: (req: Request) => Promise<Response>;
17
+ /**
18
+ * The pipeline configuration object. Exported so the dev server can set
19
+ * `devPipelineErrorHandler` after import without a module-level singleton.
20
+ */
21
+ export declare const pipelineConfig: PipelineConfig;
22
+ export default _handler;
29
23
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AAuBA,OAAO,uCAAuC,CAAC;AAiC/C,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAgCtB;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,eAAe,CAAC,EAAE,mBAAmB,EAAE,KAAK,IAAI,GACtF,IAAI,CAEN;AAED;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAE5E;AAqWD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;;AAE1D,wBAAiE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AAuBA,OAAO,uCAAuC,CAAC;AAqB/C,OAAO,KAAK,EAAuB,cAAc,EAAc,MAAM,gBAAgB,CAAC;AAqCtF;;;;;;;;;GASG;AACH,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,GAAG,IAAI,CAE5E;AA8WD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE1D,QAAA,MAAiB,QAAQ,qCAGxB,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,cAAc,gBAAkB,CAAC;AAE9C,eAAe,QAAQ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timber-js/app",
3
- "version": "0.2.0-alpha.110",
3
+ "version": "0.2.0-alpha.112",
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",
@@ -81,6 +81,10 @@
81
81
  "types": "./dist/segment-params/index.d.ts",
82
82
  "import": "./dist/segment-params/index.js"
83
83
  },
84
+ "./params": {
85
+ "types": "./dist/params/index.d.ts",
86
+ "import": "./dist/params/index.js"
87
+ },
84
88
  "./adapters/cloudflare": {
85
89
  "types": "./dist/adapters/cloudflare.d.ts",
86
90
  "import": "./dist/adapters/cloudflare.js"
@@ -110,6 +114,11 @@
110
114
  "publishConfig": {
111
115
  "access": "public"
112
116
  },
117
+ "scripts": {
118
+ "build": "vite build --config vite.lib.config.ts && tsc --emitDeclarationOnly --project tsconfig.json --outDir dist",
119
+ "typecheck": "tsgo --noEmit",
120
+ "prepublishOnly": "pnpm run build"
121
+ },
113
122
  "dependencies": {
114
123
  "@opentelemetry/api": "^1.9.1",
115
124
  "@opentelemetry/context-async-hooks": "^2.6.1",
@@ -153,9 +162,5 @@
153
162
  },
154
163
  "engines": {
155
164
  "node": ">=22.12.0"
156
- },
157
- "scripts": {
158
- "build": "vite build --config vite.lib.config.ts && tsc --emitDeclarationOnly --project tsconfig.json --outDir dist",
159
- "typecheck": "tsgo --noEmit"
160
165
  }
161
- }
166
+ }
@@ -25,7 +25,9 @@ export function estimateByteSize(value: unknown): number {
25
25
  if (json === undefined) return 0;
26
26
  // Each JS string character is 2 bytes (UTF-16)
27
27
  return json.length * 2;
28
- } catch {
28
+ } catch (e) {
29
+ // Circular reference or non-serializable value
30
+ console.debug('[timber] sizeof estimation failed:', e instanceof Error ? e.message : e);
29
31
  return 0;
30
32
  }
31
33
  }
@@ -0,0 +1,206 @@
1
+ /**
2
+ * `timber schema sync` — scan filesystem for dynamic segments and append
3
+ * missing entries to app/schema.ts with `codec.string` defaults.
4
+ *
5
+ * Only adds, never removes or modifies existing entries.
6
+ *
7
+ * Design doc: design/41-global-params.md §Auto-Scaffolding
8
+ */
9
+
10
+ import { readFileSync, writeFileSync, existsSync } from 'node:fs';
11
+ import { join } from 'node:path';
12
+ import { scanRoutes } from './routing/scanner.js';
13
+ import type { SegmentNode } from './routing/types.js';
14
+ import { resolveAppDir } from './plugin-context.js';
15
+
16
+ /**
17
+ * Collect all unique bracket-keyed dynamic segment names from the route tree.
18
+ * Returns entries like '[artistSlug]', '[...slug]', '[[...topic]]'.
19
+ */
20
+ export function collectDynamicSegments(appDir: string): string[] {
21
+ const tree = scanRoutes(appDir);
22
+ const segments = new Set<string>();
23
+ walkSegments(tree.root, segments);
24
+ return [...segments].sort();
25
+ }
26
+
27
+ function walkSegments(node: SegmentNode, segments: Set<string>): void {
28
+ if (node.paramName) {
29
+ // Reconstruct bracket key from segmentName (already has brackets)
30
+ segments.add(node.segmentName);
31
+ }
32
+ for (const child of node.children) {
33
+ walkSegments(child, segments);
34
+ }
35
+ for (const slot of Object.values(node.slots)) {
36
+ walkSegments(slot, segments);
37
+ }
38
+ }
39
+
40
+ /**
41
+ * Parse existing bracket keys from an app/schema.ts file.
42
+ * Uses regex to find keys in segmentParams: { '[key]': ... } blocks.
43
+ */
44
+ export function parseExistingSchemaKeys(content: string): string[] {
45
+ const keys: string[] = [];
46
+ // Match quoted bracket keys like '[artistSlug]', '[...slug]', '[[...topic]]'
47
+ const re = /['"](\[{1,2}(?:\.{3})?\w+\]{1,2})['"]\s*:/g;
48
+ let m: RegExpExecArray | null;
49
+ while ((m = re.exec(content)) !== null) {
50
+ keys.push(m[1]);
51
+ }
52
+ return keys;
53
+ }
54
+
55
+ /** Schema file extensions to check. */
56
+ const SCHEMA_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx'];
57
+
58
+ /**
59
+ * Find the schema file path if it exists.
60
+ */
61
+ export function findSchemaFile(appDir: string): string | undefined {
62
+ for (const ext of SCHEMA_EXTENSIONS) {
63
+ const p = join(appDir, `schema${ext}`);
64
+ if (existsSync(p)) return p;
65
+ }
66
+ return undefined;
67
+ }
68
+
69
+ /**
70
+ * Generate the content for a new app/schema.ts with the given segment keys.
71
+ */
72
+ function generateNewSchema(segments: string[]): string {
73
+ const lines: string[] = [];
74
+ lines.push("import { defineSchema, codec } from '@timber-js/app';");
75
+ lines.push('');
76
+ lines.push('export default defineSchema({');
77
+ lines.push(' segmentParams: {');
78
+ for (const seg of segments) {
79
+ lines.push(` '${seg}': codec.string,`);
80
+ }
81
+ lines.push(' },');
82
+ lines.push('});');
83
+ lines.push('');
84
+ return lines.join('\n');
85
+ }
86
+
87
+ /**
88
+ * Append missing segment entries to an existing schema file.
89
+ * Inserts new entries before the closing `}` of segmentParams.
90
+ */
91
+ function appendToSchema(content: string, newSegments: string[]): string {
92
+ // Find the closing brace of segmentParams object.
93
+ // Strategy: find the last entry in segmentParams block, insert after it.
94
+ // Look for the pattern: segmentParams: { ... }
95
+ // We find the closing `},` or `}` that ends segmentParams.
96
+
97
+ // Find "segmentParams" key position
98
+ const spIndex = content.indexOf('segmentParams');
99
+ if (spIndex === -1) {
100
+ throw new Error(
101
+ '[timber] Could not find segmentParams in schema file. ' +
102
+ 'Expected a defineSchema({ segmentParams: { ... } }) call.'
103
+ );
104
+ }
105
+
106
+ // Find the opening brace after segmentParams
107
+ const openBrace = content.indexOf('{', spIndex + 'segmentParams'.length);
108
+ if (openBrace === -1) {
109
+ throw new Error('[timber] Could not find opening brace for segmentParams.');
110
+ }
111
+
112
+ // Count braces to find the matching close
113
+ let depth = 1;
114
+ let i = openBrace + 1;
115
+ while (i < content.length && depth > 0) {
116
+ if (content[i] === '{') depth++;
117
+ else if (content[i] === '}') depth--;
118
+ i++;
119
+ }
120
+ // i now points to just after the closing brace
121
+ const closeBrace = i - 1;
122
+
123
+ // Detect indentation from existing entries
124
+ const existingLine = content.slice(openBrace, closeBrace).match(/^(\s+)['"]\[/m);
125
+ const indent = existingLine ? existingLine[1] : ' ';
126
+
127
+ // Build insertion text
128
+ const insertion = newSegments.map((seg) => `${indent}'${seg}': codec.string,`).join('\n');
129
+
130
+ // Insert before the closing brace
131
+ const before = content.slice(0, closeBrace);
132
+ const after = content.slice(closeBrace);
133
+
134
+ // Add newline if the content before doesn't end with one
135
+ const separator = before.trimEnd().endsWith(',') ? '\n' : '\n';
136
+
137
+ return before + separator + insertion + '\n' + after;
138
+ }
139
+
140
+ export interface SchemaSyncResult {
141
+ /** Segments found in the filesystem. */
142
+ filesystemSegments: string[];
143
+ /** Segments already defined in app/schema.ts. */
144
+ existingSegments: string[];
145
+ /** Segments that were added. */
146
+ addedSegments: string[];
147
+ /** Whether a new schema file was created. */
148
+ created: boolean;
149
+ }
150
+
151
+ /**
152
+ * Run the schema sync: scan filesystem, diff against schema, append missing.
153
+ */
154
+ export function runSchemaSync(projectRoot: string): SchemaSyncResult {
155
+ const appDir = resolveAppDir(projectRoot);
156
+
157
+ const filesystemSegments = collectDynamicSegments(appDir);
158
+
159
+ if (filesystemSegments.length === 0) {
160
+ return {
161
+ filesystemSegments: [],
162
+ existingSegments: [],
163
+ addedSegments: [],
164
+ created: false,
165
+ };
166
+ }
167
+
168
+ const schemaPath = findSchemaFile(appDir);
169
+
170
+ if (!schemaPath) {
171
+ // Create new schema file
172
+ const newPath = join(appDir, 'schema.ts');
173
+ writeFileSync(newPath, generateNewSchema(filesystemSegments), 'utf-8');
174
+ return {
175
+ filesystemSegments,
176
+ existingSegments: [],
177
+ addedSegments: filesystemSegments,
178
+ created: true,
179
+ };
180
+ }
181
+
182
+ // Read existing schema and find missing segments
183
+ const content = readFileSync(schemaPath, 'utf-8');
184
+ const existingSegments = parseExistingSchemaKeys(content);
185
+ const missing = filesystemSegments.filter((seg) => !existingSegments.includes(seg));
186
+
187
+ if (missing.length === 0) {
188
+ return {
189
+ filesystemSegments,
190
+ existingSegments,
191
+ addedSegments: [],
192
+ created: false,
193
+ };
194
+ }
195
+
196
+ // Append missing segments
197
+ const updated = appendToSchema(content, missing);
198
+ writeFileSync(schemaPath, updated, 'utf-8');
199
+
200
+ return {
201
+ filesystemSegments,
202
+ existingSegments,
203
+ addedSegments: missing,
204
+ created: false,
205
+ };
206
+ }
package/src/cli.ts CHANGED
@@ -11,7 +11,7 @@
11
11
  // timber preview — Serve the production build
12
12
  // timber check — Validate types + routes without building
13
13
 
14
- const COMMANDS = ['dev', 'build', 'preview', 'check'] as const;
14
+ const COMMANDS = ['dev', 'build', 'preview', 'check', 'schema'] as const;
15
15
  type Command = (typeof COMMANDS)[number];
16
16
 
17
17
  export interface ParsedArgs {
@@ -30,7 +30,7 @@ export interface CommandOptions {
30
30
  export function parseArgs(args: string[]): ParsedArgs {
31
31
  if (args.length === 0) {
32
32
  throw new Error(
33
- 'No command provided. Usage: timber <dev|build|preview|check> [--config <path>]'
33
+ 'No command provided. Usage: timber <dev|build|preview|check|schema> [--config <path>]'
34
34
  );
35
35
  }
36
36
 
@@ -184,6 +184,50 @@ export async function runCheck(options: CommandOptions): Promise<void> {
184
184
  });
185
185
  }
186
186
 
187
+ // ─── Schema Subcommand ───────────────────────────────────────────────────────
188
+
189
+ /**
190
+ * `timber schema sync` — scan filesystem for dynamic segments, diff against
191
+ * app/schema.ts, and append missing entries with codec.string default.
192
+ *
193
+ * See design/41-global-params.md §Auto-Scaffolding
194
+ */
195
+ export async function runSchema(args: string[]): Promise<void> {
196
+ const subcommand = args[0];
197
+
198
+ if (subcommand !== 'sync') {
199
+ throw new Error(
200
+ `Unknown schema subcommand: ${subcommand ?? '(none)'}. Usage: timber schema sync`
201
+ );
202
+ }
203
+
204
+ const { runSchemaSync } = await import('./cli-schema-sync.js');
205
+ const result = runSchemaSync(process.cwd());
206
+
207
+ if (result.filesystemSegments.length === 0) {
208
+ console.log('[timber] No dynamic segments found in app/.');
209
+ return;
210
+ }
211
+
212
+ if (result.created) {
213
+ console.log(`[timber] Created app/schema.ts with ${result.addedSegments.length} segment(s):`);
214
+ for (const seg of result.addedSegments) {
215
+ console.log(` + ${seg}: codec.string`);
216
+ }
217
+ return;
218
+ }
219
+
220
+ if (result.addedSegments.length === 0) {
221
+ console.log('[timber] Schema is up to date — all segments are registered.');
222
+ return;
223
+ }
224
+
225
+ console.log(`[timber] Added ${result.addedSegments.length} segment(s) to app/schema.ts:`);
226
+ for (const seg of result.addedSegments) {
227
+ console.log(` + ${seg}: codec.string`);
228
+ }
229
+ }
230
+
187
231
  // ─── Main Entry Point ────────────────────────────────────────────────────────
188
232
 
189
233
  async function main(): Promise<void> {
@@ -203,6 +247,9 @@ async function main(): Promise<void> {
203
247
  case 'check':
204
248
  await runCheck(options);
205
249
  break;
250
+ case 'schema':
251
+ await runSchema(process.argv.slice(3));
252
+ break;
206
253
  }
207
254
  }
208
255
 
@@ -78,10 +78,14 @@ export function setupServerActions(): void {
78
78
  try {
79
79
  const router = getRouter();
80
80
  void router.navigate(wrapper._redirect);
81
- } catch {
81
+ } catch (e) {
82
82
  // Router not yet initialized — fall back to full navigation.
83
83
  // Set hard-navigating flag to prevent Navigation API interception
84
84
  // and React from rendering during page teardown. See TIM-626.
85
+ console.debug(
86
+ '[timber] action redirect: router not ready, using full navigation',
87
+ e instanceof Error ? e.message : e
88
+ );
85
89
  setHardNavigating(true);
86
90
  window.location.href = wrapper._redirect;
87
91
  }
@@ -96,8 +100,11 @@ export function setupServerActions(): void {
96
100
  const router = getRouter();
97
101
  const headElements = headElementsJson ? JSON.parse(headElementsJson) : null;
98
102
  router.applyRevalidation(wrapper._tree, headElements);
99
- } catch {
100
- // Router not yet initialized — fall through
103
+ } catch (e) {
104
+ console.debug(
105
+ '[timber] action revalidation: router not ready',
106
+ e instanceof Error ? e.message : e
107
+ );
101
108
  }
102
109
  return wrapper._action;
103
110
  }
@@ -107,8 +114,11 @@ export function setupServerActions(): void {
107
114
  try {
108
115
  const router = getRouter();
109
116
  void router.refresh();
110
- } catch {
111
- // Router not yet initialized (rare edge case during bootstrap)
117
+ } catch (e) {
118
+ console.debug(
119
+ '[timber] action refresh: router not ready',
120
+ e instanceof Error ? e.message : e
121
+ );
112
122
  }
113
123
 
114
124
  return decoded;
@@ -34,6 +34,12 @@ import config from 'virtual:timber-config';
34
34
  // render and click handlers. Side-effect-only import.
35
35
  // @ts-expect-error — virtual module provided by timber-routing plugin
36
36
  import 'virtual:timber-search-params-registry';
37
+ // TIM-932: Populate the codec registry so Link's interpolateParams can
38
+ // use codec.serialize() for URL construction. Side-effect-only import.
39
+ // @ts-expect-error — virtual module provided by timber-routing plugin
40
+ import schemaCodecs from 'virtual:timber-schema';
41
+ import { setLinkCodecs } from '../../params/codec-registry.js';
42
+ if (schemaCodecs) setLinkCodecs(schemaCodecs);
37
43
 
38
44
  import { setClientDeploymentId } from '../rsc-fetch.js';
39
45
  import {
@@ -273,8 +273,8 @@ function parseDigest(error: Error): ParsedDigest | null {
273
273
  if (parsed && typeof parsed === 'object' && typeof parsed.type === 'string') {
274
274
  return parsed as ParsedDigest;
275
275
  }
276
- } catch {
277
- // Not JSON — legacy or unknown digest format
276
+ } catch (e) {
277
+ console.debug('[timber] error digest is not valid JSON:', e instanceof Error ? e.message : e);
278
278
  }
279
279
  return null;
280
280
  }
@@ -42,6 +42,7 @@ import {
42
42
  } from './link-pending-store.js';
43
43
  import { setNavLinkMetadata } from './nav-link-store.js';
44
44
  import { hasNavigationApi } from './navigation-api.js';
45
+ import { getLinkCodec } from '../params/codec-registry.js';
45
46
 
46
47
  // ─── Current Search Params ────────────────────────────────────────
47
48
 
@@ -225,6 +226,9 @@ export function parseSegments(pattern: string): UrlSegment[] {
225
226
  /**
226
227
  * Resolve a single classified segment into its string representation.
227
228
  * Returns null for optional catch-all with no value (filtered out before join).
229
+ *
230
+ * When schema codecs are registered (via virtual:timber-schema), uses
231
+ * codec.serialize() for URL construction instead of plain String().
228
232
  */
229
233
  function resolveSegment(
230
234
  seg: UrlSegment,
@@ -240,6 +244,13 @@ function resolveSegment(
240
244
  if (value === undefined || (Array.isArray(value) && value.length === 0)) {
241
245
  return null;
242
246
  }
247
+ const codec = getLinkCodec(`[[...${seg.name}]]`);
248
+ if (codec) {
249
+ const serialized = codec.serialize(value);
250
+ if (!serialized) return null;
251
+ // Codec returns a path string (may contain '/') — encode each segment
252
+ return serialized.split('/').map(encodeURIComponent).join('/');
253
+ }
243
254
  const segments = Array.isArray(value) ? value : [value];
244
255
  return segments.map(encodeURIComponent).join('/');
245
256
  }
@@ -251,6 +262,17 @@ function resolveSegment(
251
262
  `<Link> missing required catch-all param "${seg.name}" for pattern "${pattern}".`
252
263
  );
253
264
  }
265
+ const codec = getLinkCodec(`[...${seg.name}]`);
266
+ if (codec) {
267
+ const serialized = codec.serialize(value);
268
+ if (!serialized) {
269
+ throw new Error(
270
+ `<Link> catch-all param "${seg.name}" codec returned null for pattern "${pattern}".`
271
+ );
272
+ }
273
+ // Codec returns a path string (may contain '/') — encode each segment
274
+ return serialized.split('/').map(encodeURIComponent).join('/');
275
+ }
254
276
  const segments = Array.isArray(value) ? value : [value];
255
277
  if (segments.length === 0) {
256
278
  throw new Error(
@@ -270,7 +292,9 @@ function resolveSegment(
270
292
  `<Link> param "${seg.name}" expected a string but received an array for pattern "${pattern}".`
271
293
  );
272
294
  }
273
- return encodeURIComponent(String(value));
295
+ const codec = getLinkCodec(`[${seg.name}]`);
296
+ const str = codec ? (codec.serialize(value) ?? String(value)) : String(value);
297
+ return encodeURIComponent(str);
274
298
  }
275
299
  }
276
300
  }