@timber-js/app 0.1.48 → 0.1.50
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-c0AGnbqS.js → als-registry-k-AtAQ9R.js} +4 -2
- package/dist/_chunks/{als-registry-c0AGnbqS.js.map → als-registry-k-AtAQ9R.js.map} +1 -1
- package/dist/_chunks/interception-DGDIjDbR.js.map +1 -1
- package/dist/_chunks/{request-context-C69VW4xS.js → request-context-CRj2Zh1E.js} +2 -2
- package/dist/_chunks/request-context-CRj2Zh1E.js.map +1 -0
- package/dist/_chunks/{tracing-tIvqStk8.js → tracing-DF0G3FB7.js} +2 -2
- package/dist/_chunks/{tracing-tIvqStk8.js.map → tracing-DF0G3FB7.js.map} +1 -1
- package/dist/_chunks/use-query-states-DAhgj8Gx.js.map +1 -1
- package/dist/adapters/nitro.d.ts.map +1 -1
- package/dist/adapters/nitro.js +33 -6
- package/dist/adapters/nitro.js.map +1 -1
- package/dist/cache/index.js +2 -2
- package/dist/client/index.js.map +1 -1
- package/dist/client/navigation-context.d.ts +1 -1
- package/dist/client/navigation-context.d.ts.map +1 -1
- package/dist/client/router.d.ts.map +1 -1
- package/dist/client/transition-root.d.ts.map +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/client/use-router.d.ts.map +1 -1
- package/dist/cookies/index.js +2 -2
- package/dist/index.d.ts +8 -12
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +53 -10
- package/dist/index.js.map +1 -1
- package/dist/plugins/chunks.d.ts.map +1 -1
- package/dist/plugins/entries.d.ts +10 -0
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/routing/scanner.d.ts.map +1 -1
- package/dist/server/als-registry.d.ts +4 -0
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/index.js +39 -7
- package/dist/server/index.js.map +1 -1
- package/dist/server/metadata-platform.d.ts.map +1 -1
- package/dist/server/metadata-social.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/primitives.d.ts +8 -4
- package/dist/server/primitives.d.ts.map +1 -1
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts +1 -0
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- 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/rsc-prop-warnings.d.ts.map +1 -1
- package/dist/server/waituntil-bridge.d.ts +27 -0
- package/dist/server/waituntil-bridge.d.ts.map +1 -0
- package/package.json +2 -2
- package/src/adapters/nitro.ts +45 -9
- package/src/client/browser-entry.ts +80 -12
- package/src/client/navigation-context.ts +4 -1
- package/src/client/router.ts +5 -7
- package/src/client/transition-root.tsx +5 -11
- package/src/client/use-query-states.ts +4 -1
- package/src/client/use-router.ts +3 -1
- package/src/index.ts +8 -25
- package/src/plugins/chunks.ts +2 -1
- package/src/plugins/entries.ts +66 -2
- package/src/routing/scanner.ts +1 -4
- package/src/server/als-registry.ts +10 -0
- package/src/server/compress.ts +0 -1
- package/src/server/metadata-platform.ts +4 -1
- package/src/server/metadata-social.ts +4 -1
- package/src/server/pipeline.ts +6 -23
- package/src/server/primitives.ts +19 -9
- package/src/server/request-context.ts +1 -5
- package/src/server/rsc-entry/index.ts +16 -0
- package/src/server/rsc-entry/rsc-stream.ts +1 -4
- package/src/server/rsc-entry/ssr-renderer.ts +1 -3
- package/src/server/rsc-prop-warnings.ts +7 -17
- package/src/server/waituntil-bridge.ts +34 -0
- package/dist/_chunks/request-context-C69VW4xS.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata-platform.d.ts","sourceRoot":"","sources":["../../src/server/metadata-platform.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CA6ChG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAC/C,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CA+BN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,EACnD,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CAkBN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,WAAW,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,EACjD,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CAmCN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,EAC3C,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CAwCN;AAED;;GAEG;AACH,wBAAgB,YAAY,
|
|
1
|
+
{"version":3,"file":"metadata-platform.d.ts","sourceRoot":"","sources":["../../src/server/metadata-platform.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;GAEG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,WAAW,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CA6ChG;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC,CAAC,EAC/C,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CA+BN;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,YAAY,EAAE,WAAW,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC,EACnD,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CAkBN;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,WAAW,EAAE,WAAW,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC,EACjD,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CAmCN;AAED;;GAEG;AACH,wBAAgB,cAAc,CAC5B,QAAQ,EAAE,WAAW,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,EAC3C,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CAwCN;AAED;;GAEG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,EACvC,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CAQN"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata-social.d.ts","sourceRoot":"","sources":["../../src/server/metadata-social.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;GAKG;AACH,wBAAgB,eAAe,
|
|
1
|
+
{"version":3,"file":"metadata-social.d.ts","sourceRoot":"","sources":["../../src/server/metadata-social.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,EAAE,EAAE,WAAW,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC,EACtC,QAAQ,EAAE,WAAW,EAAE,GACtB,IAAI,CAoEN;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,EAAE,EAAE,WAAW,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CA0FjG"}
|
|
@@ -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":"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,CA4V1F"}
|
|
@@ -124,13 +124,17 @@ export interface WaitUntilAdapter {
|
|
|
124
124
|
* Register a promise to be kept alive after the response is sent.
|
|
125
125
|
* Maps to `ctx.waitUntil()` on Cloudflare Workers and similar platforms.
|
|
126
126
|
*
|
|
127
|
-
*
|
|
128
|
-
*
|
|
127
|
+
* In production, the platform adapter installs a per-request waitUntil
|
|
128
|
+
* function via ALS (see waituntil-bridge.ts). This function checks the
|
|
129
|
+
* ALS bridge first, then falls back to the legacy adapter argument.
|
|
130
|
+
*
|
|
131
|
+
* If neither is available, a warning is logged once and the promise is
|
|
132
|
+
* left to resolve (or reject) without being tracked.
|
|
129
133
|
*
|
|
130
134
|
* @param promise - The background work to keep alive.
|
|
131
|
-
* @param adapter -
|
|
135
|
+
* @param adapter - Optional legacy adapter (prefer ALS bridge in production).
|
|
132
136
|
*/
|
|
133
|
-
export declare function waitUntil(promise: Promise<unknown>, adapter
|
|
137
|
+
export declare function waitUntil(promise: Promise<unknown>, adapter?: WaitUntilAdapter): void;
|
|
134
138
|
/**
|
|
135
139
|
* Reset the waitUntil warning state. Exported for testing only.
|
|
136
140
|
* @internal
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"primitives.d.ts","sourceRoot":"","sources":["../../src/server/primitives.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAKnD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,SAAS,GAAG,MAAM,GAAG,IAAI,CA8DhF;AAsBD;;;GAGG;AACH,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,gBAAgB,GAAG,SAAS,CAAC;gBAEhC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,gBAAgB;IAOnD;;;;OAIG;IACH,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAqBnC;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,IAAI,CAAC,MAAM,GAAE,MAAY,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,KAAK,CASzE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,KAAK,CAEhC;AAED;;;;;;GAMG;AACH,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAIX;;;GAGG;AACH,qBAAa,cAAe,SAAQ,KAAK;IACvC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAM7C;AAKD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAY,GAAG,KAAK,CAWlE;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAErD;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,EAAE,MAAM,GAAE,MAAY,GAAG,KAAK,CAoB9F;AAID;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAChC,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,gBAAgB,GAAG,gBAAgB;IAEjD,IAAI,EAAE,KAAK,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC;CACb;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,WAAW,CACtB,KAAK,SAAS,MAAM,GAAG,MAAM,EAC7B,KAAK,SAAS,gBAAgB,GAAG,gBAAgB,CACjD,SAAQ,KAAK;IACb,QAAQ,CAAC,IAAI,EAAE,KAAK,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;IACjD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;gBAEZ,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;CAcpE;AAID,mEAAmE;AACnE,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;CAC7C;AAMD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAqBrF;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,IAAI,CAE7C;AAID;;;;;;;;;;GAUG;AACH,qBAAa,cAAe,SAAQ,KAAK;aAGrB,KAAK,EAAE,OAAO;gBAD9B,OAAO,EAAE,MAAM,EACC,KAAK,EAAE,OAAO;CAKjC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AACzC,OAAO,
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function setDevPipelineErrorHandler(handler: (error: Error, phase: string) => void): void;
|
|
8
8
|
export { runWithEarlyHintsSender } from '#/server/early-hints-sender.js';
|
|
9
|
+
export { runWithWaitUntil } from '#/server/waituntil-bridge.js';
|
|
9
10
|
declare const _default: (req: Request) => Promise<Response>;
|
|
10
11
|
export default _default;
|
|
11
12
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -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":"AA0EA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;AAwXD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;AAIzE,OAAO,EAAE,gBAAgB,EAAE,MAAM,8BAA8B,CAAC;8BA5P3C,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AA8PhD,wBAAiE"}
|
|
@@ -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;AAKjF;;;;;GAKG;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;CACxD;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,
|
|
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;AAKjF;;;;;GAKG;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;CACxD;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,CA8G1F"}
|
|
@@ -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,CA+JjF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"rsc-prop-warnings.d.ts","sourceRoot":"","sources":["../../src/server/rsc-prop-warnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;
|
|
1
|
+
{"version":3,"file":"rsc-prop-warnings.d.ts","sourceRoot":"","sources":["../../src/server/rsc-prop-warnings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAIH,MAAM,WAAW,uBAAuB;IACtC,wEAAwE;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,iCAAiC;IACjC,UAAU,EAAE,MAAM,CAAC;CACpB;AAkFD;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,YAAY,EAAE,MAAM,GAAG,uBAAuB,GAAG,IAAI,CAU9F;AAED;;;;;;;;GAQG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,uBAAuB,EAC7B,WAAW,CAAC,EAAE,MAAM,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB,MAAM,CAeR;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAUrF"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-request waitUntil bridge — ALS bridge for platform adapters.
|
|
3
|
+
*
|
|
4
|
+
* The generated entry point (Nitro, Cloudflare) wraps the handler with
|
|
5
|
+
* `runWithWaitUntil`, binding the platform's lifecycle extension function
|
|
6
|
+
* (e.g., h3's `event.waitUntil()` or CF's `ctx.waitUntil()`) for the
|
|
7
|
+
* request duration. The `waitUntil()` primitive reads from this ALS to
|
|
8
|
+
* dispatch background work to the correct platform API.
|
|
9
|
+
*
|
|
10
|
+
* Design doc: design/11-platform.md §"waitUntil()"
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Run a function with a per-request waitUntil handler installed.
|
|
14
|
+
*
|
|
15
|
+
* Called by generated entry points (Nitro node-server/bun, Cloudflare)
|
|
16
|
+
* to bind the platform's lifecycle extension for the request duration.
|
|
17
|
+
*/
|
|
18
|
+
export declare function runWithWaitUntil<T>(waitUntilFn: (promise: Promise<unknown>) => void, fn: () => T): T;
|
|
19
|
+
/**
|
|
20
|
+
* Get the current request's waitUntil function, if available.
|
|
21
|
+
*
|
|
22
|
+
* Returns undefined when no platform adapter has installed a waitUntil
|
|
23
|
+
* handler for the current request (e.g., on platforms that don't support
|
|
24
|
+
* lifecycle extension, or outside a request context).
|
|
25
|
+
*/
|
|
26
|
+
export declare function getWaitUntil(): ((promise: Promise<unknown>) => void) | undefined;
|
|
27
|
+
//# sourceMappingURL=waituntil-bridge.d.ts.map
|
|
@@ -0,0 +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,EAAE,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAEpG;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.1.
|
|
3
|
+
"version": "0.1.50",
|
|
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",
|
|
@@ -88,7 +88,7 @@
|
|
|
88
88
|
"@opentelemetry/api": "^1.9.0",
|
|
89
89
|
"@opentelemetry/context-async-hooks": "^2.6.0",
|
|
90
90
|
"@opentelemetry/sdk-trace-base": "^2.6.0",
|
|
91
|
-
"nitro": "
|
|
91
|
+
"nitro": "3.0.260311-beta"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
94
|
"@content-collections/core": "^0.14.0",
|
package/src/adapters/nitro.ts
CHANGED
|
@@ -273,7 +273,7 @@ export function generateNitroEntry(
|
|
|
273
273
|
buildDir: string,
|
|
274
274
|
outDir: string,
|
|
275
275
|
preset: NitroPreset,
|
|
276
|
-
hasManifestInit = false
|
|
276
|
+
hasManifestInit = false
|
|
277
277
|
): string {
|
|
278
278
|
// The RSC entry is the main request handler — it exports the fetch handler as default.
|
|
279
279
|
// rsc/ is copied into the nitro dir so the import is local.
|
|
@@ -282,31 +282,67 @@ export function generateNitroEntry(
|
|
|
282
282
|
const serverEntryRelative = './rsc/index.js';
|
|
283
283
|
const runtimeName = PRESET_CONFIGS[preset].runtimeName;
|
|
284
284
|
const earlyHints = PRESET_CONFIGS[preset].supportsEarlyHints;
|
|
285
|
+
const supportsWaitUntil = PRESET_CONFIGS[preset].supportsWaitUntil;
|
|
285
286
|
|
|
286
287
|
// On node-server and bun, wrap the handler with ALS so the pipeline
|
|
287
288
|
// can send 103 Early Hints via res.writeEarlyHints(). Other presets
|
|
288
289
|
// either don't support 103 or handle it at the CDN level.
|
|
289
|
-
|
|
290
|
-
|
|
290
|
+
//
|
|
291
|
+
// For presets that support waitUntil, bridge h3's event.waitUntil()
|
|
292
|
+
// to timber's waitUntil() primitive via the ALS bridge.
|
|
293
|
+
// See design/11-platform.md §"waitUntil()".
|
|
294
|
+
let handlerCall: string;
|
|
295
|
+
if (earlyHints && supportsWaitUntil) {
|
|
296
|
+
handlerCall = ` const nodeRes = event.node?.res
|
|
297
|
+
const earlyHintsSender = (typeof nodeRes?.writeEarlyHints === 'function')
|
|
298
|
+
? (links) => { try { nodeRes.writeEarlyHints({ link: links }) } catch {} }
|
|
299
|
+
: undefined
|
|
300
|
+
|
|
301
|
+
const waitUntilFn = (typeof event.waitUntil === 'function')
|
|
302
|
+
? (p) => event.waitUntil(p)
|
|
303
|
+
: undefined
|
|
304
|
+
|
|
305
|
+
const callHandler = () => handler(webRequest)
|
|
306
|
+
let wrappedHandler = earlyHintsSender
|
|
307
|
+
? () => runWithEarlyHintsSender(earlyHintsSender, callHandler)
|
|
308
|
+
: callHandler
|
|
309
|
+
const webResponse = waitUntilFn
|
|
310
|
+
? await runWithWaitUntil(waitUntilFn, wrappedHandler)
|
|
311
|
+
: await wrappedHandler()`;
|
|
312
|
+
} else if (earlyHints) {
|
|
313
|
+
handlerCall = ` const nodeRes = event.node?.res
|
|
291
314
|
const earlyHintsSender = (typeof nodeRes?.writeEarlyHints === 'function')
|
|
292
315
|
? (links) => { try { nodeRes.writeEarlyHints({ link: links }) } catch {} }
|
|
293
316
|
: undefined
|
|
294
317
|
|
|
295
318
|
const webResponse = earlyHintsSender
|
|
296
319
|
? await runWithEarlyHintsSender(earlyHintsSender, () => handler(webRequest))
|
|
297
|
-
: await handler(webRequest)
|
|
298
|
-
|
|
320
|
+
: await handler(webRequest)`;
|
|
321
|
+
} else if (supportsWaitUntil) {
|
|
322
|
+
handlerCall = ` const waitUntilFn = (typeof event.waitUntil === 'function')
|
|
323
|
+
? (p) => event.waitUntil(p)
|
|
324
|
+
: undefined
|
|
325
|
+
|
|
326
|
+
const webResponse = waitUntilFn
|
|
327
|
+
? await runWithWaitUntil(waitUntilFn, () => handler(webRequest))
|
|
328
|
+
: await handler(webRequest)`;
|
|
329
|
+
} else {
|
|
330
|
+
handlerCall = ` const webResponse = await handler(webRequest)`;
|
|
331
|
+
}
|
|
299
332
|
|
|
300
333
|
// Build manifest init must be imported before the handler so that
|
|
301
334
|
// globalThis.__TIMBER_BUILD_MANIFEST__ is set when the virtual module evaluates.
|
|
302
335
|
// ESM guarantees imports are evaluated in order.
|
|
303
336
|
const manifestImport = hasManifestInit ? "import './_timber-manifest-init.js'\n" : '';
|
|
304
337
|
|
|
338
|
+
// Import runWithWaitUntil only when the preset supports it.
|
|
339
|
+
const waitUntilImport = supportsWaitUntil ? ', runWithWaitUntil' : '';
|
|
340
|
+
|
|
305
341
|
return `// Generated by @timber-js/app/adapters/nitro
|
|
306
342
|
// Do not edit — this file is regenerated on each build.
|
|
307
343
|
|
|
308
|
-
${manifestImport}import { defineEventHandler } from '
|
|
309
|
-
import handler, { runWithEarlyHintsSender } from '${serverEntryRelative}'
|
|
344
|
+
${manifestImport}import { defineEventHandler } from 'h3'
|
|
345
|
+
import handler, { runWithEarlyHintsSender${waitUntilImport} } from '${serverEntryRelative}'
|
|
310
346
|
import { compressResponse } from './_compress.mjs'
|
|
311
347
|
|
|
312
348
|
// Set TIMBER_RUNTIME for instrumentation.ts conditional SDK initialization.
|
|
@@ -571,7 +607,7 @@ async function runNitroBuild(
|
|
|
571
607
|
userConfig?: Record<string, unknown>
|
|
572
608
|
): Promise<void> {
|
|
573
609
|
const presetConfig = PRESET_CONFIGS[preset];
|
|
574
|
-
const { createNitro, build: nitroBuild, prepare, copyPublicAssets } = await import('nitro');
|
|
610
|
+
const { createNitro, build: nitroBuild, prepare, copyPublicAssets } = await import('nitro/builder');
|
|
575
611
|
|
|
576
612
|
const nitro = await createNitro({
|
|
577
613
|
rootDir: nitroDir,
|
|
@@ -579,7 +615,7 @@ async function runNitroBuild(
|
|
|
579
615
|
// Use renderer.entry so Nitro wraps our handler with its server runtime
|
|
580
616
|
// (HTTP server, static file serving, graceful shutdown, etc.).
|
|
581
617
|
// Using `entry` directly would bypass the Nitro server runtime.
|
|
582
|
-
renderer: {
|
|
618
|
+
renderer: { handler: join(nitroDir, 'entry.ts') },
|
|
583
619
|
output: { dir: join(nitroDir, presetConfig.outputDir) },
|
|
584
620
|
routeRules: {
|
|
585
621
|
'/assets/**': { headers: { 'Cache-Control': IMMUTABLE_CACHE } },
|
|
@@ -36,12 +36,7 @@ import {
|
|
|
36
36
|
// If we used relative imports (./router-ref.js), Vite would load separate src/
|
|
37
37
|
// copies with separate module-level state — e.g., globalRouter set here but
|
|
38
38
|
// read as null from the dist/ copy used by useRouter().
|
|
39
|
-
import {
|
|
40
|
-
createRouter,
|
|
41
|
-
setGlobalRouter,
|
|
42
|
-
getRouter,
|
|
43
|
-
setCurrentParams,
|
|
44
|
-
} from '@timber-js/app/client';
|
|
39
|
+
import { createRouter, setGlobalRouter, getRouter, setCurrentParams } from '@timber-js/app/client';
|
|
45
40
|
import type { RouterDeps, RouterInstance } from '@timber-js/app/client';
|
|
46
41
|
|
|
47
42
|
// Internal-only modules (no shared mutable state with user code) use relative
|
|
@@ -49,7 +44,11 @@ import type { RouterDeps, RouterInstance } from '@timber-js/app/client';
|
|
|
49
44
|
import { applyHeadElements } from './head.js';
|
|
50
45
|
import { TimberNuqsAdapter } from './nuqs-adapter.js';
|
|
51
46
|
import { isPageUnloading } from './unload-guard.js';
|
|
52
|
-
import {
|
|
47
|
+
import {
|
|
48
|
+
NavigationProvider,
|
|
49
|
+
getNavigationState,
|
|
50
|
+
setNavigationState,
|
|
51
|
+
} from './navigation-context.js';
|
|
53
52
|
import { setupServerLogReplay, setupClientErrorForwarding } from './browser-dev.js';
|
|
54
53
|
import { handleLinkClick, handleLinkHover } from './browser-links.js';
|
|
55
54
|
import { TransitionRoot, transitionRender, navigateTransition } from './transition-root.js';
|
|
@@ -153,9 +152,58 @@ function getScrollY(): number {
|
|
|
153
152
|
for (const el of document.querySelectorAll('[data-timber-scroll-restoration]')) {
|
|
154
153
|
if ((el as HTMLElement).scrollTop > 0) return (el as HTMLElement).scrollTop;
|
|
155
154
|
}
|
|
155
|
+
// Auto-detect: if window isn't scrolled, check for overflow containers.
|
|
156
|
+
// Common pattern: layouts use a scrollable div (overflow-y: auto/scroll)
|
|
157
|
+
// inside a fixed-height parent (h-screen). In this case window.scrollY is
|
|
158
|
+
// always 0 and the real scroll position lives on the overflow container.
|
|
159
|
+
const container = findOverflowContainer();
|
|
160
|
+
if (container && container.scrollTop > 0) return container.scrollTop;
|
|
156
161
|
return 0;
|
|
157
162
|
}
|
|
158
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Find the primary overflow scroll container in the document.
|
|
166
|
+
*
|
|
167
|
+
* Walks direct children of body and their immediate children looking for
|
|
168
|
+
* an element with overflow-y: auto|scroll that is actually scrollable
|
|
169
|
+
* (scrollHeight > clientHeight). Returns the first match, or null.
|
|
170
|
+
*
|
|
171
|
+
* This heuristic covers the common layout patterns:
|
|
172
|
+
* <body> → <html-wrapper> → <div class="overflow-y-auto">
|
|
173
|
+
* <body> → <main class="overflow-y-auto">
|
|
174
|
+
*
|
|
175
|
+
* We limit depth to avoid expensive full-tree traversals.
|
|
176
|
+
*
|
|
177
|
+
* DIVERGENCE FROM NEXT.JS: Next.js's ScrollAndFocusHandler scrolls only
|
|
178
|
+
* document.documentElement.scrollTop — it does NOT handle overflow containers.
|
|
179
|
+
* Layouts using h-screen + overflow-y-auto have the same scroll bug in Next.js.
|
|
180
|
+
* This heuristic is a deliberate improvement. The tradeoff is fragility: depth-2
|
|
181
|
+
* traversal may miss deeply nested containers or match the wrong element.
|
|
182
|
+
* See design/19-client-navigation.md §"Overflow Scroll Containers".
|
|
183
|
+
*/
|
|
184
|
+
function findOverflowContainer(): HTMLElement | null {
|
|
185
|
+
const candidates: HTMLElement[] = [];
|
|
186
|
+
// Check body's direct children and their children (depth 2)
|
|
187
|
+
for (const child of document.body.children) {
|
|
188
|
+
candidates.push(child as HTMLElement);
|
|
189
|
+
for (const grandchild of child.children) {
|
|
190
|
+
candidates.push(grandchild as HTMLElement);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
for (const el of candidates) {
|
|
194
|
+
if (!(el instanceof HTMLElement)) continue;
|
|
195
|
+
const style = getComputedStyle(el);
|
|
196
|
+
const overflowY = style.overflowY;
|
|
197
|
+
if (
|
|
198
|
+
(overflowY === 'auto' || overflowY === 'scroll') &&
|
|
199
|
+
el.scrollHeight > el.clientHeight
|
|
200
|
+
) {
|
|
201
|
+
return el;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return null;
|
|
205
|
+
}
|
|
206
|
+
|
|
159
207
|
function bootstrap(runtimeConfig: typeof config): void {
|
|
160
208
|
const _config = runtimeConfig;
|
|
161
209
|
|
|
@@ -308,7 +356,11 @@ function bootstrap(runtimeConfig: typeof config): void {
|
|
|
308
356
|
// startTransition, so React keeps old UI visible while new Suspense
|
|
309
357
|
// boundaries resolve during navigation. See design/05-streaming.md.
|
|
310
358
|
const navState = getNavigationState();
|
|
311
|
-
const withNav = createElement(
|
|
359
|
+
const withNav = createElement(
|
|
360
|
+
NavigationProvider,
|
|
361
|
+
{ value: navState },
|
|
362
|
+
element as React.ReactNode
|
|
363
|
+
);
|
|
312
364
|
const wrapped = createElement(TimberNuqsAdapter, null, withNav);
|
|
313
365
|
const rootElement = createElement(TransitionRoot, { initial: wrapped });
|
|
314
366
|
_reactRoot = hydrateRoot(document, rootElement, {
|
|
@@ -356,6 +408,16 @@ function bootstrap(runtimeConfig: typeof config): void {
|
|
|
356
408
|
for (const el of document.querySelectorAll('[data-timber-scroll-restoration]')) {
|
|
357
409
|
(el as HTMLElement).scrollTop = y;
|
|
358
410
|
}
|
|
411
|
+
// Auto-detect overflow containers for layouts that scroll inside
|
|
412
|
+
// a fixed-height wrapper (e.g., h-screen + overflow-y-auto).
|
|
413
|
+
// In these layouts, window.scrollY is always 0 and the real scroll
|
|
414
|
+
// lives on the overflow container. Without this, forward navigation
|
|
415
|
+
// between pages that share a layout with parallel route slots won't
|
|
416
|
+
// scroll to top — the router's window.scrollTo(0,0) is a no-op.
|
|
417
|
+
const container = findOverflowContainer();
|
|
418
|
+
if (container) {
|
|
419
|
+
container.scrollTop = y;
|
|
420
|
+
}
|
|
359
421
|
},
|
|
360
422
|
getCurrentUrl: () => window.location.pathname + window.location.search,
|
|
361
423
|
getScrollY,
|
|
@@ -376,7 +438,11 @@ function bootstrap(runtimeConfig: typeof config): void {
|
|
|
376
438
|
// in a React transition with useOptimistic for the pending URL.
|
|
377
439
|
renderRoot: (element: unknown) => {
|
|
378
440
|
const navState = getNavigationState();
|
|
379
|
-
const withNav = createElement(
|
|
441
|
+
const withNav = createElement(
|
|
442
|
+
NavigationProvider,
|
|
443
|
+
{ value: navState },
|
|
444
|
+
element as React.ReactNode
|
|
445
|
+
);
|
|
380
446
|
const wrapped = createElement(TimberNuqsAdapter, null, withNav);
|
|
381
447
|
transitionRender(wrapped);
|
|
382
448
|
},
|
|
@@ -394,7 +460,11 @@ function bootstrap(runtimeConfig: typeof config): void {
|
|
|
394
460
|
return navigateTransition(pendingUrl, async () => {
|
|
395
461
|
const payload = await perform((rawPayload: unknown) => {
|
|
396
462
|
const navState = getNavigationState();
|
|
397
|
-
const withNav = createElement(
|
|
463
|
+
const withNav = createElement(
|
|
464
|
+
NavigationProvider,
|
|
465
|
+
{ value: navState },
|
|
466
|
+
rawPayload as React.ReactNode
|
|
467
|
+
);
|
|
398
468
|
return createElement(TimberNuqsAdapter, null, withNav);
|
|
399
469
|
});
|
|
400
470
|
return payload as React.ReactNode;
|
|
@@ -542,8 +612,6 @@ function bootstrap(runtimeConfig: typeof config): void {
|
|
|
542
612
|
}
|
|
543
613
|
}
|
|
544
614
|
|
|
545
|
-
|
|
546
|
-
|
|
547
615
|
bootstrap(config);
|
|
548
616
|
|
|
549
617
|
// Signal that the client runtime has been initialized.
|
|
@@ -106,7 +106,10 @@ export interface NavigationProviderProps {
|
|
|
106
106
|
* Used in browser-entry.ts renderRoot to wrap the RSC payload element
|
|
107
107
|
* so that navigation state updates atomically with the tree render.
|
|
108
108
|
*/
|
|
109
|
-
export function NavigationProvider({
|
|
109
|
+
export function NavigationProvider({
|
|
110
|
+
value,
|
|
111
|
+
children,
|
|
112
|
+
}: NavigationProviderProps): React.ReactElement {
|
|
110
113
|
const ctx = getOrCreateContext();
|
|
111
114
|
if (!ctx) {
|
|
112
115
|
// RSC environment — no context available. Return children as-is.
|
package/src/client/router.ts
CHANGED
|
@@ -67,7 +67,7 @@ export interface RouterDeps {
|
|
|
67
67
|
*/
|
|
68
68
|
navigateTransition?: (
|
|
69
69
|
pendingUrl: string,
|
|
70
|
-
perform: (wrapPayload: (payload: unknown) => unknown) => Promise<unknown
|
|
70
|
+
perform: (wrapPayload: (payload: unknown) => unknown) => Promise<unknown>
|
|
71
71
|
) => Promise<void>;
|
|
72
72
|
}
|
|
73
73
|
|
|
@@ -359,9 +359,7 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
359
359
|
// Module-level fallback for tests (no NavigationProvider) and SSR
|
|
360
360
|
setCurrentParams(resolvedParams);
|
|
361
361
|
// Navigation context — read by renderRoot to wrap the RSC element
|
|
362
|
-
const pathname = url.startsWith('http')
|
|
363
|
-
? new URL(url).pathname
|
|
364
|
-
: url.split('?')[0] || '/';
|
|
362
|
+
const pathname = url.startsWith('http') ? new URL(url).pathname : url.split('?')[0] || '/';
|
|
365
363
|
setNavigationState({ params: resolvedParams, pathname });
|
|
366
364
|
}
|
|
367
365
|
|
|
@@ -373,7 +371,7 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
373
371
|
*/
|
|
374
372
|
async function renderViaTransition(
|
|
375
373
|
pendingUrl: string,
|
|
376
|
-
perform: () => Promise<FetchResult
|
|
374
|
+
perform: () => Promise<FetchResult>
|
|
377
375
|
): Promise<HeadElement[] | null> {
|
|
378
376
|
if (deps.navigateTransition) {
|
|
379
377
|
let headElements: HeadElement[] | null = null;
|
|
@@ -412,7 +410,7 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
412
410
|
*/
|
|
413
411
|
async function performNavigationFetch(
|
|
414
412
|
url: string,
|
|
415
|
-
options: { replace: boolean }
|
|
413
|
+
options: { replace: boolean }
|
|
416
414
|
): Promise<FetchResult> {
|
|
417
415
|
// Check prefetch cache first. PrefetchResult has optional segmentInfo/params
|
|
418
416
|
// fields — normalize to null for FetchResult compatibility.
|
|
@@ -476,7 +474,7 @@ export function createRouter(deps: RouterDeps): RouterInstance {
|
|
|
476
474
|
|
|
477
475
|
try {
|
|
478
476
|
const headElements = await renderViaTransition(url, () =>
|
|
479
|
-
performNavigationFetch(url, { replace })
|
|
477
|
+
performNavigationFetch(url, { replace })
|
|
480
478
|
);
|
|
481
479
|
|
|
482
480
|
// Update document.title and <meta> tags with the new page's metadata
|
|
@@ -22,12 +22,7 @@
|
|
|
22
22
|
* See design/19-client-navigation.md §"NavigationContext"
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import {
|
|
26
|
-
useState,
|
|
27
|
-
useTransition,
|
|
28
|
-
createElement,
|
|
29
|
-
type ReactNode,
|
|
30
|
-
} from 'react';
|
|
25
|
+
import { useState, useTransition, createElement, type ReactNode } from 'react';
|
|
31
26
|
import { PendingNavigationProvider } from './navigation-context.js';
|
|
32
27
|
|
|
33
28
|
// ─── Module-level functions ──────────────────────────────────────
|
|
@@ -43,10 +38,9 @@ let _transitionRender: ((element: ReactNode) => void) | null = null;
|
|
|
43
38
|
* Wraps a full navigation (fetch + render) in a single startTransition
|
|
44
39
|
* with useOptimistic for the pending URL.
|
|
45
40
|
*/
|
|
46
|
-
let _navigateTransition:
|
|
47
|
-
pendingUrl: string,
|
|
48
|
-
|
|
49
|
-
) => Promise<void>) | null = null;
|
|
41
|
+
let _navigateTransition:
|
|
42
|
+
| ((pendingUrl: string, perform: () => Promise<ReactNode>) => Promise<void>)
|
|
43
|
+
| null = null;
|
|
50
44
|
|
|
51
45
|
// ─── Component ───────────────────────────────────────────────────
|
|
52
46
|
|
|
@@ -140,7 +134,7 @@ export function transitionRender(element: ReactNode): void {
|
|
|
140
134
|
*/
|
|
141
135
|
export function navigateTransition(
|
|
142
136
|
pendingUrl: string,
|
|
143
|
-
perform: () => Promise<ReactNode
|
|
137
|
+
perform: () => Promise<ReactNode>
|
|
144
138
|
): Promise<void> {
|
|
145
139
|
if (_navigateTransition) {
|
|
146
140
|
return _navigateTransition(pendingUrl, perform);
|
|
@@ -106,7 +106,10 @@ export function useQueryStates<T extends Record<string, unknown>>(
|
|
|
106
106
|
try {
|
|
107
107
|
[values, setValues] = nuqsUseQueryStates(bridged, nuqsOptions);
|
|
108
108
|
} catch (err) {
|
|
109
|
-
if (
|
|
109
|
+
if (
|
|
110
|
+
err instanceof Error &&
|
|
111
|
+
/Invalid hook call|cannot be called|Cannot read properties of null/i.test(err.message)
|
|
112
|
+
) {
|
|
110
113
|
throw new Error(
|
|
111
114
|
'useQueryStates is a client component hook and cannot be called outside a React component. ' +
|
|
112
115
|
'Use definition.parse(searchParams) in server components instead.'
|
package/src/client/use-router.ts
CHANGED
|
@@ -63,7 +63,9 @@ export function useRouter(): AppRouterInstance {
|
|
|
63
63
|
const router = getRouterOrNull();
|
|
64
64
|
if (!router) {
|
|
65
65
|
if (process.env.NODE_ENV === 'development') {
|
|
66
|
-
console.error(
|
|
66
|
+
console.error(
|
|
67
|
+
'[timber] useRouter().push() called but router is not initialized. This is a bug — please report it.'
|
|
68
|
+
);
|
|
67
69
|
}
|
|
68
70
|
return;
|
|
69
71
|
}
|
package/src/index.ts
CHANGED
|
@@ -61,16 +61,6 @@ export interface TimberUserConfig {
|
|
|
61
61
|
* Server-side JS still runs — this only affects what is sent to the browser.
|
|
62
62
|
*/
|
|
63
63
|
clientJavascript?: boolean | ClientJavascriptConfig;
|
|
64
|
-
/**
|
|
65
|
-
* @deprecated Use `clientJavascript: false` or `clientJavascript: { disabled: true }` instead.
|
|
66
|
-
*
|
|
67
|
-
* Disable all client-side JavaScript output. When true, no client JS
|
|
68
|
-
* bundles are emitted or referenced in HTML. Pages work entirely via
|
|
69
|
-
* server-rendered HTML. Works in both 'server' and 'static' modes.
|
|
70
|
-
*
|
|
71
|
-
* Server-side JS still runs — this only affects what is sent to the browser.
|
|
72
|
-
*/
|
|
73
|
-
noClientJavascript?: boolean;
|
|
74
64
|
adapter?: unknown;
|
|
75
65
|
cacheHandler?: unknown;
|
|
76
66
|
allowedOrigins?: string[];
|
|
@@ -81,6 +71,13 @@ export interface TimberUserConfig {
|
|
|
81
71
|
maxFields?: number;
|
|
82
72
|
};
|
|
83
73
|
pageExtensions?: string[];
|
|
74
|
+
/**
|
|
75
|
+
* Slow request threshold in milliseconds. Requests exceeding this emit
|
|
76
|
+
* a warning via the logger. Set to 0 to disable. Default: 3000.
|
|
77
|
+
*
|
|
78
|
+
* See design/17-logging.md §"slowRequestMs".
|
|
79
|
+
*/
|
|
80
|
+
slowRequestMs?: number;
|
|
84
81
|
/** Dev-mode options. These have no effect in production builds. */
|
|
85
82
|
dev?: {
|
|
86
83
|
/** Threshold in ms to highlight slow phases in dev logging output. Default: 200. */
|
|
@@ -116,11 +113,9 @@ export interface TimberUserConfig {
|
|
|
116
113
|
}
|
|
117
114
|
|
|
118
115
|
/**
|
|
119
|
-
* Resolve `clientJavascript`
|
|
120
|
-
* a fully resolved config. Emits a deprecation warning for the old option.
|
|
116
|
+
* Resolve `clientJavascript` into a fully resolved config.
|
|
121
117
|
*/
|
|
122
118
|
export function resolveClientJavascript(config: TimberUserConfig): ResolvedClientJavascript {
|
|
123
|
-
// New option takes precedence over deprecated option
|
|
124
119
|
if (config.clientJavascript !== undefined) {
|
|
125
120
|
if (typeof config.clientJavascript === 'boolean') {
|
|
126
121
|
// `clientJavascript: false` → disabled
|
|
@@ -137,18 +132,6 @@ export function resolveClientJavascript(config: TimberUserConfig): ResolvedClien
|
|
|
137
132
|
};
|
|
138
133
|
}
|
|
139
134
|
|
|
140
|
-
// Fall back to deprecated noClientJavascript
|
|
141
|
-
if (config.noClientJavascript !== undefined) {
|
|
142
|
-
console.warn(
|
|
143
|
-
'[timber] `noClientJavascript` is deprecated. ' +
|
|
144
|
-
'Use `clientJavascript: false` or `clientJavascript: { disabled: true, enableHMRInDev: true }` instead.'
|
|
145
|
-
);
|
|
146
|
-
return {
|
|
147
|
-
disabled: config.noClientJavascript,
|
|
148
|
-
enableHMRInDev: config.noClientJavascript, // default true when disabled
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
|
|
152
135
|
// Default: client JS enabled
|
|
153
136
|
return { disabled: false, enableHMRInDev: false };
|
|
154
137
|
}
|
package/src/plugins/chunks.ts
CHANGED
|
@@ -181,7 +181,8 @@ export function assignClientChunk(meta: {
|
|
|
181
181
|
}): string | undefined {
|
|
182
182
|
// Timber framework client modules → vendor-timber
|
|
183
183
|
// Match both monorepo paths (/timber-app/) and consumer paths (/@timber-js/app/)
|
|
184
|
-
if (meta.id.includes('/timber-app/') || meta.id.includes('/@timber-js/app/'))
|
|
184
|
+
if (meta.id.includes('/timber-app/') || meta.id.includes('/@timber-js/app/'))
|
|
185
|
+
return 'vendor-timber';
|
|
185
186
|
|
|
186
187
|
// Small user client components → shared-client (prevents facade micro-chunks)
|
|
187
188
|
if (!meta.id.includes('\0') && meta.id.startsWith('/')) {
|