@timber-js/app 0.2.0-alpha.60 → 0.2.0-alpha.62

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 (117) hide show
  1. package/dist/_chunks/{als-registry-Ba7URUIn.js → als-registry-BJARkOcu.js} +1 -1
  2. package/dist/_chunks/{als-registry-Ba7URUIn.js.map → als-registry-BJARkOcu.js.map} +1 -1
  3. package/dist/_chunks/{define-D5STJpIr.js → define-Djpqoe1K.js} +2 -2
  4. package/dist/_chunks/{define-D5STJpIr.js.map → define-Djpqoe1K.js.map} +1 -1
  5. package/dist/_chunks/{define-cookie-DtAavax4.js → define-cookie-B2djY9w0.js} +4 -4
  6. package/dist/_chunks/{define-cookie-DtAavax4.js.map → define-cookie-B2djY9w0.js.map} +1 -1
  7. package/dist/_chunks/{define-TK8C1M3x.js → define-hdajFTq7.js} +2 -2
  8. package/dist/_chunks/{define-TK8C1M3x.js.map → define-hdajFTq7.js.map} +1 -1
  9. package/dist/_chunks/{error-boundary-DpZJBCqh.js → error-boundary-A_sgyyUP.js} +1 -1
  10. package/dist/_chunks/{error-boundary-DpZJBCqh.js.map → error-boundary-A_sgyyUP.js.map} +1 -1
  11. package/dist/_chunks/{tracing-VYETCQsg.js → handler-store-CaE0ZgVG.js} +54 -3
  12. package/dist/_chunks/handler-store-CaE0ZgVG.js.map +1 -0
  13. package/dist/_chunks/{interception-Cey5DCGr.js → interception-BVm64Jr5.js} +7 -13
  14. package/dist/_chunks/interception-BVm64Jr5.js.map +1 -0
  15. package/dist/_chunks/{metadata-routes-BU684ls2.js → metadata-routes-DS3eKNmf.js} +1 -1
  16. package/dist/_chunks/{metadata-routes-BU684ls2.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
  17. package/dist/_chunks/{request-context-0wfZsnhh.js → request-context-B_u9dyhZ.js} +4 -4
  18. package/dist/_chunks/{request-context-0wfZsnhh.js.map → request-context-B_u9dyhZ.js.map} +1 -1
  19. package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
  20. package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
  21. package/dist/_chunks/{segment-context-CyaM1mrD.js → segment-context-CVRHlkkQ.js} +1 -1
  22. package/dist/_chunks/{segment-context-CyaM1mrD.js.map → segment-context-CVRHlkkQ.js.map} +1 -1
  23. package/dist/_chunks/{stale-reload-DKN3aXxR.js → stale-reload-BeyHXZ5B.js} +5 -2
  24. package/dist/_chunks/{stale-reload-DKN3aXxR.js.map → stale-reload-BeyHXZ5B.js.map} +1 -1
  25. package/dist/_chunks/{use-query-states-wEXY2JQB.js → use-query-states-DAhgj8Gx.js} +1 -1
  26. package/dist/_chunks/{use-query-states-wEXY2JQB.js.map → use-query-states-DAhgj8Gx.js.map} +1 -1
  27. package/dist/_chunks/{wrappers-BaG1bnM3.js → wrappers-CJQ3KwVr.js} +1 -1
  28. package/dist/_chunks/{wrappers-BaG1bnM3.js.map → wrappers-CJQ3KwVr.js.map} +1 -1
  29. package/dist/cache/cache-api.d.ts +24 -0
  30. package/dist/cache/cache-api.d.ts.map +1 -0
  31. package/dist/cache/handler-store.d.ts +31 -0
  32. package/dist/cache/handler-store.d.ts.map +1 -0
  33. package/dist/cache/index.d.ts +2 -1
  34. package/dist/cache/index.d.ts.map +1 -1
  35. package/dist/cache/index.js +33 -2
  36. package/dist/cache/index.js.map +1 -1
  37. package/dist/client/error-boundary.js +1 -1
  38. package/dist/client/index.d.ts +1 -1
  39. package/dist/client/index.d.ts.map +1 -1
  40. package/dist/client/index.js +50 -21
  41. package/dist/client/index.js.map +1 -1
  42. package/dist/client/link.d.ts +6 -0
  43. package/dist/client/link.d.ts.map +1 -1
  44. package/dist/client/rsc-fetch.d.ts.map +1 -1
  45. package/dist/client/stale-reload.d.ts.map +1 -1
  46. package/dist/client/transition-root.d.ts +12 -0
  47. package/dist/client/transition-root.d.ts.map +1 -1
  48. package/dist/cookies/index.js +1 -1
  49. package/dist/index.js +55 -3
  50. package/dist/index.js.map +1 -1
  51. package/dist/params/define.d.ts.map +1 -1
  52. package/dist/params/index.js +3 -3
  53. package/dist/plugins/dev-browser-logs.d.ts.map +1 -1
  54. package/dist/plugins/entries.d.ts.map +1 -1
  55. package/dist/routing/index.d.ts +2 -0
  56. package/dist/routing/index.d.ts.map +1 -1
  57. package/dist/routing/index.js +3 -2
  58. package/dist/routing/scanner.d.ts.map +1 -1
  59. package/dist/routing/segment-classify.d.ts +46 -0
  60. package/dist/routing/segment-classify.d.ts.map +1 -0
  61. package/dist/search-params/index.js +3 -3
  62. package/dist/server/actions.d.ts +0 -3
  63. package/dist/server/actions.d.ts.map +1 -1
  64. package/dist/server/deny-renderer.d.ts.map +1 -1
  65. package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
  66. package/dist/server/fallback-error.d.ts.map +1 -1
  67. package/dist/server/index.js +100 -17
  68. package/dist/server/index.js.map +1 -1
  69. package/dist/server/pipeline-interception.d.ts.map +1 -1
  70. package/dist/server/pipeline.d.ts.map +1 -1
  71. package/dist/server/route-element-builder.d.ts.map +1 -1
  72. package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
  73. package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
  74. package/dist/server/rsc-entry/index.d.ts.map +1 -1
  75. package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
  76. package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
  77. package/dist/server/safe-load.d.ts +46 -0
  78. package/dist/server/safe-load.d.ts.map +1 -0
  79. package/dist/server/slot-resolver.d.ts.map +1 -1
  80. package/dist/server/stream-utils.d.ts.map +1 -1
  81. package/dist/server/tracing.d.ts.map +1 -1
  82. package/package.json +1 -1
  83. package/src/cache/cache-api.ts +38 -0
  84. package/src/cache/handler-store.ts +68 -0
  85. package/src/cache/index.ts +2 -1
  86. package/src/client/browser-entry.ts +90 -31
  87. package/src/client/index.ts +1 -1
  88. package/src/client/link.tsx +81 -46
  89. package/src/client/rsc-fetch.ts +3 -1
  90. package/src/client/stale-reload.ts +19 -2
  91. package/src/client/transition-root.tsx +27 -0
  92. package/src/params/define.ts +11 -4
  93. package/src/plugins/dev-browser-logs.ts +10 -0
  94. package/src/plugins/entries.ts +61 -0
  95. package/src/plugins/routing.ts +1 -1
  96. package/src/routing/index.ts +2 -0
  97. package/src/routing/scanner.ts +7 -16
  98. package/src/routing/segment-classify.ts +89 -0
  99. package/src/server/actions.ts +7 -6
  100. package/src/server/deny-renderer.ts +4 -3
  101. package/src/server/error-boundary-wrapper.ts +9 -6
  102. package/src/server/fallback-error.ts +20 -7
  103. package/src/server/pipeline-interception.ts +16 -15
  104. package/src/server/pipeline.ts +20 -2
  105. package/src/server/route-element-builder.ts +5 -4
  106. package/src/server/rsc-entry/api-handler.ts +4 -3
  107. package/src/server/rsc-entry/error-renderer.ts +25 -10
  108. package/src/server/rsc-entry/index.ts +24 -0
  109. package/src/server/rsc-entry/rsc-payload.ts +1 -1
  110. package/src/server/rsc-entry/ssr-bridge.ts +13 -4
  111. package/src/server/rsc-entry/ssr-renderer.ts +12 -1
  112. package/src/server/safe-load.ts +60 -0
  113. package/src/server/slot-resolver.ts +3 -1
  114. package/src/server/stream-utils.ts +10 -6
  115. package/src/server/tracing.ts +14 -3
  116. package/dist/_chunks/interception-Cey5DCGr.js.map +0 -1
  117. package/dist/_chunks/tracing-VYETCQsg.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"pipeline-interception.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-interception.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,iDAAiD;AACjD,MAAM,WAAW,uBAAuB;IACtC,yEAAyE;IACzE,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,4BAA4B,EAAE,mBAAmB,EAAE,GACnE,uBAAuB,GAAG,IAAI,CAYhC;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CA0BjF"}
1
+ {"version":3,"file":"pipeline-interception.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-interception.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,iDAAiD;AACjD,MAAM,WAAW,uBAAuB;IACtC,yEAAyE;IACzE,cAAc,EAAE,MAAM,CAAC;CACxB;AAED;;;;;;;GAOG;AACH,wBAAgB,qBAAqB,CACnC,cAAc,EAAE,MAAM,EACtB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,OAAO,4BAA4B,EAAE,mBAAmB,EAAE,GACnE,uBAAuB,GAAG,IAAI,CAYhC;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAyBjF"}
@@ -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":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAoC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvD,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,mDAAmD;IACnD,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,uDAAuD;IACvD,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B;AAED,6DAA6D;AAC7D,MAAM,MAAM,YAAY,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,CAAC;AAEnE,sEAAsE;AACtE,MAAM,MAAM,oBAAoB,GAAG,CACjC,QAAQ,EAAE,MAAM,KACb,OAAO,oBAAoB,EAAE,kBAAkB,GAAG,IAAI,CAAC;AAE5D,iEAAiE;AACjE,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,6DAA6D;AAC7D,MAAM,MAAM,aAAa,GAAG,CAC1B,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,YAAY,CAAC,EAAE,mBAAmB,KAC/B,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;AAElC,+DAA+D;AAC/D,MAAM,MAAM,iBAAiB,GAAG,CAC9B,KAAK,EAAE,UAAU,EACjB,GAAG,EAAE,OAAO,EACZ,eAAe,EAAE,OAAO,KACrB,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAI1B,MAAM,WAAW,cAAc;IAC7B,iFAAiF;IACjF,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC;QAAE,OAAO,EAAE,WAAW,CAAA;KAAE,CAAC,CAAC;IACtD,qEAAqE;IACrE,UAAU,EAAE,YAAY,CAAC;IACzB,iGAAiG;IACjG,kBAAkB,CAAC,EAAE,oBAAoB,CAAC;IAC1C,kEAAkE;IAClE,MAAM,EAAE,aAAa,CAAC;IACtB,kEAAkE;IAClE,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,EAAE,OAAO,KAAK,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;IACzF,kFAAkF;IAClF,UAAU,CAAC,EAAE,iBAAiB,CAAC;IAC/B,gFAAgF;IAChF,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,yGAAyG;IACzG,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,4BAA4B,EAAE,mBAAmB,EAAE,CAAC;IAClF;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,UAAU,GAAG,OAAO,GAAG,KAAK,CAAC;IAC5C;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxD;;;;;;;;;;OAUG;IACH,mBAAmB,CAAC,EAAE,CACpB,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,OAAO,EACZ,eAAe,EAAE,OAAO,KACrB,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACnC;AAID;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CA8B1E;AAID;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CA6Z1F"}
@@ -1 +1 @@
1
- {"version":3,"file":"route-element-builder.d.ts","sourceRoot":"","sources":["../../src/server/route-element-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAM7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAKzD;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAID,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACvC;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC;IAC5B,2CAA2C;IAC3C,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,wDAAwD;IACxD,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,qCAAqC;IACrC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,MAAM,EAAE,UAAU,GAAG,cAAc;aACnC,gBAAgB,EAAE,oBAAoB,EAAE;aACxC,QAAQ,EAAE,mBAAmB,EAAE;gBAF/B,MAAM,EAAE,UAAU,GAAG,cAAc,EACnC,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,QAAQ,EAAE,mBAAmB,EAAE;CAIlD;AA8DD;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,YAAY,CAAC,EAAE,mBAAmB,EAClC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GACnC,OAAO,CAAC,kBAAkB,CAAC,CA6R7B"}
1
+ {"version":3,"file":"route-element-builder.d.ts","sourceRoot":"","sources":["../../src/server/route-element-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAM7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAMzD;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAID,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACvC;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC;IAC5B,2CAA2C;IAC3C,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,wDAAwD;IACxD,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,qCAAqC;IACrC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;GAGG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,MAAM,EAAE,UAAU,GAAG,cAAc;aACnC,gBAAgB,EAAE,oBAAoB,EAAE;aACxC,QAAQ,EAAE,mBAAmB,EAAE;gBAF/B,MAAM,EAAE,UAAU,GAAG,cAAc,EACnC,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,QAAQ,EAAE,mBAAmB,EAAE;CAIlD;AA8DD;;;;;;;;;GASG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,YAAY,CAAC,EAAE,mBAAmB,EAClC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GACnC,OAAO,CAAC,kBAAkB,CAAC,CA6R7B"}
@@ -1 +1 @@
1
- {"version":3,"file":"api-handler.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/api-handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAC/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAMjD,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,eAAe,EAAE,OAAO,GACvB,OAAO,CAAC,QAAQ,CAAC,CAyDnB"}
1
+ {"version":3,"file":"api-handler.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/api-handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE/D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAMjD,wBAAsB,cAAc,CAClC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,eAAe,EAAE,OAAO,GACvB,OAAO,CAAC,QAAQ,CAAC,CAyDnB"}
@@ -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;AAUvD;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAkHD;;;;;;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,CAoCnB;AA0HD;;;;;;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;AAWvD;;;;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,CAoCnB;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 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AA4DA,OAAO,EAKL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAkCtB;;;;;;;;;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;AAwdD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;8BAjTrC,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AAmThD,wBAAiE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AA8DA,OAAO,EAKL,KAAK,mBAAmB,EACzB,MAAM,cAAc,CAAC;AAkCtB;;;;;;;;;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;AA8eD,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAInE,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;8BA7TrC,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AA+ThD,wBAAiE"}
@@ -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,CAMnB"}
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 +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;AAU/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,CAqPjF"}
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;AAU/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,CAgQjF"}
@@ -0,0 +1,46 @@
1
+ /**
2
+ * loadModule — enriched error context for route manifest .load() failures.
3
+ *
4
+ * Wraps the lazy `load()` functions from the route manifest with a
5
+ * try/catch that re-throws with the file path and original cause.
6
+ *
7
+ * Callers that need fallthrough behavior (error renderers) can use
8
+ * `.catch(() => null)` or try/catch — the decision stays at the call site.
9
+ *
10
+ * See design/spike-TIM-551-dynamic-import-audit.md §"Proposed Wrapping Strategy"
11
+ */
12
+ /** A manifest file reference with a lazy import function and file path. */
13
+ export interface ManifestLoader {
14
+ load: () => Promise<unknown>;
15
+ filePath: string;
16
+ }
17
+ /**
18
+ * Custom error class for module load failures.
19
+ *
20
+ * Preserves the original error as `cause` while providing a
21
+ * human-readable message with the file path.
22
+ */
23
+ export declare class ModuleLoadError extends Error {
24
+ /** The file path that failed to load. */
25
+ readonly filePath: string;
26
+ constructor(filePath: string, cause: unknown);
27
+ }
28
+ /**
29
+ * Load a route manifest module with enriched error context.
30
+ *
31
+ * On success: returns the module object (same as `loader.load()`).
32
+ * On failure: throws `ModuleLoadError` with file path and original cause.
33
+ *
34
+ * For error rendering paths that need fallthrough instead of throwing,
35
+ * callers should catch at the call site:
36
+ *
37
+ * ```ts
38
+ * // Throwing (default) — route-element-builder, api-handler, etc.
39
+ * const mod = await loadModule(segment.page);
40
+ *
41
+ * // Fallthrough — error-renderer, error-boundary-wrapper
42
+ * const mod = await loadModule(segment.error).catch(() => null);
43
+ * ```
44
+ */
45
+ export declare function loadModule<T = Record<string, unknown>>(loader: ManifestLoader): Promise<T>;
46
+ //# sourceMappingURL=safe-load.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"safe-load.d.ts","sourceRoot":"","sources":["../../src/server/safe-load.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,2EAA2E;AAC3E,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;GAKG;AACH,qBAAa,eAAgB,SAAQ,KAAK;IACxC,yCAAyC;IACzC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBAEd,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO;CAM7C;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAsB,UAAU,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,EAAE,cAAc,GAAG,OAAO,CAAC,CAAC,CAAC,CAMhG"}
@@ -1 +1 @@
1
- {"version":3,"file":"slot-resolver.d.ts","sourceRoot":"","sources":["../../src/server/slot-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,KAAK,eAAe,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,YAAY,CAAC;AAkHlE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,UAAU,EACjB,CAAC,EAAE,eAAe,EAClB,YAAY,CAAC,EAAE,mBAAmB,GACjC,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CA+FpC"}
1
+ {"version":3,"file":"slot-resolver.d.ts","sourceRoot":"","sources":["../../src/server/slot-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,KAAK,eAAe,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,YAAY,CAAC;AAmHlE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,UAAU,EACjB,CAAC,EAAE,eAAe,EAClB,YAAY,CAAC,EAAE,mBAAmB,GACjC,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CA+FpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"stream-utils.d.ts","sourceRoot":"","sources":["../../src/server/stream-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,CAAC,EAAE,UAAU,GACnB,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,CA+J1D"}
1
+ {"version":3,"file":"stream-utils.d.ts","sourceRoot":"","sources":["../../src/server/stream-utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,MAAM,WAAW,UAAU;IACzB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,cAAc,CAAC,UAAU,CAAC,EAClC,OAAO,CAAC,EAAE,UAAU,GACnB,CAAC,cAAc,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC,CAmK1D"}
@@ -1 +1 @@
1
- {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/server/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG9D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;;;;;GAOG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAShC;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,MAAM,GAAG,SAAS,CAE3C;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAM3E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAKhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,SAAS,CAEtD;AAID;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,OAAO,iBAAiB,EAAE,eAAe,GAChD,OAAO,CAAC,IAAI,CAAC,CA4Bf;AA4BD;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC,CAUrF;AAED;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EACrD,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAyBZ;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAC/B,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GACrD,IAAI,CASN;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAc/F"}
1
+ {"version":3,"file":"tracing.d.ts","sourceRoot":"","sources":["../../src/server/tracing.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EAAY,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG9D,YAAY,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAIpD;;;;;;;GAOG;AACH,wBAAgB,OAAO,IAAI,MAAM,CAShC;AAED;;GAEG;AACH,wBAAgB,MAAM,IAAI,MAAM,GAAG,SAAS,CAE3C;AAID;;;GAGG;AACH,wBAAgB,eAAe,IAAI,MAAM,CAExC;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAE5D;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAM3E;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAKhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,IAAI,UAAU,GAAG,SAAS,CAEtD;AAID;;;;;;;;;GASG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,OAAO,iBAAiB,EAAE,eAAe,GAChD,OAAO,CAAC,IAAI,CAAC,CAuCf;AA4BD;;GAEG;AACH,wBAAsB,SAAS,IAAI,OAAO,CAAC,OAAO,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC,CAUrF;AAED;;;;;;;;;GASG;AACH,wBAAsB,QAAQ,CAAC,CAAC,EAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,EACrD,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAyBZ;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,GAC/B,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;GAGG;AACH,wBAAsB,YAAY,CAChC,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GACrD,OAAO,CAAC,IAAI,CAAC,CAQf;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,GACrD,IAAI,CASN;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,CAAC,CAc/F"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timber-js/app",
3
- "version": "0.2.0-alpha.60",
3
+ "version": "0.2.0-alpha.62",
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",
@@ -0,0 +1,38 @@
1
+ import type { CacheOptions } from './index';
2
+ import { createCache } from './timber-cache';
3
+ import { getCacheHandler } from './handler-store';
4
+
5
+ /**
6
+ * Public caching API: `cache(fn, opts)`.
7
+ *
8
+ * Wraps an async function with cross-request caching. Uses the configured
9
+ * cache handler (defaults to MemoryCacheHandler, overridable via timber.config.ts).
10
+ *
11
+ * ```ts
12
+ * import { cache } from '@timber-js/app/cache';
13
+ *
14
+ * const getUser = cache(
15
+ * async (id: string) => db.users.findUnique({ where: { id } }),
16
+ * { ttl: 60, tags: (id) => [`user:${id}`] }
17
+ * );
18
+ * ```
19
+ */
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
+ export function cache<Fn extends (...args: any[]) => Promise<any>>(
22
+ fn: Fn,
23
+ opts: CacheOptions<Fn>
24
+ ): Fn {
25
+ return createCache(fn, opts, getCacheHandler());
26
+ }
27
+
28
+ /**
29
+ * Invalidate cache entries by tag or key.
30
+ *
31
+ * ```ts
32
+ * cache.invalidate({ tag: 'products' });
33
+ * cache.invalidate({ key: 'user:abc' });
34
+ * ```
35
+ */
36
+ cache.invalidate = async function invalidate(opts: { key?: string; tag?: string }): Promise<void> {
37
+ await getCacheHandler().invalidate(opts);
38
+ };
@@ -0,0 +1,68 @@
1
+ /**
2
+ * Module-level cache handler singleton.
3
+ *
4
+ * Lazily initialized to MemoryCacheHandler on first access. The framework
5
+ * replaces this at boot from timber.config.ts via setCacheHandler().
6
+ *
7
+ * This module avoids importing from ./index to prevent circular dependencies.
8
+ */
9
+
10
+ // Inline the interface to avoid circular import with index.ts
11
+ interface CacheHandlerLike {
12
+ get(key: string): Promise<{ value: unknown; stale: boolean } | null>;
13
+ set(key: string, value: unknown, opts: { ttl: number; tags: string[] }): Promise<void>;
14
+ invalidate(opts: { key?: string; tag?: string }): Promise<void>;
15
+ }
16
+
17
+ let handler: CacheHandlerLike | null = null;
18
+
19
+ /** Replace the active cache handler. Called by the framework at boot. */
20
+ export function setCacheHandler(h: CacheHandlerLike): void {
21
+ handler = h;
22
+ }
23
+
24
+ /**
25
+ * Get the active cache handler. Creates a default MemoryCacheHandler on
26
+ * first access if none has been set via setCacheHandler().
27
+ */
28
+ export function getCacheHandler(): CacheHandlerLike {
29
+ if (!handler) {
30
+ // Inline a minimal LRU cache to avoid circular dep with index.ts.
31
+ // In production, the framework always calls setCacheHandler() at boot.
32
+ handler = createDefaultHandler();
33
+ }
34
+ return handler;
35
+ }
36
+
37
+ function createDefaultHandler(): CacheHandlerLike {
38
+ const store = new Map<string, { value: unknown; expiresAt: number; tags: string[] }>();
39
+ const maxSize = 1000;
40
+
41
+ return {
42
+ async get(key) {
43
+ const entry = store.get(key);
44
+ if (!entry) return null;
45
+ store.delete(key);
46
+ store.set(key, entry);
47
+ const stale = Date.now() > entry.expiresAt;
48
+ return { value: entry.value, stale };
49
+ },
50
+ async set(key, value, opts) {
51
+ if (store.has(key)) store.delete(key);
52
+ while (store.size >= maxSize) {
53
+ const oldest = store.keys().next().value;
54
+ if (oldest !== undefined) store.delete(oldest);
55
+ else break;
56
+ }
57
+ store.set(key, { value, expiresAt: Date.now() + opts.ttl * 1000, tags: opts.tags });
58
+ },
59
+ async invalidate(opts) {
60
+ if (opts.key) store.delete(opts.key);
61
+ if (opts.tag) {
62
+ for (const [key, entry] of store) {
63
+ if (entry.tags.includes(opts.tag)) store.delete(key);
64
+ }
65
+ }
66
+ },
67
+ };
68
+ }
@@ -86,7 +86,8 @@ export class MemoryCacheHandler implements CacheHandler {
86
86
 
87
87
  export { RedisCacheHandler } from './redis-handler';
88
88
  export type { RedisClient } from './redis-handler';
89
- export { createCache } from './timber-cache';
89
+ export { cache } from './cache-api';
90
+ export { setCacheHandler, getCacheHandler } from './handler-store';
90
91
  export { registerCachedFunction } from './register-cached-function';
91
92
  export type { RegisterCachedFunctionOptions } from './register-cached-function';
92
93
  export { stableStringify } from './stable-stringify';
@@ -35,7 +35,13 @@ import {
35
35
  // If we used relative imports (./router-ref.js), Vite would load separate src/
36
36
  // copies with separate module-level state — e.g., globalRouter set here but
37
37
  // read as null from the dist/ copy used by useRouter().
38
- import { createRouter, setGlobalRouter, getRouter, setCurrentParams } from '@timber-js/app/client';
38
+ import {
39
+ createRouter,
40
+ setGlobalRouter,
41
+ getRouter,
42
+ getRouterOrNull,
43
+ setCurrentParams,
44
+ } from '@timber-js/app/client';
39
45
  import type { RouterDeps, RouterInstance } from '@timber-js/app/client';
40
46
 
41
47
  // Internal-only modules (no shared mutable state with user code) use relative
@@ -52,7 +58,12 @@ import {
52
58
  import { setupServerLogReplay, setupClientErrorForwarding } from './browser-dev.js';
53
59
  // browser-links.ts removed — Link components own their click/hover handlers directly.
54
60
  // See LOCAL-340.
55
- import { TransitionRoot, transitionRender, navigateTransition } from './transition-root.js';
61
+ import {
62
+ TransitionRoot,
63
+ transitionRender,
64
+ navigateTransition,
65
+ installDeferredNavigation,
66
+ } from './transition-root.js';
56
67
  import {
57
68
  isStaleClientReference,
58
69
  isChunkLoadError,
@@ -365,33 +376,28 @@ function bootstrap(runtimeConfig: typeof config): void {
365
376
  const element = createFromReadableStream(rscPayload);
366
377
  initialElement = element;
367
378
 
368
- // ── Initialize the navigation router BEFORE hydration ──────────────
369
- // hydrateRoot() synchronously executes component render functions.
370
- // Components that call useRouter() during render need the global
371
- // router to be available, otherwise they get a stale no-op reference.
372
- // The router must be initialized before hydration so useRouter() works.
373
- // renderRoot uses transitionRender (no direct reactRoot dependency).
374
- initRouter();
375
-
376
- // ── Initialize navigation state BEFORE hydration ───────────────────
377
- // Read server-embedded params and set navigation state so that
378
- // useSegmentParams() and usePathname() return correct values during hydration.
379
- // This must happen before hydrateRoot so the NavigationProvider
380
- // wrapping the element has the right values on the initial render.
381
- const earlyParams = (self as unknown as Record<string, unknown>).__timber_params;
382
- if (earlyParams && typeof earlyParams === 'object') {
383
- setCurrentParams(earlyParams as Record<string, string | string[]>);
384
- setNavigationState({
385
- params: earlyParams as Record<string, string | string[]>,
386
- pathname: window.location.pathname,
387
- });
388
- delete (self as unknown as Record<string, unknown>).__timber_params;
389
- } else {
390
- setNavigationState({
391
- params: {},
392
- pathname: window.location.pathname,
393
- });
394
- }
379
+ // ── Pre-hydration bootstrap sequence ──────────────────────────────
380
+ //
381
+ // These steps MUST execute in this exact order before hydrateRoot():
382
+ //
383
+ // 1. initRouter() — creates the global router so useRouter()
384
+ // works during render (methods lazily resolve
385
+ // the router at invocation, not render time,
386
+ // but initRouter must still run first)
387
+ //
388
+ // 2. setCurrentParams() — populates module-level params snapshot so
389
+ // + setNavigationState() useSegmentParams() and usePathname()
390
+ // return correct values during hydration
391
+ //
392
+ // 3. hydrateRoot() — synchronously executes component render
393
+ // functions that depend on steps 1-2
394
+ //
395
+ // Implicit prerequisite: the __timber_f RSC stream (ReadableStream
396
+ // above) must be wired up before hydrateRoot, because React starts
397
+ // consuming it synchronously during hydration.
398
+ //
399
+ // See design/19-client-navigation.md §"NavigationContext"
400
+ runPreHydration(element);
395
401
 
396
402
  // Hydrate on document — the root layout renders the full <html> tree,
397
403
  // so React owns the entire document from the root.
@@ -413,6 +419,15 @@ function bootstrap(runtimeConfig: typeof config): void {
413
419
  initial: wrapped,
414
420
  topLoaderConfig: _config.topLoader,
415
421
  });
422
+
423
+ if (process.env.NODE_ENV !== 'production') {
424
+ if (!getRouterOrNull()) {
425
+ throw new Error(
426
+ '[timber] hydrateRoot called before initRouter() — bootstrap order violated'
427
+ );
428
+ }
429
+ }
430
+
416
431
  _reactRoot = hydrateRoot(document, rootElement, {
417
432
  // Suppress recoverable hydration errors from deny/error signals
418
433
  // inside Suspense boundaries. The server already handled these
@@ -436,8 +451,27 @@ function bootstrap(runtimeConfig: typeof config): void {
436
451
  // navigation can still render RSC payloads. The initial SSR HTML
437
452
  // remains as-is; the first client navigation will replace it with
438
453
  // a React-managed tree.
439
- initRouter();
440
- _reactRoot = createRoot(document);
454
+ runPreHydration(null);
455
+ // Defer React root creation until first client navigation (TIM-600).
456
+ //
457
+ // We must NOT call createRoot(document).render() here — that would take
458
+ // React ownership of the entire document and blank the SSR HTML.
459
+ // Instead, installDeferredNavigation sets up one-shot callbacks so the
460
+ // first navigateTransition/transitionRender call creates the root on
461
+ // `document` with the navigated content. After that initial render,
462
+ // TransitionRoot's real startTransition-based callbacks take over.
463
+ //
464
+ // This also fixes TIM-580 (navigation from SSR-only pages) because the
465
+ // deferred callbacks ensure TransitionRoot is mounted before the first
466
+ // navigation completes.
467
+ installDeferredNavigation((initial) => {
468
+ const rootElement = createElement(TransitionRoot, {
469
+ initial,
470
+ topLoaderConfig: _config.topLoader,
471
+ });
472
+ _reactRoot = createRoot(document);
473
+ _reactRoot.render(rootElement);
474
+ });
441
475
  }
442
476
 
443
477
  // ── Router initialization (hoisted above hydrateRoot) ────────────────
@@ -552,6 +586,31 @@ function bootstrap(runtimeConfig: typeof config): void {
552
586
  setGlobalRouter(router);
553
587
  }
554
588
 
589
+ // ── Pre-hydration sequence ──────────────────────────────────────────
590
+ // Concentrates the ordering contract: initRouter → setParams/navState.
591
+ // Called before hydrateRoot in the hydration path. The createRoot path
592
+ // calls initRouter() directly (no params to read from server embed).
593
+ function runPreHydration(_element: unknown): void {
594
+ // Step 1: Initialize the router
595
+ initRouter();
596
+
597
+ // Step 2: Read server-embedded params and set navigation state
598
+ const earlyParams = (self as unknown as Record<string, unknown>).__timber_params;
599
+ if (earlyParams && typeof earlyParams === 'object') {
600
+ setCurrentParams(earlyParams as Record<string, string | string[]>);
601
+ setNavigationState({
602
+ params: earlyParams as Record<string, string | string[]>,
603
+ pathname: window.location.pathname,
604
+ });
605
+ delete (self as unknown as Record<string, unknown>).__timber_params;
606
+ } else {
607
+ setNavigationState({
608
+ params: {},
609
+ pathname: window.location.pathname,
610
+ });
611
+ }
612
+ }
613
+
555
614
  // Store the initial page in the history stack so back-button works
556
615
  // after the first navigation. We store the decoded RSC element so
557
616
  // back navigation can replay it instantly without a server fetch.
@@ -20,7 +20,7 @@ export type {
20
20
  export { useNavigationPending } from './use-navigation-pending';
21
21
  export { useLinkStatus, LinkStatusContext } from './use-link-status';
22
22
  export type { LinkStatus } from './use-link-status';
23
- export { getRouter, setGlobalRouter } from './router-ref';
23
+ export { getRouter, getRouterOrNull, setGlobalRouter } from './router-ref';
24
24
  export { useRouter } from './use-router';
25
25
  export type { AppRouterInstance } from './use-router';
26
26
  export { usePathname } from './use-pathname';
@@ -27,6 +27,7 @@ import {
27
27
  type MouseEvent as ReactMouseEvent,
28
28
  } from 'react';
29
29
  import type { SearchParamsDefinition } from '../search-params/define.js';
30
+ import { classifyUrlSegment, type UrlSegment } from '../routing/segment-classify.js';
30
31
  import { LinkStatusContext } from './use-link-status.js';
31
32
  import { getRouterOrNull } from './router-ref.js';
32
33
  import { getSsrData } from './ssr-data.js';
@@ -187,57 +188,91 @@ export function isInternalHref(href: string): boolean {
187
188
  * - [...param] → catch-all (joined with /)
188
189
  * - [[...param]] → optional catch-all (omitted if undefined/empty)
189
190
  */
191
+ /**
192
+ * Parse a route pattern's path portion into classified segments.
193
+ * Exported for testing. Uses the shared character-based classifier.
194
+ */
195
+ export function parseSegments(pattern: string): UrlSegment[] {
196
+ return pattern.split('/').filter(Boolean).map(classifyUrlSegment);
197
+ }
198
+
199
+ /**
200
+ * Resolve a single classified segment into its string representation.
201
+ * Returns null for optional catch-all with no value (filtered out before join).
202
+ */
203
+ function resolveSegment(
204
+ seg: UrlSegment,
205
+ params: Record<string, string | number | string[]>,
206
+ pattern: string
207
+ ): string | null {
208
+ switch (seg.kind) {
209
+ case 'static':
210
+ return seg.value;
211
+
212
+ case 'optional-catch-all': {
213
+ const value = params[seg.name];
214
+ if (value === undefined || (Array.isArray(value) && value.length === 0)) {
215
+ return null;
216
+ }
217
+ const segments = Array.isArray(value) ? value : [value];
218
+ return segments.map(encodeURIComponent).join('/');
219
+ }
220
+
221
+ case 'catch-all': {
222
+ const value = params[seg.name];
223
+ if (value === undefined) {
224
+ throw new Error(
225
+ `<Link> missing required catch-all param "${seg.name}" for pattern "${pattern}".`
226
+ );
227
+ }
228
+ const segments = Array.isArray(value) ? value : [value];
229
+ if (segments.length === 0) {
230
+ throw new Error(
231
+ `<Link> catch-all param "${seg.name}" must have at least one segment for pattern "${pattern}".`
232
+ );
233
+ }
234
+ return segments.map(encodeURIComponent).join('/');
235
+ }
236
+
237
+ case 'dynamic': {
238
+ const value = params[seg.name];
239
+ if (value === undefined) {
240
+ throw new Error(`<Link> missing required param "${seg.name}" for pattern "${pattern}".`);
241
+ }
242
+ if (Array.isArray(value)) {
243
+ throw new Error(
244
+ `<Link> param "${seg.name}" expected a string but received an array for pattern "${pattern}".`
245
+ );
246
+ }
247
+ return encodeURIComponent(String(value));
248
+ }
249
+ }
250
+ }
251
+
252
+ /**
253
+ * Split a URL pattern into the path portion and any trailing ?query/#hash suffix.
254
+ * Uses URL parsing for correctness rather than manual index arithmetic.
255
+ */
256
+ function splitPatternSuffix(pattern: string): [path: string, suffix: string] {
257
+ if (!pattern.includes('?') && !pattern.includes('#')) {
258
+ return [pattern, ''];
259
+ }
260
+ const url = new URL(pattern, 'http://x');
261
+ const suffix = url.search + url.hash;
262
+ const path = pattern.slice(0, pattern.length - suffix.length);
263
+ return [path, suffix];
264
+ }
265
+
190
266
  export function interpolateParams(
191
267
  pattern: string,
192
268
  params: Record<string, string | number | string[]>
193
269
  ): string {
194
- return (
195
- pattern
196
- .replace(
197
- /\[\[\.\.\.(\w+)\]\]|\[\.\.\.(\w+)\]|\[(\w+)\]/g,
198
- (_match, optionalCatchAll, catchAll, single) => {
199
- if (optionalCatchAll) {
200
- const value = params[optionalCatchAll];
201
- if (value === undefined || (Array.isArray(value) && value.length === 0)) {
202
- return '';
203
- }
204
- const segments = Array.isArray(value) ? value : [value];
205
- return segments.map(encodeURIComponent).join('/');
206
- }
207
-
208
- if (catchAll) {
209
- const value = params[catchAll];
210
- if (value === undefined) {
211
- throw new Error(
212
- `<Link> missing required catch-all param "${catchAll}" for pattern "${pattern}".`
213
- );
214
- }
215
- const segments = Array.isArray(value) ? value : [value];
216
- if (segments.length === 0) {
217
- throw new Error(
218
- `<Link> catch-all param "${catchAll}" must have at least one segment for pattern "${pattern}".`
219
- );
220
- }
221
- return segments.map(encodeURIComponent).join('/');
222
- }
270
+ const [pathPart, suffix] = splitPatternSuffix(pattern);
223
271
 
224
- // single dynamic segment
225
- const value = params[single];
226
- if (value === undefined) {
227
- throw new Error(`<Link> missing required param "${single}" for pattern "${pattern}".`);
228
- }
229
- if (Array.isArray(value)) {
230
- throw new Error(
231
- `<Link> param "${single}" expected a string but received an array for pattern "${pattern}".`
232
- );
233
- }
234
- // Accept numbers — coerce to string for URL interpolation
235
- return encodeURIComponent(String(value));
236
- }
237
- )
238
- // Clean up trailing slash from empty optional catch-all
239
- .replace(/\/+$/, '') || '/'
240
- );
272
+ const resolved = parseSegments(pathPart)
273
+ .map((seg) => resolveSegment(seg, params, pattern))
274
+ .filter((s): s is string => s !== null);
275
+ return ('/' + resolved.join('/') || '/') + suffix;
241
276
  }
242
277
 
243
278
  // ─── Resolve Href ───────────────────────────────────────────────
@@ -284,8 +284,10 @@ export async function fetchRscPayload(
284
284
  // Detect server 5xx errors. The server returns X-Timber-Error header
285
285
  // with a JSON body instead of a broken RSC stream. Hard-navigate so
286
286
  // the server renders the error page as HTML via the SSR-only path.
287
+ // Only trigger for 5xx — intentional 4xx RenderErrors (e.g., 403)
288
+ // should stay within SPA navigation, not force a full page reload.
287
289
  // See design/10-error-handling.md §"Error Page Rendering for Client Navigation"
288
- if (response.headers.get('X-Timber-Error') === '1') {
290
+ if (response.headers.get('X-Timber-Error') === '1' && response.status >= 500) {
289
291
  throw new ServerErrorResponse(response.status, url);
290
292
  }
291
293
  headElements = extractHeadElements(response);
@@ -104,8 +104,12 @@ export function triggerStaleReload(): boolean {
104
104
  return true;
105
105
  } catch {
106
106
  // sessionStorage unavailable (private browsing, storage full, etc.)
107
- // Use in-memory counter as fallback loop guard
108
- if (memoryReloadCount > 0) {
107
+ // Use document.cookie as a reload-persistent fallback loop guard.
108
+ // Module-level memoryReloadCount resets on every reload, so it can't
109
+ // detect cross-reload loops. Cookies persist across reloads and are
110
+ // available even when sessionStorage is blocked (TIM-576).
111
+ const cookieFlag = document.cookie.includes(RELOAD_FLAG_KEY + '=1');
112
+ if (cookieFlag || memoryReloadCount > 0) {
109
113
  console.warn(
110
114
  '[timber] Stale client reference detected again after reload. ' +
111
115
  'Not reloading to prevent infinite loop. ' +
@@ -115,6 +119,13 @@ export function triggerStaleReload(): boolean {
115
119
  }
116
120
 
117
121
  memoryReloadCount++;
122
+ // Set a short-lived cookie (60s) as the persistent loop guard.
123
+ // It auto-expires so it won't block future legitimate reloads.
124
+ try {
125
+ document.cookie = `${RELOAD_FLAG_KEY}=1; max-age=60; path=/; SameSite=Lax`;
126
+ } catch {
127
+ // Cookie API unavailable — proceed anyway, memoryReloadCount guards same-page loops
128
+ }
118
129
  console.warn(
119
130
  '[timber] Stale client reference detected — the server has been ' +
120
131
  'redeployed with new bundles. Reloading to pick up the new version.'
@@ -136,4 +147,10 @@ export function clearStaleReloadFlag(): void {
136
147
  } catch {
137
148
  // sessionStorage unavailable — nothing to clear
138
149
  }
150
+ // Also clear the cookie fallback
151
+ try {
152
+ document.cookie = `${RELOAD_FLAG_KEY}=; max-age=0; path=/; SameSite=Lax`;
153
+ } catch {
154
+ // Cookie API unavailable
155
+ }
139
156
  }