@timber-js/app 0.2.0-alpha.7 → 0.2.0-alpha.9
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/{tracing-Cwn7697K.js → tracing-CemImE6h.js} +16 -2
- package/dist/_chunks/{tracing-Cwn7697K.js.map → tracing-CemImE6h.js.map} +1 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/fast-hash.d.ts +22 -0
- package/dist/cache/fast-hash.d.ts.map +1 -0
- package/dist/cache/index.js +51 -9
- package/dist/cache/index.js.map +1 -1
- package/dist/cache/register-cached-function.d.ts.map +1 -1
- package/dist/cache/timber-cache.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/client/link.d.ts.map +1 -1
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/segment-context.d.ts +1 -1
- package/dist/client/segment-context.d.ts.map +1 -1
- package/dist/client/segment-merger.d.ts.map +1 -1
- package/dist/client/stale-reload.d.ts.map +1 -1
- package/dist/client/top-loader.d.ts.map +1 -1
- package/dist/client/transition-root.d.ts +1 -1
- package/dist/client/transition-root.d.ts.map +1 -1
- package/dist/index.d.ts +0 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +38 -34
- package/dist/index.js.map +1 -1
- package/dist/plugins/fonts.d.ts +7 -0
- package/dist/plugins/fonts.d.ts.map +1 -1
- package/dist/server/action-client.d.ts.map +1 -1
- package/dist/server/index.js +9 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/response-cache.d.ts +5 -4
- package/dist/server/response-cache.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-payload.d.ts.map +1 -1
- package/dist/server/rsc-entry/rsc-stream.d.ts +6 -0
- package/dist/server/rsc-entry/rsc-stream.d.ts.map +1 -1
- package/dist/server/rsc-entry/ssr-renderer.d.ts.map +1 -1
- package/dist/server/tracing.d.ts +10 -0
- package/dist/server/tracing.d.ts.map +1 -1
- package/dist/server/waituntil-bridge.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/adapters/nitro.ts +6 -1
- package/src/cache/fast-hash.ts +34 -0
- package/src/cache/register-cached-function.ts +7 -3
- package/src/cache/timber-cache.ts +17 -10
- package/src/client/browser-entry.ts +10 -6
- package/src/client/link.tsx +14 -9
- package/src/client/router.ts +4 -6
- package/src/client/segment-context.ts +6 -1
- package/src/client/segment-merger.ts +2 -8
- package/src/client/stale-reload.ts +4 -6
- package/src/client/top-loader.tsx +8 -7
- package/src/client/transition-root.tsx +7 -1
- package/src/index.ts +1 -2
- package/src/plugins/entries.ts +1 -1
- package/src/plugins/fonts.ts +54 -43
- package/src/server/action-client.ts +7 -1
- package/src/server/pipeline.ts +7 -0
- package/src/server/response-cache.ts +169 -36
- package/src/server/route-element-builder.ts +1 -6
- package/src/server/rsc-entry/index.ts +9 -6
- package/src/server/rsc-entry/rsc-payload.ts +42 -10
- package/src/server/rsc-entry/rsc-stream.ts +9 -5
- package/src/server/rsc-entry/ssr-renderer.ts +11 -8
- package/src/server/tracing.ts +23 -0
- package/src/server/waituntil-bridge.ts +4 -1
|
@@ -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;AAgC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,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,2BAA2B,EAAE,mBAAmB,EAAE,CAAC;IACjF;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;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;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,
|
|
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;AAgC1E,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAItD,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,2BAA2B,EAAE,mBAAmB,EAAE,CAAC;IACjF;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B;;;;;;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;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAmW1F"}
|
|
@@ -10,10 +10,11 @@
|
|
|
10
10
|
* re-executing the RSC-to-SSR pipeline. Entries have a short TTL
|
|
11
11
|
* (default 5s) and the cache has a bounded size (default 150 entries).
|
|
12
12
|
*
|
|
13
|
-
* Cache keys are compound:
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
13
|
+
* Cache keys are compound: pathname + search + isRscPayload + Vary'd headers.
|
|
14
|
+
* Only GET requests are cached. Responses with Set-Cookie, Cache-Control:
|
|
15
|
+
* no-store/private, or error/redirect status codes are never cached.
|
|
16
|
+
* When `publicOnly` is true (default), requests with Cookie or Authorization
|
|
17
|
+
* headers bypass the cache entirely.
|
|
17
18
|
*
|
|
18
19
|
* See design/02-rendering-pipeline.md, design/31-benchmarking.md.
|
|
19
20
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/server/response-cache.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"response-cache.d.ts","sourceRoot":"","sources":["../../src/server/response-cache.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH,MAAM,WAAW,mBAAmB;IAClC,gEAAgE;IAChE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,kEAAkE;IAClE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;CACrB;AAED,wBAAgB,0BAA0B,CACxC,MAAM,CAAC,EAAE,mBAAmB,GAAG,KAAK,GACnC,2BAA2B,GAAG,IAAI,CASpC;AA+ED,MAAM,WAAW,aAAa;IAC5B;;;OAGG;IACH,WAAW,CACT,GAAG,EAAE,OAAO,EACZ,YAAY,EAAE,OAAO,EACrB,QAAQ,EAAE,MAAM,OAAO,CAAC,QAAQ,CAAC,GAChC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAErB,oDAAoD;IACpD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,gCAAgC;IAChC,KAAK,IAAI,IAAI,CAAC;CACf;AAuDD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,2BAA2B,GAAG,aAAa,CAyMtF"}
|
|
@@ -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;AAO7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAKzD,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;AAID;;;;;;;;;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,
|
|
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;AAO7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAKzD,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;AAID;;;;;;;;;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,CAsW7B"}
|
|
@@ -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":"AAkFA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;AAiaD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;8BArQ3C,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AAuQhD,wBAAiE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-payload.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAQrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,YAAY,EAAE,WAAW,EAAE,EAC3B,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"rsc-payload.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-payload.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC3F,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAQrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;GAQG;AACH,wBAAsB,uBAAuB,CAC3C,GAAG,EAAE,OAAO,EACZ,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,OAAO,EAAE,aAAa,EACtB,QAAQ,EAAE,mBAAmB,EAAE,EAC/B,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,YAAY,EAAE,WAAW,EAAE,EAC3B,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,eAAe,CAAC,EAAE,MAAM,EAAE,GACzB,OAAO,CAAC,QAAQ,CAAC,CA0HnB"}
|
|
@@ -15,6 +15,10 @@ import { DenySignal, RedirectSignal } from '#/server/primitives.js';
|
|
|
15
15
|
*
|
|
16
16
|
* Signals fire asynchronously via `onError` during stream consumption.
|
|
17
17
|
* The first signal of each type wins — subsequent signals are ignored.
|
|
18
|
+
*
|
|
19
|
+
* `onSignal` is an optional callback fired when a DenySignal or
|
|
20
|
+
* RedirectSignal is captured. Consumers use it with Promise.race to
|
|
21
|
+
* react immediately instead of polling with setTimeout/queueMicrotask.
|
|
18
22
|
*/
|
|
19
23
|
export interface RenderSignals {
|
|
20
24
|
denySignal: DenySignal | null;
|
|
@@ -23,6 +27,8 @@ export interface RenderSignals {
|
|
|
23
27
|
error: unknown;
|
|
24
28
|
status: number;
|
|
25
29
|
} | null;
|
|
30
|
+
/** Callback fired when a redirect or deny signal is captured in onError. */
|
|
31
|
+
onSignal?: () => void;
|
|
26
32
|
}
|
|
27
33
|
export interface RscStreamResult {
|
|
28
34
|
rscStream: ReadableStream<Uint8Array> | undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAMjF
|
|
1
|
+
{"version":3,"file":"rsc-stream.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/rsc-stream.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,UAAU,EAAE,cAAc,EAAe,MAAM,wBAAwB,CAAC;AAMjF;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,UAAU,GAAG,IAAI,CAAC;IAC9B,cAAc,EAAE,cAAc,GAAG,IAAI,CAAC;IACtC,WAAW,EAAE;QAAE,KAAK,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACvD,4EAA4E;IAC5E,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAED,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,GAAG,SAAS,CAAC;IAClD,OAAO,EAAE,aAAa,CAAC;CACxB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,GAAG,EAAE,OAAO,GAAG,eAAe,CA4G1F"}
|
|
@@ -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,4BAA4B,CAAC;AAGxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAYrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,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;CAC1B;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,4BAA4B,CAAC;AAGxE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,2BAA2B,CAAC;AAYrE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAErD,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;CAC1B;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,iBAAiB,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAsKjF"}
|
package/dist/server/tracing.d.ts
CHANGED
|
@@ -84,6 +84,16 @@ export declare function setSpanAttribute(key: string, value: string | number | b
|
|
|
84
84
|
* Used for timber.cache HIT/MISS events — recorded as span events, not child spans.
|
|
85
85
|
*/
|
|
86
86
|
export declare function addSpanEvent(name: string, attributes?: Record<string, string | number | boolean>): Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Fire-and-forget span event — no await, no microtask overhead.
|
|
89
|
+
*
|
|
90
|
+
* Used on the cache hot path where awaiting addSpanEvent creates an
|
|
91
|
+
* unnecessary microtask per cache operation. If OTEL is not loaded yet,
|
|
92
|
+
* the event is silently dropped (acceptable for diagnostics).
|
|
93
|
+
*
|
|
94
|
+
* See TIM-370 for perf motivation.
|
|
95
|
+
*/
|
|
96
|
+
export declare function addSpanEventSync(name: string, attributes?: Record<string, string | number | boolean>): void;
|
|
87
97
|
/**
|
|
88
98
|
* Try to extract the OTEL trace ID from the current active span context.
|
|
89
99
|
* Returns undefined if OTEL is not active or no span exists.
|
|
@@ -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;;;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,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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"waituntil-bridge.d.ts","sourceRoot":"","sources":["../../src/server/waituntil-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"waituntil-bridge.d.ts","sourceRoot":"","sources":["../../src/server/waituntil-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAChC,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,EAChD,EAAE,EAAE,MAAM,CAAC,GACV,CAAC,CAEH;AAED;;;;;;GAMG;AACH,wBAAgB,YAAY,IAAI,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC,GAAG,SAAS,CAEhF"}
|
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.9",
|
|
4
4
|
"description": "Vite-native React framework for Cloudflare Workers — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
package/src/adapters/nitro.ts
CHANGED
|
@@ -611,7 +611,12 @@ async function runNitroBuild(
|
|
|
611
611
|
userConfig?: Record<string, unknown>
|
|
612
612
|
): Promise<void> {
|
|
613
613
|
const presetConfig = PRESET_CONFIGS[preset];
|
|
614
|
-
const {
|
|
614
|
+
const {
|
|
615
|
+
createNitro,
|
|
616
|
+
build: nitroBuild,
|
|
617
|
+
prepare,
|
|
618
|
+
copyPublicAssets,
|
|
619
|
+
} = await import('nitro/builder');
|
|
615
620
|
|
|
616
621
|
const nitro = await createNitro({
|
|
617
622
|
rootDir: nitroDir,
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fast non-cryptographic hash for cache keys.
|
|
3
|
+
*
|
|
4
|
+
* FNV-1a 64-bit produces a well-distributed hash with a collision
|
|
5
|
+
* probability of ~1 in 5 billion at 77k keys (birthday paradox).
|
|
6
|
+
* Not suitable for security, but ideal for cache key generation
|
|
7
|
+
* where we need speed over crypto strength.
|
|
8
|
+
*
|
|
9
|
+
* Uses BigInt for 64-bit arithmetic — supported in all modern runtimes
|
|
10
|
+
* including Cloudflare Workers. No node:crypto dependency.
|
|
11
|
+
*
|
|
12
|
+
* See TIM-370.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
// FNV-1a constants for 64-bit hash
|
|
16
|
+
const FNV_OFFSET_BASIS = 0xcbf29ce484222325n;
|
|
17
|
+
const FNV_PRIME = 0x100000001b3n;
|
|
18
|
+
const MASK_64 = 0xffffffffffffffffn;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Compute a 64-bit FNV-1a hash of a string, returned as a 16-char hex string.
|
|
22
|
+
*
|
|
23
|
+
* 64 bits gives ~5 billion keys before a 50% collision probability
|
|
24
|
+
* (birthday paradox), making accidental collisions effectively impossible
|
|
25
|
+
* for cache key use cases.
|
|
26
|
+
*/
|
|
27
|
+
export function fnv1aHash(input: string): string {
|
|
28
|
+
let hash = FNV_OFFSET_BASIS;
|
|
29
|
+
for (let i = 0; i < input.length; i++) {
|
|
30
|
+
hash ^= BigInt(input.charCodeAt(i));
|
|
31
|
+
hash = (hash * FNV_PRIME) & MASK_64;
|
|
32
|
+
}
|
|
33
|
+
return hash.toString(16).padStart(16, '0');
|
|
34
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
import type { CacheHandler } from './index';
|
|
3
2
|
import { stableStringify } from './stable-stringify';
|
|
4
3
|
import { createSingleflight } from './singleflight';
|
|
4
|
+
import { fnv1aHash } from './fast-hash.js';
|
|
5
5
|
|
|
6
6
|
const singleflight = createSingleflight();
|
|
7
7
|
|
|
@@ -27,11 +27,15 @@ export interface RegisterCachedFunctionOptions<Fn extends (...args: any[]) => an
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/**
|
|
30
|
-
* Generate a
|
|
30
|
+
* Generate a cache key from a stable function ID and serialized args.
|
|
31
|
+
*
|
|
32
|
+
* Uses FNV-1a (fast non-crypto hash) instead of SHA-256. The id prefix
|
|
33
|
+
* provides namespace isolation; the hash covers the args.
|
|
34
|
+
* See TIM-370.
|
|
31
35
|
*/
|
|
32
36
|
function generateKey(id: string, args: unknown[]): string {
|
|
33
37
|
const raw = id + ':' + stableStringify(args);
|
|
34
|
-
return
|
|
38
|
+
return id + ':' + fnv1aHash(raw);
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
/**
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
-
import { createHash } from 'node:crypto';
|
|
2
1
|
import type { CacheHandler, CacheOptions } from './index';
|
|
3
2
|
import { stableStringify } from './stable-stringify';
|
|
4
3
|
import { createSingleflight } from './singleflight';
|
|
5
|
-
import {
|
|
4
|
+
import { addSpanEventSync } from '#/server/tracing.js';
|
|
5
|
+
import { fnv1aHash } from './fast-hash.js';
|
|
6
6
|
|
|
7
7
|
const singleflight = createSingleflight();
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Generate a
|
|
10
|
+
* Generate a cache key from function identity and serialized args.
|
|
11
|
+
*
|
|
12
|
+
* Uses FNV-1a (fast non-crypto hash) instead of SHA-256. Cache keys don't
|
|
13
|
+
* need collision resistance — they need speed. The fnId prefix provides
|
|
14
|
+
* namespace isolation; the hash covers the args.
|
|
15
|
+
*
|
|
16
|
+
* See TIM-370 for perf motivation.
|
|
11
17
|
*/
|
|
12
18
|
function defaultKeyGenerator(fnId: string, args: unknown[]): string {
|
|
13
19
|
const raw = fnId + ':' + stableStringify(args);
|
|
14
|
-
return
|
|
20
|
+
return fnId + ':' + fnv1aHash(raw);
|
|
15
21
|
}
|
|
16
22
|
|
|
17
23
|
/**
|
|
@@ -57,8 +63,9 @@ export function createCache<Fn extends (...args: any[]) => Promise<any>>(
|
|
|
57
63
|
const cached = await handler.get(key);
|
|
58
64
|
|
|
59
65
|
if (cached && !cached.stale) {
|
|
60
|
-
// Record as OTEL span event on enclosing span (not a child span)
|
|
61
|
-
|
|
66
|
+
// Record as OTEL span event on enclosing span (not a child span).
|
|
67
|
+
// Fire-and-forget — no microtask overhead on the cache hot path.
|
|
68
|
+
addSpanEventSync('timber.cache.hit', {
|
|
62
69
|
key,
|
|
63
70
|
duration_ms: Math.round(performance.now() - cacheStart),
|
|
64
71
|
});
|
|
@@ -66,8 +73,8 @@ export function createCache<Fn extends (...args: any[]) => Promise<any>>(
|
|
|
66
73
|
}
|
|
67
74
|
|
|
68
75
|
if (cached && cached.stale && opts.staleWhileRevalidate) {
|
|
69
|
-
// Record stale cache hit as OTEL span event
|
|
70
|
-
|
|
76
|
+
// Record stale cache hit as OTEL span event (fire-and-forget).
|
|
77
|
+
addSpanEventSync('timber.cache.hit', {
|
|
71
78
|
key,
|
|
72
79
|
duration_ms: Math.round(performance.now() - cacheStart),
|
|
73
80
|
stale: true,
|
|
@@ -95,8 +102,8 @@ export function createCache<Fn extends (...args: any[]) => Promise<any>>(
|
|
|
95
102
|
const tags = resolveTags(opts, args);
|
|
96
103
|
await handler.set(key, result, { ttl: opts.ttl, tags });
|
|
97
104
|
|
|
98
|
-
// Record cache miss as OTEL span event
|
|
99
|
-
|
|
105
|
+
// Record cache miss as OTEL span event (fire-and-forget).
|
|
106
|
+
addSpanEventSync('timber.cache.miss', {
|
|
100
107
|
key,
|
|
101
108
|
duration_ms: Math.round(performance.now() - cacheStart),
|
|
102
109
|
});
|
|
@@ -52,7 +52,11 @@ import { setupServerLogReplay, setupClientErrorForwarding } from './browser-dev.
|
|
|
52
52
|
// browser-links.ts removed — Link components own their click/hover handlers directly.
|
|
53
53
|
// See LOCAL-340.
|
|
54
54
|
import { TransitionRoot, transitionRender, navigateTransition } from './transition-root.js';
|
|
55
|
-
import {
|
|
55
|
+
import {
|
|
56
|
+
isStaleClientReference,
|
|
57
|
+
triggerStaleReload,
|
|
58
|
+
clearStaleReloadFlag,
|
|
59
|
+
} from './stale-reload.js';
|
|
56
60
|
|
|
57
61
|
// ─── Server Action Dispatch ──────────────────────────────────────
|
|
58
62
|
|
|
@@ -213,10 +217,7 @@ function findOverflowContainer(): HTMLElement | null {
|
|
|
213
217
|
if (!(el instanceof HTMLElement)) continue;
|
|
214
218
|
const style = getComputedStyle(el);
|
|
215
219
|
const overflowY = style.overflowY;
|
|
216
|
-
if (
|
|
217
|
-
(overflowY === 'auto' || overflowY === 'scroll') &&
|
|
218
|
-
el.scrollHeight > el.clientHeight
|
|
219
|
-
) {
|
|
220
|
+
if ((overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight) {
|
|
220
221
|
return el;
|
|
221
222
|
}
|
|
222
223
|
}
|
|
@@ -381,7 +382,10 @@ function bootstrap(runtimeConfig: typeof config): void {
|
|
|
381
382
|
element as React.ReactNode
|
|
382
383
|
);
|
|
383
384
|
const wrapped = createElement(TimberNuqsAdapter, null, withNav);
|
|
384
|
-
const rootElement = createElement(TransitionRoot, {
|
|
385
|
+
const rootElement = createElement(TransitionRoot, {
|
|
386
|
+
initial: wrapped,
|
|
387
|
+
topLoaderConfig: _config.topLoader,
|
|
388
|
+
});
|
|
385
389
|
_reactRoot = hydrateRoot(document, rootElement, {
|
|
386
390
|
// Suppress recoverable hydration errors from deny/error signals
|
|
387
391
|
// inside Suspense boundaries. The server already handled these
|
package/src/client/link.tsx
CHANGED
|
@@ -335,7 +335,11 @@ export function Link({
|
|
|
335
335
|
// Call onNavigate if provided — allows caller to cancel
|
|
336
336
|
if (onNavigate) {
|
|
337
337
|
let prevented = false;
|
|
338
|
-
onNavigate({
|
|
338
|
+
onNavigate({
|
|
339
|
+
preventDefault: () => {
|
|
340
|
+
prevented = true;
|
|
341
|
+
},
|
|
342
|
+
});
|
|
339
343
|
if (prevented) {
|
|
340
344
|
event.preventDefault();
|
|
341
345
|
return;
|
|
@@ -352,15 +356,16 @@ export function Link({
|
|
|
352
356
|
: userOnClick; // External links — just pass through user's onClick
|
|
353
357
|
|
|
354
358
|
// ─── Hover prefetch ──────────────────────────────────────────
|
|
355
|
-
const handleMouseEnter =
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
router
|
|
359
|
+
const handleMouseEnter =
|
|
360
|
+
internal && prefetch
|
|
361
|
+
? (event: ReactMouseEvent<HTMLAnchorElement>) => {
|
|
362
|
+
userOnMouseEnter?.(event);
|
|
363
|
+
const router = getRouterOrNull();
|
|
364
|
+
if (router) {
|
|
365
|
+
router.prefetch(resolvedHref);
|
|
366
|
+
}
|
|
361
367
|
}
|
|
362
|
-
|
|
363
|
-
: userOnMouseEnter;
|
|
368
|
+
: userOnMouseEnter;
|
|
364
369
|
|
|
365
370
|
return (
|
|
366
371
|
<a {...rest} href={resolvedHref} onClick={handleClick} onMouseEnter={handleMouseEnter}>
|
package/src/client/router.ts
CHANGED
|
@@ -7,11 +7,7 @@ import { HistoryStack } from './history';
|
|
|
7
7
|
import type { HeadElement } from './head';
|
|
8
8
|
import { setCurrentParams } from './use-params.js';
|
|
9
9
|
import { setNavigationState } from './navigation-context.js';
|
|
10
|
-
import {
|
|
11
|
-
SegmentElementCache,
|
|
12
|
-
cacheSegmentElements,
|
|
13
|
-
mergeSegmentTree,
|
|
14
|
-
} from './segment-merger.js';
|
|
10
|
+
import { SegmentElementCache, cacheSegmentElements, mergeSegmentTree } from './segment-merger.js';
|
|
15
11
|
import { fetchRscPayload, RedirectError } from './rsc-fetch.js';
|
|
16
12
|
import type { FetchResult } from './rsc-fetch.js';
|
|
17
13
|
|
|
@@ -421,7 +417,9 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
421
417
|
setPending(true, url);
|
|
422
418
|
try {
|
|
423
419
|
const headElements = await renderViaTransition(url, async () => {
|
|
424
|
-
const stateTree = segmentCache.serializeStateTree(
|
|
420
|
+
const stateTree = segmentCache.serializeStateTree(
|
|
421
|
+
segmentElementCache.getMergeablePaths()
|
|
422
|
+
);
|
|
425
423
|
const result = await fetchRscPayload(url, deps, stateTree);
|
|
426
424
|
updateSegmentCache(result.segmentInfo);
|
|
427
425
|
updateNavigationState(result.params, url);
|
|
@@ -52,7 +52,12 @@ interface SegmentProviderProps {
|
|
|
52
52
|
* Wraps each layout to provide segment position context.
|
|
53
53
|
* Injected by rsc-entry.ts during element tree construction.
|
|
54
54
|
*/
|
|
55
|
-
export function SegmentProvider({
|
|
55
|
+
export function SegmentProvider({
|
|
56
|
+
segments,
|
|
57
|
+
segmentId: _segmentId,
|
|
58
|
+
parallelRouteKeys,
|
|
59
|
+
children,
|
|
60
|
+
}: SegmentProviderProps) {
|
|
56
61
|
const value = useMemo(
|
|
57
62
|
() => ({ segments, parallelRouteKeys }),
|
|
58
63
|
// segments and parallelRouteKeys are static per layout — they don't change
|
|
@@ -186,10 +186,7 @@ function walkChildren(children: ReactNode, out: CachedSegmentEntry[]): void {
|
|
|
186
186
|
* Cache all segment subtrees from a fully-rendered RSC element tree.
|
|
187
187
|
* Call this after every full RSC payload render (navigate, refresh, hydration).
|
|
188
188
|
*/
|
|
189
|
-
export function cacheSegmentElements(
|
|
190
|
-
element: unknown,
|
|
191
|
-
cache: SegmentElementCache
|
|
192
|
-
): void {
|
|
189
|
+
export function cacheSegmentElements(element: unknown, cache: SegmentElementCache): void {
|
|
193
190
|
const segments = extractSegments(element);
|
|
194
191
|
for (const entry of segments) {
|
|
195
192
|
cache.set(entry.segmentPath, entry);
|
|
@@ -208,10 +205,7 @@ export function cacheSegmentElements(
|
|
|
208
205
|
*/
|
|
209
206
|
type TreePath = Array<{ element: ReactElement; childIndex: number }>;
|
|
210
207
|
|
|
211
|
-
function findSegmentProviderPath(
|
|
212
|
-
node: ReactElement,
|
|
213
|
-
targetPath?: string
|
|
214
|
-
): TreePath | null {
|
|
208
|
+
function findSegmentProviderPath(node: ReactElement, targetPath?: string): TreePath | null {
|
|
215
209
|
const children = (node.props as { children?: ReactNode }).children;
|
|
216
210
|
if (children == null) return null;
|
|
217
211
|
|
|
@@ -48,8 +48,8 @@ export function triggerStaleReload(): boolean {
|
|
|
48
48
|
if (sessionStorage.getItem(RELOAD_FLAG_KEY)) {
|
|
49
49
|
console.warn(
|
|
50
50
|
'[timber] Stale client reference detected again after reload. ' +
|
|
51
|
-
|
|
52
|
-
|
|
51
|
+
'Not reloading to prevent infinite loop. ' +
|
|
52
|
+
'This may indicate a deployment issue — try a hard refresh.'
|
|
53
53
|
);
|
|
54
54
|
return false;
|
|
55
55
|
}
|
|
@@ -59,7 +59,7 @@ export function triggerStaleReload(): boolean {
|
|
|
59
59
|
|
|
60
60
|
console.warn(
|
|
61
61
|
'[timber] Stale client reference detected — the server has been ' +
|
|
62
|
-
|
|
62
|
+
'redeployed with new bundles. Reloading to pick up the new version.'
|
|
63
63
|
);
|
|
64
64
|
|
|
65
65
|
window.location.reload();
|
|
@@ -67,9 +67,7 @@ export function triggerStaleReload(): boolean {
|
|
|
67
67
|
} catch {
|
|
68
68
|
// sessionStorage may be unavailable (private browsing, storage full, etc.)
|
|
69
69
|
// Fall back to reloading without loop protection
|
|
70
|
-
console.warn(
|
|
71
|
-
'[timber] Stale client reference detected. Reloading page.'
|
|
72
|
-
);
|
|
70
|
+
console.warn('[timber] Stale client reference detected. Reloading page.');
|
|
73
71
|
window.location.reload();
|
|
74
72
|
return true;
|
|
75
73
|
}
|
|
@@ -183,18 +183,19 @@ export function TopLoader({ config }: { config?: TopLoaderConfig }): React.React
|
|
|
183
183
|
};
|
|
184
184
|
|
|
185
185
|
// Clean up the finishing phase when the finish animation completes.
|
|
186
|
-
const handleAnimationEnd =
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
186
|
+
const handleAnimationEnd =
|
|
187
|
+
phase === 'finishing'
|
|
188
|
+
? (e: React.AnimationEvent) => {
|
|
189
|
+
if (e.animationName === FINISH_KEYFRAMES) {
|
|
190
|
+
setPhase('hidden');
|
|
191
|
+
}
|
|
190
192
|
}
|
|
191
|
-
|
|
192
|
-
: undefined;
|
|
193
|
+
: undefined;
|
|
193
194
|
|
|
194
195
|
return createElement(
|
|
195
196
|
'div',
|
|
196
197
|
{
|
|
197
|
-
style: containerStyle,
|
|
198
|
+
'style': containerStyle,
|
|
198
199
|
'aria-hidden': 'true',
|
|
199
200
|
'data-timber-top-loader': '',
|
|
200
201
|
},
|
|
@@ -62,7 +62,13 @@ let _navigateTransition:
|
|
|
62
62
|
* Non-navigation renders:
|
|
63
63
|
* transitionRender(newWrappedElement);
|
|
64
64
|
*/
|
|
65
|
-
export function TransitionRoot({
|
|
65
|
+
export function TransitionRoot({
|
|
66
|
+
initial,
|
|
67
|
+
topLoaderConfig,
|
|
68
|
+
}: {
|
|
69
|
+
initial: ReactNode;
|
|
70
|
+
topLoaderConfig?: TopLoaderConfig;
|
|
71
|
+
}): ReactNode {
|
|
66
72
|
const [element, setElement] = useState<ReactNode>(initial);
|
|
67
73
|
const [pendingUrl, setPendingUrl] = useState<string | null>(null);
|
|
68
74
|
const [, startTransition] = useTransition();
|
package/src/index.ts
CHANGED
|
@@ -223,8 +223,7 @@ export interface PluginContext {
|
|
|
223
223
|
buildManifest: BuildManifest | null;
|
|
224
224
|
/** Startup timer for profiling cold start phases (active in dev, no-op in prod) */
|
|
225
225
|
timer: StartupTimer;
|
|
226
|
-
|
|
227
|
-
fontCssUrl?: string;
|
|
226
|
+
|
|
228
227
|
}
|
|
229
228
|
|
|
230
229
|
/**
|
package/src/plugins/entries.ts
CHANGED