@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.
- package/dist/_chunks/{als-registry-Ba7URUIn.js → als-registry-BJARkOcu.js} +1 -1
- package/dist/_chunks/{als-registry-Ba7URUIn.js.map → als-registry-BJARkOcu.js.map} +1 -1
- package/dist/_chunks/{define-D5STJpIr.js → define-Djpqoe1K.js} +2 -2
- package/dist/_chunks/{define-D5STJpIr.js.map → define-Djpqoe1K.js.map} +1 -1
- package/dist/_chunks/{define-cookie-DtAavax4.js → define-cookie-B2djY9w0.js} +4 -4
- package/dist/_chunks/{define-cookie-DtAavax4.js.map → define-cookie-B2djY9w0.js.map} +1 -1
- package/dist/_chunks/{define-TK8C1M3x.js → define-hdajFTq7.js} +2 -2
- package/dist/_chunks/{define-TK8C1M3x.js.map → define-hdajFTq7.js.map} +1 -1
- package/dist/_chunks/{error-boundary-DpZJBCqh.js → error-boundary-A_sgyyUP.js} +1 -1
- package/dist/_chunks/{error-boundary-DpZJBCqh.js.map → error-boundary-A_sgyyUP.js.map} +1 -1
- package/dist/_chunks/{tracing-VYETCQsg.js → handler-store-CaE0ZgVG.js} +54 -3
- package/dist/_chunks/handler-store-CaE0ZgVG.js.map +1 -0
- package/dist/_chunks/{interception-Cey5DCGr.js → interception-BVm64Jr5.js} +7 -13
- package/dist/_chunks/interception-BVm64Jr5.js.map +1 -0
- package/dist/_chunks/{metadata-routes-BU684ls2.js → metadata-routes-DS3eKNmf.js} +1 -1
- package/dist/_chunks/{metadata-routes-BU684ls2.js.map → metadata-routes-DS3eKNmf.js.map} +1 -1
- package/dist/_chunks/{request-context-0wfZsnhh.js → request-context-B_u9dyhZ.js} +4 -4
- package/dist/_chunks/{request-context-0wfZsnhh.js.map → request-context-B_u9dyhZ.js.map} +1 -1
- package/dist/_chunks/segment-classify-BDNn6EzD.js +65 -0
- package/dist/_chunks/segment-classify-BDNn6EzD.js.map +1 -0
- package/dist/_chunks/{segment-context-CyaM1mrD.js → segment-context-CVRHlkkQ.js} +1 -1
- package/dist/_chunks/{segment-context-CyaM1mrD.js.map → segment-context-CVRHlkkQ.js.map} +1 -1
- package/dist/_chunks/{stale-reload-DKN3aXxR.js → stale-reload-BeyHXZ5B.js} +5 -2
- package/dist/_chunks/{stale-reload-DKN3aXxR.js.map → stale-reload-BeyHXZ5B.js.map} +1 -1
- package/dist/_chunks/{use-query-states-wEXY2JQB.js → use-query-states-DAhgj8Gx.js} +1 -1
- package/dist/_chunks/{use-query-states-wEXY2JQB.js.map → use-query-states-DAhgj8Gx.js.map} +1 -1
- package/dist/_chunks/{wrappers-BaG1bnM3.js → wrappers-CJQ3KwVr.js} +1 -1
- package/dist/_chunks/{wrappers-BaG1bnM3.js.map → wrappers-CJQ3KwVr.js.map} +1 -1
- package/dist/cache/cache-api.d.ts +24 -0
- package/dist/cache/cache-api.d.ts.map +1 -0
- package/dist/cache/handler-store.d.ts +31 -0
- package/dist/cache/handler-store.d.ts.map +1 -0
- package/dist/cache/index.d.ts +2 -1
- package/dist/cache/index.d.ts.map +1 -1
- package/dist/cache/index.js +33 -2
- package/dist/cache/index.js.map +1 -1
- package/dist/client/error-boundary.js +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +50 -21
- package/dist/client/index.js.map +1 -1
- package/dist/client/link.d.ts +6 -0
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/rsc-fetch.d.ts.map +1 -1
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/transition-root.d.ts +12 -0
- package/dist/client/transition-root.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -1
- package/dist/index.js +55 -3
- package/dist/index.js.map +1 -1
- package/dist/params/define.d.ts.map +1 -1
- package/dist/params/index.js +3 -3
- package/dist/plugins/dev-browser-logs.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/routing/index.d.ts +2 -0
- package/dist/routing/index.d.ts.map +1 -1
- package/dist/routing/index.js +3 -2
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/routing/segment-classify.d.ts +46 -0
- package/dist/routing/segment-classify.d.ts.map +1 -0
- package/dist/search-params/index.js +3 -3
- package/dist/server/actions.d.ts +0 -3
- package/dist/server/actions.d.ts.map +1 -1
- package/dist/server/deny-renderer.d.ts.map +1 -1
- package/dist/server/error-boundary-wrapper.d.ts.map +1 -1
- package/dist/server/fallback-error.d.ts.map +1 -1
- package/dist/server/index.js +100 -17
- package/dist/server/index.js.map +1 -1
- package/dist/server/pipeline-interception.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/rsc-entry/api-handler.d.ts.map +1 -1
- package/dist/server/rsc-entry/error-renderer.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-bridge.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/safe-load.d.ts +46 -0
- package/dist/server/safe-load.d.ts.map +1 -0
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/stream-utils.d.ts.map +1 -1
- package/dist/server/tracing.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cache/cache-api.ts +38 -0
- package/src/cache/handler-store.ts +68 -0
- package/src/cache/index.ts +2 -1
- package/src/client/browser-entry.ts +90 -31
- package/src/client/index.ts +1 -1
- package/src/client/link.tsx +81 -46
- package/src/client/rsc-fetch.ts +3 -1
- package/src/client/stale-reload.ts +19 -2
- package/src/client/transition-root.tsx +27 -0
- package/src/params/define.ts +11 -4
- package/src/plugins/dev-browser-logs.ts +10 -0
- package/src/plugins/entries.ts +61 -0
- package/src/plugins/routing.ts +1 -1
- package/src/routing/index.ts +2 -0
- package/src/routing/scanner.ts +7 -16
- package/src/routing/segment-classify.ts +89 -0
- package/src/server/actions.ts +7 -6
- package/src/server/deny-renderer.ts +4 -3
- package/src/server/error-boundary-wrapper.ts +9 -6
- package/src/server/fallback-error.ts +20 -7
- package/src/server/pipeline-interception.ts +16 -15
- package/src/server/pipeline.ts +20 -2
- package/src/server/route-element-builder.ts +5 -4
- package/src/server/rsc-entry/api-handler.ts +4 -3
- package/src/server/rsc-entry/error-renderer.ts +25 -10
- package/src/server/rsc-entry/index.ts +24 -0
- package/src/server/rsc-entry/rsc-payload.ts +1 -1
- package/src/server/rsc-entry/ssr-bridge.ts +13 -4
- package/src/server/rsc-entry/ssr-renderer.ts +12 -1
- package/src/server/safe-load.ts +60 -0
- package/src/server/slot-resolver.ts +3 -1
- package/src/server/stream-utils.ts +10 -6
- package/src/server/tracing.ts +14 -3
- package/dist/_chunks/interception-Cey5DCGr.js.map +0 -1
- 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;
|
|
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":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAY,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAiB,KAAK,YAAY,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -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;
|
|
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;
|
|
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;
|
|
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":"
|
|
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,
|
|
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,
|
|
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;
|
|
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,
|
|
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,
|
|
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.
|
|
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
|
+
}
|
package/src/cache/index.ts
CHANGED
|
@@ -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 {
|
|
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 {
|
|
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 {
|
|
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
|
-
// ──
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
//
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
//
|
|
377
|
-
//
|
|
378
|
-
// useSegmentParams() and usePathname()
|
|
379
|
-
//
|
|
380
|
-
//
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
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
|
-
|
|
440
|
-
|
|
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.
|
package/src/client/index.ts
CHANGED
|
@@ -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';
|
package/src/client/link.tsx
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
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 ───────────────────────────────────────────────
|
package/src/client/rsc-fetch.ts
CHANGED
|
@@ -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
|
|
108
|
-
|
|
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
|
}
|