@timber-js/app 0.1.10 → 0.1.12
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/request-context-BzES06i1.js.map +1 -1
- package/dist/_chunks/ssr-data-BgSwMbN9.js +38 -0
- package/dist/_chunks/ssr-data-BgSwMbN9.js.map +1 -0
- package/dist/_chunks/{use-cookie-HcvNlW4L.js → use-cookie-D2cZu0jK.js} +3 -37
- package/dist/_chunks/use-cookie-D2cZu0jK.js.map +1 -0
- package/dist/_chunks/use-query-states-wEXY2JQB.js +109 -0
- package/dist/_chunks/use-query-states-wEXY2JQB.js.map +1 -0
- package/dist/client/error-boundary.d.ts.map +1 -1
- package/dist/client/error-boundary.js +8 -0
- package/dist/client/error-boundary.js.map +1 -1
- package/dist/client/index.js +3 -84
- package/dist/client/index.js.map +1 -1
- package/dist/client/ssr-data.d.ts +9 -0
- package/dist/client/ssr-data.d.ts.map +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/cookies/index.js +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -12
- package/dist/index.js.map +1 -1
- package/dist/plugins/entries.d.ts.map +1 -1
- package/dist/plugins/routing.d.ts.map +1 -1
- package/dist/plugins/server-bundle.d.ts.map +1 -1
- package/dist/plugins/shims.d.ts.map +1 -1
- package/dist/routing/status-file-lint.d.ts.map +1 -1
- package/dist/search-params/create.d.ts.map +1 -1
- package/dist/search-params/index.js +13 -4
- package/dist/search-params/index.js.map +1 -1
- package/dist/server/fallback-error.d.ts +28 -0
- package/dist/server/fallback-error.d.ts.map +1 -0
- package/dist/server/html-injectors.d.ts.map +1 -1
- package/dist/server/index.js +13 -10
- package/dist/server/index.js.map +1 -1
- package/dist/server/pipeline.d.ts +12 -0
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-matcher.d.ts.map +1 -1
- package/dist/server/rsc-entry/index.d.ts.map +1 -1
- package/dist/server/slot-resolver.d.ts +1 -1
- package/dist/server/slot-resolver.d.ts.map +1 -1
- package/dist/server/ssr-entry.d.ts +7 -0
- package/dist/server/ssr-entry.d.ts.map +1 -1
- package/dist/server/tree-builder.d.ts +10 -0
- package/dist/server/tree-builder.d.ts.map +1 -1
- package/package.json +23 -23
- package/src/client/browser-entry.ts +1 -1
- package/src/client/error-boundary.tsx +22 -0
- package/src/client/ssr-data.ts +7 -0
- package/src/client/use-query-states.ts +13 -1
- package/src/index.ts +16 -16
- package/src/plugins/dev-server.ts +3 -1
- package/src/plugins/entries.ts +2 -1
- package/src/plugins/routing.ts +5 -4
- package/src/plugins/server-bundle.ts +15 -6
- package/src/plugins/shims.ts +8 -14
- package/src/routing/status-file-lint.ts +1 -3
- package/src/search-params/create.ts +15 -8
- package/src/server/error-formatter.ts +12 -0
- package/src/server/fallback-error.ts +159 -0
- package/src/server/html-injectors.ts +9 -4
- package/src/server/pipeline.ts +24 -0
- package/src/server/request-context.ts +0 -1
- package/src/server/route-matcher.ts +1 -4
- package/src/server/rsc-entry/index.ts +98 -39
- package/src/server/slot-resolver.ts +38 -5
- package/src/server/ssr-entry.ts +12 -1
- package/src/server/tree-builder.ts +39 -11
- package/src/shims/server-only-noop.js +1 -0
- package/dist/_chunks/registry-BfPM41ri.js +0 -20
- package/dist/_chunks/registry-BfPM41ri.js.map +0 -1
- package/dist/_chunks/use-cookie-HcvNlW4L.js.map +0 -1
|
@@ -70,6 +70,18 @@ export interface PipelineConfig {
|
|
|
70
70
|
* Undefined in production — zero overhead.
|
|
71
71
|
*/
|
|
72
72
|
onPipelineError?: (error: Error, phase: string) => void;
|
|
73
|
+
/**
|
|
74
|
+
* Fallback error renderer — called when a catastrophic error escapes the
|
|
75
|
+
* render phase. Produces an HTML Response instead of a bare empty 500.
|
|
76
|
+
*
|
|
77
|
+
* In dev mode, this renders a styled error page with the error message
|
|
78
|
+
* and stack trace. In production, this attempts to render the app's
|
|
79
|
+
* error.tsx / 5xx.tsx / 500.tsx from the root segment.
|
|
80
|
+
*
|
|
81
|
+
* If this function throws, the pipeline falls back to a bare
|
|
82
|
+
* `new Response(null, { status: 500 })`.
|
|
83
|
+
*/
|
|
84
|
+
renderFallbackError?: (error: unknown, req: Request, responseHeaders: Headers) => Response | Promise<Response>;
|
|
73
85
|
}
|
|
74
86
|
/**
|
|
75
87
|
* Create the request handler from a pipeline configuration.
|
|
@@ -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;AA6B1E,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;;;;;;OAMG;IACH,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,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;AA6B1E,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;;;;;;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,CA2R1F"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,YAAY,CAAC;AAIzC,UAAU,mBAAmB;IAC3B,iDAAiD;IACjD,OAAO,EAAE,OAAO,CAAC;IACjB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAC;IACrB,8EAA8E;IAC9E,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,uEAAuE;IACvE,eAAe,EAAE,OAAO,CAAC;IACzB;;;;OAIG;IACH,mBAAmB,EAAE,OAAO,CAAC,eAAe,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;IACxE,wFAAwF;IACxF,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IACpC,4DAA4D;IAC5D,OAAO,EAAE,OAAO,CAAC;IACjB,0DAA0D;IAC1D,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,wDAAwD;AACxD,UAAU,WAAW;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,aAAa,CAAC;CACxB;AAED,gBAAgB;AAChB,eAAO,MAAM,iBAAiB,wCAA+C,CAAC;
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-matcher.d.ts","sourceRoot":"","sources":["../../src/server/route-matcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,
|
|
1
|
+
{"version":3,"file":"route-matcher.d.ts","sourceRoot":"","sources":["../../src/server/route-matcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAA8B,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAM1F,6DAA6D;AAC7D,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,gFAAgF;AAChF,MAAM,WAAW,mBAAmB;IAClC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EACP,QAAQ,GACR,SAAS,GACT,WAAW,GACX,oBAAoB,GACpB,OAAO,GACP,MAAM,GACN,cAAc,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8DAA8D;IAC9D,kBAAkB,CAAC,EAAE,KAAK,GAAG,MAAM,GAAG,OAAO,GAAG,UAAU,CAAC;IAC3D,8EAA8E;IAC9E,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAEhC,IAAI,CAAC,EAAE,YAAY,CAAC;IACpB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,UAAU,CAAC,EAAE,YAAY,CAAC;IAC1B,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,KAAK,CAAC,EAAE,YAAY,CAAC;IACrB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC3C,eAAe,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IACjD,SAAS,CAAC,EAAE,YAAY,CAAC;IACzB,sFAAsF;IACtF,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;IAE9C,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC;CAC5C;AAED,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,mBAAmB,CAAC;IAC1B,KAAK,CAAC,EAAE,YAAY,CAAC;CACtB;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,YAAY,GACrB,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,CAEzC;AA4MD,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,4DAA4D;IAC5D,IAAI,EAAE,iBAAiB,CAAC;IACxB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,0DAA0D;IAC1D,IAAI,EAAE,YAAY,CAAC;IACnB,0DAA0D;IAC1D,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,YAAY,GACrB,CAAC,QAAQ,EAAE,MAAM,KAAK,kBAAkB,GAAG,IAAI,CAMjD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AA2EA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/server/rsc-entry/index.ts"],"names":[],"mappings":"AA2EA;;;;;GAKG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,GAAG,IAAI,CAE/F;AAqrBD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;8BA/jBpD,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AAikBhD,wBAAiE"}
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
*
|
|
16
16
|
* See design/02-rendering-pipeline.md §"Parallel Slots"
|
|
17
17
|
*/
|
|
18
|
+
import type { InterceptionContext, RouteMatch } from './pipeline.js';
|
|
18
19
|
import type { ManifestSegmentNode } from './route-matcher.js';
|
|
19
|
-
import type { RouteMatch, InterceptionContext } from './pipeline.js';
|
|
20
20
|
type CreateElementFn = (...args: unknown[]) => React.ReactElement;
|
|
21
21
|
/**
|
|
22
22
|
* Resolve the element for a parallel slot.
|
|
@@ -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;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAErE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAE9D,KAAK,eAAe,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,YAAY,CAAC;AAElE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,UAAU,EACjB,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC,EACzD,CAAC,EAAE,eAAe,EAClB,YAAY,CAAC,EAAE,mBAAmB,GACjC,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAiKpC"}
|
|
@@ -46,6 +46,13 @@ export interface NavContext {
|
|
|
46
46
|
/** Request cookies as name→value pairs. Used by useCookie() during SSR
|
|
47
47
|
* to return correct cookie values before hydration. */
|
|
48
48
|
cookies?: Map<string, string>;
|
|
49
|
+
/**
|
|
50
|
+
* Mutable flag: set by TimberErrorBoundary during SSR when it catches
|
|
51
|
+
* a DenySignal (via digest). This tells the RSC entry that the denial
|
|
52
|
+
* was contained by a slot error boundary and should NOT be promoted
|
|
53
|
+
* to a page-level deny. See LOCAL-298.
|
|
54
|
+
*/
|
|
55
|
+
_denyHandledByBoundary?: boolean;
|
|
49
56
|
}
|
|
50
57
|
/**
|
|
51
58
|
* Handle SSR: decode an RSC stream and render it to hydration-ready HTML.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ssr-entry.d.ts","sourceRoot":"","sources":["../../src/server/ssr-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA6BH;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,eAAe,EAAE,OAAO,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qEAAqE;IACrE,SAAS,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC;;;0DAGsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;iFAE6E;IAC7E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;4DACwD;IACxD,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"ssr-entry.d.ts","sourceRoot":"","sources":["../../src/server/ssr-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AA6BH;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,qCAAqC;IACrC,UAAU,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,eAAe,EAAE,OAAO,CAAC;IACzB,0DAA0D;IAC1D,QAAQ,EAAE,MAAM,CAAC;IACjB,8EAA8E;IAC9E,sBAAsB,EAAE,MAAM,CAAC;IAC/B,qEAAqE;IACrE,SAAS,CAAC,EAAE,cAAc,CAAC,UAAU,CAAC,CAAC;IACvC;;;0DAGsD;IACtD,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B;;iFAE6E;IAC7E,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB;4DACwD;IACxD,OAAO,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B;;;;;OAKG;IACH,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,QAAQ,CAAC,CA4EnB;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -40,6 +40,16 @@ export interface TreeBuilderConfig {
|
|
|
40
40
|
loadModule: ModuleLoader;
|
|
41
41
|
/** React.createElement or equivalent. */
|
|
42
42
|
createElement: CreateElement;
|
|
43
|
+
/**
|
|
44
|
+
* Error boundary component for wrapping segments.
|
|
45
|
+
*
|
|
46
|
+
* This is injected by the caller rather than imported directly to avoid
|
|
47
|
+
* pulling 'use client' code into the server barrel (@timber-js/app/server).
|
|
48
|
+
* In the RSC environment, the RSC plugin transforms this import to a
|
|
49
|
+
* client reference proxy — the caller handles the import so the server
|
|
50
|
+
* barrel stays free of client dependencies.
|
|
51
|
+
*/
|
|
52
|
+
errorBoundaryComponent?: unknown;
|
|
43
53
|
}
|
|
44
54
|
/**
|
|
45
55
|
* Framework-injected access gate component.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tree-builder.d.ts","sourceRoot":"","sources":["../../src/server/tree-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"tree-builder.d.ts","sourceRoot":"","sources":["../../src/server/tree-builder.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.12",
|
|
4
4
|
"description": "Vite-native React framework for Cloudflare Workers — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"license": "SEE LICENSE IN LICENSE",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/switz/timber.js.git",
|
|
10
|
-
"directory": "packages/timber-app"
|
|
11
|
-
},
|
|
12
|
-
"homepage": "https://github.com/switz/timber.js",
|
|
13
5
|
"keywords": [
|
|
14
|
-
"react",
|
|
15
|
-
"vite",
|
|
16
|
-
"rsc",
|
|
17
|
-
"react-server-components",
|
|
18
6
|
"cloudflare-workers",
|
|
19
7
|
"framework",
|
|
8
|
+
"react",
|
|
9
|
+
"react-server-components",
|
|
10
|
+
"rsc",
|
|
20
11
|
"ssr",
|
|
21
|
-
"streaming"
|
|
12
|
+
"streaming",
|
|
13
|
+
"vite"
|
|
22
14
|
],
|
|
23
|
-
"
|
|
24
|
-
|
|
15
|
+
"homepage": "https://github.com/switz/timber.js",
|
|
16
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
17
|
+
"repository": {
|
|
18
|
+
"type": "git",
|
|
19
|
+
"url": "git+https://github.com/switz/timber.js.git",
|
|
20
|
+
"directory": "packages/timber-app"
|
|
25
21
|
},
|
|
26
22
|
"bin": {
|
|
27
23
|
"timber": "./bin/timber.mjs"
|
|
28
24
|
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"src",
|
|
28
|
+
"bin",
|
|
29
|
+
"README.md",
|
|
30
|
+
"LICENSE"
|
|
31
|
+
],
|
|
32
|
+
"type": "module",
|
|
29
33
|
"imports": {
|
|
30
34
|
"#/*": "./src/*"
|
|
31
35
|
},
|
|
@@ -75,13 +79,6 @@
|
|
|
75
79
|
"publishConfig": {
|
|
76
80
|
"access": "public"
|
|
77
81
|
},
|
|
78
|
-
"files": [
|
|
79
|
-
"dist",
|
|
80
|
-
"src",
|
|
81
|
-
"bin",
|
|
82
|
-
"README.md",
|
|
83
|
-
"LICENSE"
|
|
84
|
-
],
|
|
85
82
|
"scripts": {
|
|
86
83
|
"build": "vite build --config vite.lib.config.ts && tsc --emitDeclarationOnly --project tsconfig.json --outDir dist",
|
|
87
84
|
"typecheck": "tsgo --noEmit",
|
|
@@ -121,5 +118,8 @@
|
|
|
121
118
|
"zod": {
|
|
122
119
|
"optional": true
|
|
123
120
|
}
|
|
121
|
+
},
|
|
122
|
+
"engines": {
|
|
123
|
+
"node": ">=20.0.0"
|
|
124
124
|
}
|
|
125
125
|
}
|
|
@@ -364,7 +364,7 @@ function bootstrap(runtimeConfig: typeof config): void {
|
|
|
364
364
|
// so duplicate URLs in history each have their own scroll position.
|
|
365
365
|
window.addEventListener('popstate', () => {
|
|
366
366
|
const state = window.history.state;
|
|
367
|
-
const scrollY =
|
|
367
|
+
const scrollY = state && typeof state.scrollY === 'number' ? state.scrollY : 0;
|
|
368
368
|
void router.handlePopState(window.location.pathname + window.location.search, scrollY);
|
|
369
369
|
});
|
|
370
370
|
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import { Component, createElement, type ReactNode } from 'react';
|
|
22
|
+
import { getSsrData } from './ssr-data.js';
|
|
22
23
|
|
|
23
24
|
// ─── Page Unload Detection ───────────────────────────────────────────────────
|
|
24
25
|
// Track whether the page is being unloaded (user refreshed or navigated away).
|
|
@@ -97,6 +98,27 @@ export class TimberErrorBoundary extends Component<
|
|
|
97
98
|
if (_isUnloading) {
|
|
98
99
|
return { hasError: false, error: null };
|
|
99
100
|
}
|
|
101
|
+
|
|
102
|
+
// Report DenySignal handling to prevent page-level promotion.
|
|
103
|
+
// When a slot's error boundary catches a DenySignal, the RSC onError
|
|
104
|
+
// callback has already tracked it globally. Setting this flag tells
|
|
105
|
+
// the RSC entry not to promote the denial to page-level (which would
|
|
106
|
+
// replace the entire SSR response). See LOCAL-298.
|
|
107
|
+
const digest = (error as { digest?: string }).digest;
|
|
108
|
+
if (typeof digest === 'string') {
|
|
109
|
+
try {
|
|
110
|
+
const parsed = JSON.parse(digest);
|
|
111
|
+
if (parsed?.type === 'deny') {
|
|
112
|
+
const ssrData = getSsrData();
|
|
113
|
+
if (ssrData?._navContext) {
|
|
114
|
+
ssrData._navContext._denyHandledByBoundary = true;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
} catch {
|
|
118
|
+
// Not a JSON digest — ignore
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
100
122
|
return { hasError: true, error };
|
|
101
123
|
}
|
|
102
124
|
|
package/src/client/ssr-data.ts
CHANGED
|
@@ -30,6 +30,13 @@ export interface SsrData {
|
|
|
30
30
|
cookies: Map<string, string>;
|
|
31
31
|
/** The request's route params (e.g. { id: '123' }) */
|
|
32
32
|
params: Record<string, string | string[]>;
|
|
33
|
+
/**
|
|
34
|
+
* Mutable reference to NavContext for error boundary → RSC communication.
|
|
35
|
+
* When TimberErrorBoundary catches a DenySignal, it sets
|
|
36
|
+
* `_navContext._denyHandledByBoundary = true` to prevent the RSC entry
|
|
37
|
+
* from promoting the denial to page-level. See LOCAL-298.
|
|
38
|
+
*/
|
|
39
|
+
_navContext?: { _denyHandledByBoundary?: boolean };
|
|
33
40
|
}
|
|
34
41
|
|
|
35
42
|
// ─── ALS-Backed Provider ─────────────────────────────────────────
|
|
@@ -101,7 +101,19 @@ export function useQueryStates<T extends Record<string, unknown>>(
|
|
|
101
101
|
nuqsOptions.urlKeys = resolvedUrlKeys;
|
|
102
102
|
}
|
|
103
103
|
|
|
104
|
-
|
|
104
|
+
let values: Record<string, unknown>;
|
|
105
|
+
let setValues: Function;
|
|
106
|
+
try {
|
|
107
|
+
[values, setValues] = nuqsUseQueryStates(bridged, nuqsOptions);
|
|
108
|
+
} catch (err) {
|
|
109
|
+
if (err instanceof Error && /Invalid hook call|cannot be called|Cannot read properties of null/i.test(err.message)) {
|
|
110
|
+
throw new Error(
|
|
111
|
+
'useQueryStates is a client component hook and cannot be called outside a React component. ' +
|
|
112
|
+
'Use definition.parse(searchParams) in server components instead.'
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
throw err;
|
|
116
|
+
}
|
|
105
117
|
|
|
106
118
|
// Wrap the nuqs setter to match timber's SetParams<T> signature.
|
|
107
119
|
// nuqs's setter accepts Partial<Nullable<Values>> | UpdaterFn | null.
|
package/src/index.ts
CHANGED
|
@@ -190,9 +190,7 @@ export function resolveAppDir(root: string, configAppDir?: string): string {
|
|
|
190
190
|
if (configAppDir) {
|
|
191
191
|
const explicit = join(root, configAppDir);
|
|
192
192
|
if (!existsSync(explicit)) {
|
|
193
|
-
throw new Error(
|
|
194
|
-
`[timber] Configured appDir "${configAppDir}" does not exist at ${explicit}`
|
|
195
|
-
);
|
|
193
|
+
throw new Error(`[timber] Configured appDir "${configAppDir}" does not exist at ${explicit}`);
|
|
196
194
|
}
|
|
197
195
|
return explicit;
|
|
198
196
|
}
|
|
@@ -361,19 +359,21 @@ export function timber(config?: TimberUserConfig): PluginOption[] {
|
|
|
361
359
|
const consumerRequire = createRequire(join(process.cwd(), 'package.json'));
|
|
362
360
|
const rscPluginPath = consumerRequire.resolve('@vitejs/plugin-rsc');
|
|
363
361
|
ctx.timer.start('rsc-plugin-import');
|
|
364
|
-
const rscPluginsPromise = import(pathToFileURL(rscPluginPath).href).then(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
362
|
+
const rscPluginsPromise = import(pathToFileURL(rscPluginPath).href).then(
|
|
363
|
+
({ default: vitePluginRsc }) => {
|
|
364
|
+
ctx.timer.end('rsc-plugin-import');
|
|
365
|
+
return vitePluginRsc({
|
|
366
|
+
serverHandler: false,
|
|
367
|
+
customClientEntry: true,
|
|
368
|
+
entries: {
|
|
369
|
+
rsc: 'virtual:timber-rsc-entry',
|
|
370
|
+
ssr: 'virtual:timber-ssr-entry',
|
|
371
|
+
client: 'virtual:timber-browser-entry',
|
|
372
|
+
},
|
|
373
|
+
clientChunks: assignClientChunk,
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
);
|
|
377
377
|
|
|
378
378
|
return [
|
|
379
379
|
rootSync,
|
|
@@ -146,7 +146,9 @@ function createTimberMiddleware(server: ViteDevServer, projectRoot: string) {
|
|
|
146
146
|
// environment's module runner for HMR-aware loading.
|
|
147
147
|
let handler: (req: Request) => Promise<Response>;
|
|
148
148
|
try {
|
|
149
|
-
const rscEnv = server.environments.rsc as DevEnvironment & {
|
|
149
|
+
const rscEnv = server.environments.rsc as DevEnvironment & {
|
|
150
|
+
runner?: { import: (id: string) => Promise<any> };
|
|
151
|
+
};
|
|
150
152
|
// Duck-type check instead of isRunnableDevEnvironment() — the vite
|
|
151
153
|
// import-based check fails across pnpm link boundaries where the
|
|
152
154
|
// linked package resolves a different vite module instance.
|
package/src/plugins/entries.ts
CHANGED
|
@@ -92,7 +92,8 @@ function stripRootPrefix(id: string, root: string): string {
|
|
|
92
92
|
*/
|
|
93
93
|
function generateConfigModule(ctx: PluginContext): string {
|
|
94
94
|
// Resolve cookie secrets: `secret` shorthand expands to `secrets: [secret]`
|
|
95
|
-
const cookieSecrets =
|
|
95
|
+
const cookieSecrets =
|
|
96
|
+
ctx.config.cookies?.secrets ??
|
|
96
97
|
(ctx.config.cookies?.secret ? [ctx.config.cookies.secret] : undefined);
|
|
97
98
|
|
|
98
99
|
const runtimeConfig = {
|
package/src/plugins/routing.ts
CHANGED
|
@@ -14,7 +14,10 @@ import { join } from 'node:path';
|
|
|
14
14
|
import { scanRoutes } from '#/routing/scanner.js';
|
|
15
15
|
import { generateRouteMap } from '#/routing/codegen.js';
|
|
16
16
|
import { collectInterceptionRewrites } from '#/routing/interception.js';
|
|
17
|
-
import {
|
|
17
|
+
import {
|
|
18
|
+
lintStatusFileDirectives,
|
|
19
|
+
formatStatusFileLintWarnings,
|
|
20
|
+
} from '#/routing/status-file-lint.js';
|
|
18
21
|
import type { RouteTree, SegmentNode, RouteFile } from '#/routing/types.js';
|
|
19
22
|
import type { PluginContext } from '#/index.js';
|
|
20
23
|
|
|
@@ -352,9 +355,7 @@ function generateManifestModule(tree: RouteTree): string {
|
|
|
352
355
|
`${nextIndent} ${JSON.stringify(name)}: { load: ${v}, filePath: ${JSON.stringify(file.filePath)} }`
|
|
353
356
|
);
|
|
354
357
|
}
|
|
355
|
-
parts.push(
|
|
356
|
-
`${nextIndent}metadataRoutes: {\n${metaEntries.join(',\n')}\n${nextIndent}},`
|
|
357
|
-
);
|
|
358
|
+
parts.push(`${nextIndent}metadataRoutes: {\n${metaEntries.join(',\n')}\n${nextIndent}},`);
|
|
358
359
|
}
|
|
359
360
|
|
|
360
361
|
// Children
|
|
@@ -26,11 +26,20 @@ export function timberServerBundle(): Plugin[] {
|
|
|
26
26
|
// which throws in the SSR environment.
|
|
27
27
|
if (command === 'serve') {
|
|
28
28
|
// In dev, Vite externalizes node_modules and loads them via Node's
|
|
29
|
-
// native require().
|
|
30
|
-
//
|
|
31
|
-
//
|
|
32
|
-
//
|
|
33
|
-
//
|
|
29
|
+
// native require(). This causes two problems:
|
|
30
|
+
//
|
|
31
|
+
// 1. Poison-pill packages: deps that import `server-only` (like `bright`)
|
|
32
|
+
// hit the real CJS package which throws in the SSR environment.
|
|
33
|
+
//
|
|
34
|
+
// 2. Dual React instances: deps with React hooks (nuqs, etc.) are
|
|
35
|
+
// externalized and loaded via Node.js, getting their own copy of
|
|
36
|
+
// React. Meanwhile, SSR's renderToReadableStream uses Vite's
|
|
37
|
+
// dep-optimized React. Two React instances = dispatcher mismatch,
|
|
38
|
+
// causing "Invalid hook call" / "Cannot read properties of null
|
|
39
|
+
// (reading 'useId')" errors. See LOCAL-297.
|
|
40
|
+
//
|
|
41
|
+
// We force these packages to be non-external so they go through
|
|
42
|
+
// Vite's module pipeline, which deduplicates React correctly.
|
|
34
43
|
return {
|
|
35
44
|
environments: {
|
|
36
45
|
rsc: {
|
|
@@ -40,7 +49,7 @@ export function timberServerBundle(): Plugin[] {
|
|
|
40
49
|
},
|
|
41
50
|
ssr: {
|
|
42
51
|
resolve: {
|
|
43
|
-
noExternal: ['server-only', 'client-only'],
|
|
52
|
+
noExternal: ['server-only', 'client-only', 'nuqs'],
|
|
44
53
|
},
|
|
45
54
|
},
|
|
46
55
|
},
|
package/src/plugins/shims.ts
CHANGED
|
@@ -173,21 +173,15 @@ export function timberShims(_ctx: PluginContext): Plugin {
|
|
|
173
173
|
return 'export {};';
|
|
174
174
|
}
|
|
175
175
|
|
|
176
|
-
//
|
|
177
|
-
//
|
|
178
|
-
//
|
|
176
|
+
// Error module for @timber-js/app/server in client environment.
|
|
177
|
+
// Server modules must never be bundled into the browser — if this
|
|
178
|
+
// module is reached, there is a broken import chain that needs fixing.
|
|
179
179
|
if (id === '\0timber:server-empty') {
|
|
180
|
-
return `
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
export const redirect = stub("redirect");
|
|
186
|
-
export const permanentRedirect = stub("permanentRedirect");
|
|
187
|
-
export const deny = stub("deny");
|
|
188
|
-
export const searchParams = stub("searchParams");
|
|
189
|
-
export const RedirectType = { push: "push", replace: "replace" };
|
|
190
|
-
`;
|
|
180
|
+
return `throw new Error(
|
|
181
|
+
"[timber] @timber-js/app/server was imported from client code. " +
|
|
182
|
+
"Server modules (headers, cookies, redirect, deny, etc.) cannot be used in client components. " +
|
|
183
|
+
"If you need these APIs, move the import to a server component or middleware."
|
|
184
|
+
);`;
|
|
191
185
|
}
|
|
192
186
|
},
|
|
193
187
|
};
|
|
@@ -106,9 +106,7 @@ export function formatStatusFileLintWarnings(warnings: StatusFileLintWarning[]):
|
|
|
106
106
|
lines.push(
|
|
107
107
|
" Status files and error.tsx are rendered inside TimberErrorBoundary (a 'use client' component)."
|
|
108
108
|
);
|
|
109
|
-
lines.push(
|
|
110
|
-
" Add 'use client' as the first line of each file to avoid a runtime error."
|
|
111
|
-
);
|
|
109
|
+
lines.push(" Add 'use client' as the first line of each file to avoid a runtime error.");
|
|
112
110
|
|
|
113
111
|
return lines.join('\n');
|
|
114
112
|
}
|
|
@@ -8,6 +8,8 @@
|
|
|
8
8
|
* Design doc: design/09-typescript.md §"Typed searchParams — search-params.ts"
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
+
import { useQueryStates as clientUseQueryStates } from '#/client/use-query-states.js';
|
|
12
|
+
|
|
11
13
|
// ---------------------------------------------------------------------------
|
|
12
14
|
// Types
|
|
13
15
|
// ---------------------------------------------------------------------------
|
|
@@ -288,14 +290,19 @@ function buildDefinition<T extends Record<string, unknown>>(
|
|
|
288
290
|
}
|
|
289
291
|
|
|
290
292
|
// ---- useQueryStates ----
|
|
291
|
-
//
|
|
292
|
-
//
|
|
293
|
-
//
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
293
|
+
// Delegates to the 'use client' implementation from use-query-states.ts.
|
|
294
|
+
//
|
|
295
|
+
// In the RSC environment: use-query-states.ts is transformed by the RSC
|
|
296
|
+
// plugin into a client reference proxy. Calling it throws — correct,
|
|
297
|
+
// because hooks can't run during server component rendering.
|
|
298
|
+
// In SSR: use-query-states.ts is the real nuqs-backed function. Hooks
|
|
299
|
+
// work during SSR's renderToReadableStream, so this works correctly.
|
|
300
|
+
// On the client: same as SSR — the real function is available.
|
|
301
|
+
function useQueryStates(options?: QueryStatesOptions): [T, SetParams<T>] {
|
|
302
|
+
return clientUseQueryStates(codecMap, options, Object.freeze({ ...urlKeys })) as [
|
|
303
|
+
T,
|
|
304
|
+
SetParams<T>,
|
|
305
|
+
];
|
|
299
306
|
}
|
|
300
307
|
|
|
301
308
|
const definition: SearchParamsDefinition<T> = {
|
|
@@ -147,6 +147,18 @@ function extractErrorHint(message: string): string | null {
|
|
|
147
147
|
return 'A component resolved to undefined/null — check default exports and import paths';
|
|
148
148
|
}
|
|
149
149
|
|
|
150
|
+
// "Invalid hook call" — hooks called outside React's render context.
|
|
151
|
+
// In RSC, this typically means a 'use client' component was executed as a
|
|
152
|
+
// server component instead of being serialized as a client reference.
|
|
153
|
+
if (message.includes('Invalid hook call')) {
|
|
154
|
+
return (
|
|
155
|
+
'A hook was called outside of a React component render. ' +
|
|
156
|
+
"If this is a 'use client' component, ensure the directive is at the very top of the file " +
|
|
157
|
+
'(before any imports) and that @vitejs/plugin-rsc is loaded correctly. ' +
|
|
158
|
+
"Barrel re-exports from non-'use client' files do not propagate the directive."
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
150
162
|
return null;
|
|
151
163
|
}
|
|
152
164
|
|