@timber-js/app 0.1.10 → 0.1.11
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/use-query-states-wEXY2JQB.js +109 -0
- package/dist/_chunks/use-query-states-wEXY2JQB.js.map +1 -0
- package/dist/client/index.js +1 -83
- package/dist/client/index.js.map +1 -1
- package/dist/client/use-query-states.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -1
- 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/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 +4 -0
- 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.map +1 -1
- 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/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/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 +88 -36
- package/src/server/slot-resolver.ts +38 -5
- package/src/server/ssr-entry.ts +4 -1
- package/src/server/tree-builder.ts +4 -1
- 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
|
@@ -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;AA8qBD,OAAO,EAAE,uBAAuB,EAAE,MAAM,gCAAgC,CAAC;8BAxjBpD,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC;AA0jBhD,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"}
|
|
@@ -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;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,QAAQ,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;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAsB,SAAS,CAC7B,SAAS,EAAE,cAAc,CAAC,UAAU,CAAC,EACrC,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,QAAQ,CAAC,CA2EnB;AAED,eAAe,SAAS,CAAC"}
|
|
@@ -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;AAKjE,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,iDAAiD;AACjD,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAErF,gFAAgF;AAEhF,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC;AAE/B,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,CAC1B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACrC,GAAG,QAAQ,EAAE,OAAO,EAAE,KACnB,YAAY,CAAC;AAElB;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAErD,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,uDAAuD;IACvD,YAAY,EAAE,OAAO,CAAC;IACtB,mCAAmC;IACnC,UAAU,EAAE,YAAY,CAAC;IACzB,yCAAyC;IACzC,aAAa,EAAE,aAAa,CAAC;CAC9B;AAID;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;IACjG,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,YAAY,EAAE,OAAO,CAAC;IACtB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,OAAO,CAAC,
|
|
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;AAKjE,mDAAmD;AACnD,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mEAAmE;IACnE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,iDAAiD;AACjD,MAAM,MAAM,YAAY,GAAG,CAAC,IAAI,EAAE,SAAS,KAAK,YAAY,GAAG,OAAO,CAAC,YAAY,CAAC,CAAC;AAErF,gFAAgF;AAEhF,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC;AAE/B,oFAAoF;AACpF,MAAM,MAAM,aAAa,GAAG,CAC1B,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,EACrC,GAAG,QAAQ,EAAE,OAAO,EAAE,KACnB,YAAY,CAAC;AAElB;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC;AAErD,0CAA0C;AAC1C,MAAM,WAAW,iBAAiB;IAChC,mDAAmD;IACnD,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,mFAAmF;IACnF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,uDAAuD;IACvD,YAAY,EAAE,OAAO,CAAC;IACtB,mCAAmC;IACnC,UAAU,EAAE,YAAY,CAAC;IACzB,yCAAyC;IACzC,aAAa,EAAE,aAAa,CAAC;CAC9B;AAID;;;;;;;GAOG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;IACjG,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,YAAY,EAAE,OAAO,CAAC;IACtB,wEAAwE;IACxE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;OAKG;IACH,OAAO,CAAC,EACJ,MAAM,GACN,OAAO,iBAAiB,EAAE,UAAU,GACpC,OAAO,iBAAiB,EAAE,cAAc,CAAC;IAC7C,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,CAAC,GAAG,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;QAAC,YAAY,EAAE,OAAO,CAAA;KAAE,KAAK,OAAO,CAAC;IACjG,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IAC1C,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,YAAY,GAAG,IAAI,CAAC;IACpC,eAAe,EAAE,YAAY,GAAG,IAAI,CAAC;IACrC,QAAQ,EAAE,YAAY,CAAC;CACxB;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,iBAAiB,EAAE,YAAY,GAAG,IAAI,CAAC;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,YAAY,CAAC;CACxB;AAID;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,oEAAoE;IACpE,IAAI,EAAE,YAAY,CAAC;IACnB,gFAAgF;IAChF,UAAU,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gBAAgB,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,eAAe,CAAC,CAiF1F"}
|
package/package.json
CHANGED
|
@@ -1,31 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
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
|
|
|
@@ -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
|
},
|
|
@@ -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
|
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fallback error rendering — handles catastrophic errors that escape the
|
|
3
|
+
* render pipeline entirely (e.g. module evaluation failures).
|
|
4
|
+
*
|
|
5
|
+
* In dev mode: renders a styled HTML page with error details and stack trace.
|
|
6
|
+
* The Vite client script is included so the error overlay still fires.
|
|
7
|
+
*
|
|
8
|
+
* In production: attempts to render root error pages (500.tsx / 5xx.tsx /
|
|
9
|
+
* error.tsx) via the normal RSC → SSR pipeline. Stack traces are never
|
|
10
|
+
* exposed to the client (design/13-security.md principle 4).
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { RouteMatch } from '#/server/pipeline.js';
|
|
14
|
+
import type { ManifestSegmentNode } from '#/server/route-matcher.js';
|
|
15
|
+
import type { ClientBootstrapConfig } from '#/server/html-injectors.js';
|
|
16
|
+
import type { LayoutEntry } from '#/server/deny-renderer.js';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Render a fallback error page when the render pipeline throws.
|
|
20
|
+
*
|
|
21
|
+
* In dev: styled HTML with error details.
|
|
22
|
+
* In prod: renders root error pages via renderErrorPage.
|
|
23
|
+
*/
|
|
24
|
+
export async function renderFallbackError(
|
|
25
|
+
error: unknown,
|
|
26
|
+
req: Request,
|
|
27
|
+
responseHeaders: Headers,
|
|
28
|
+
isDev: boolean,
|
|
29
|
+
rootSegment: ManifestSegmentNode,
|
|
30
|
+
clientBootstrap: ClientBootstrapConfig
|
|
31
|
+
): Promise<Response> {
|
|
32
|
+
if (isDev) {
|
|
33
|
+
return renderDevErrorPage(error);
|
|
34
|
+
}
|
|
35
|
+
// Lazy import to avoid loading error-renderer in the pipeline module
|
|
36
|
+
const { renderErrorPage } = await import('#/server/rsc-entry/error-renderer.js');
|
|
37
|
+
const segments = [rootSegment];
|
|
38
|
+
const layoutComponents: LayoutEntry[] = [];
|
|
39
|
+
if (rootSegment.layout) {
|
|
40
|
+
const mod = (await rootSegment.layout.load()) as Record<string, unknown>;
|
|
41
|
+
if (mod.default) {
|
|
42
|
+
layoutComponents.push({
|
|
43
|
+
component: mod.default as (...args: unknown[]) => unknown,
|
|
44
|
+
segment: rootSegment,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const match: RouteMatch = { segments: segments as never, params: {} };
|
|
49
|
+
return renderErrorPage(
|
|
50
|
+
error,
|
|
51
|
+
500,
|
|
52
|
+
segments,
|
|
53
|
+
layoutComponents,
|
|
54
|
+
req,
|
|
55
|
+
match,
|
|
56
|
+
responseHeaders,
|
|
57
|
+
clientBootstrap
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Render a dev-mode 500 error page with error message and stack trace.
|
|
63
|
+
*
|
|
64
|
+
* Returns an HTML Response that displays the error in a styled page.
|
|
65
|
+
* The Vite HMR client script is included so the error overlay still fires.
|
|
66
|
+
*/
|
|
67
|
+
export function renderDevErrorPage(error: unknown): Response {
|
|
68
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
69
|
+
const title = err.name || 'Error';
|
|
70
|
+
const message = escapeHtml(err.message);
|
|
71
|
+
const stack = err.stack ? escapeHtml(err.stack) : '';
|
|
72
|
+
|
|
73
|
+
const html = `<!DOCTYPE html>
|
|
74
|
+
<html lang="en">
|
|
75
|
+
<head>
|
|
76
|
+
<meta charset="utf-8">
|
|
77
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
78
|
+
<title>500 — ${escapeHtml(title)}</title>
|
|
79
|
+
<script type="module" src="/@vite/client"></script>
|
|
80
|
+
<style>
|
|
81
|
+
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
|
|
82
|
+
body {
|
|
83
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
84
|
+
background: #1a1a2e;
|
|
85
|
+
color: #e0e0e0;
|
|
86
|
+
padding: 2rem;
|
|
87
|
+
line-height: 1.6;
|
|
88
|
+
}
|
|
89
|
+
.container { max-width: 800px; margin: 0 auto; }
|
|
90
|
+
.badge {
|
|
91
|
+
display: inline-block;
|
|
92
|
+
background: #e74c3c;
|
|
93
|
+
color: white;
|
|
94
|
+
font-size: 0.75rem;
|
|
95
|
+
font-weight: 700;
|
|
96
|
+
padding: 0.2rem 0.6rem;
|
|
97
|
+
border-radius: 4px;
|
|
98
|
+
text-transform: uppercase;
|
|
99
|
+
letter-spacing: 0.05em;
|
|
100
|
+
margin-bottom: 1rem;
|
|
101
|
+
}
|
|
102
|
+
h1 {
|
|
103
|
+
font-size: 1.5rem;
|
|
104
|
+
color: #ff6b6b;
|
|
105
|
+
margin-bottom: 0.5rem;
|
|
106
|
+
word-break: break-word;
|
|
107
|
+
}
|
|
108
|
+
.message {
|
|
109
|
+
font-size: 1.1rem;
|
|
110
|
+
color: #ccc;
|
|
111
|
+
margin-bottom: 1.5rem;
|
|
112
|
+
word-break: break-word;
|
|
113
|
+
}
|
|
114
|
+
.stack-container {
|
|
115
|
+
background: #16213e;
|
|
116
|
+
border: 1px solid #2a2a4a;
|
|
117
|
+
border-radius: 8px;
|
|
118
|
+
padding: 1rem;
|
|
119
|
+
overflow-x: auto;
|
|
120
|
+
}
|
|
121
|
+
.stack {
|
|
122
|
+
font-family: 'SF Mono', 'Fira Code', 'Fira Mono', Menlo, Consolas, monospace;
|
|
123
|
+
font-size: 0.8rem;
|
|
124
|
+
color: #a0a0c0;
|
|
125
|
+
white-space: pre-wrap;
|
|
126
|
+
word-break: break-all;
|
|
127
|
+
}
|
|
128
|
+
.hint {
|
|
129
|
+
margin-top: 1.5rem;
|
|
130
|
+
font-size: 0.85rem;
|
|
131
|
+
color: #666;
|
|
132
|
+
}
|
|
133
|
+
</style>
|
|
134
|
+
</head>
|
|
135
|
+
<body>
|
|
136
|
+
<div class="container">
|
|
137
|
+
<span class="badge">500 Internal Server Error</span>
|
|
138
|
+
<h1>${escapeHtml(title)}</h1>
|
|
139
|
+
<p class="message">${message}</p>
|
|
140
|
+
${stack ? `<div class="stack-container"><pre class="stack">${stack}</pre></div>` : ''}
|
|
141
|
+
<p class="hint">This error page is only shown in development.</p>
|
|
142
|
+
</div>
|
|
143
|
+
</body>
|
|
144
|
+
</html>`;
|
|
145
|
+
|
|
146
|
+
return new Response(html, {
|
|
147
|
+
status: 500,
|
|
148
|
+
headers: { 'Content-Type': 'text/html; charset=utf-8' },
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function escapeHtml(str: string): string {
|
|
153
|
+
return str
|
|
154
|
+
.replace(/&/g, '&')
|
|
155
|
+
.replace(/</g, '<')
|
|
156
|
+
.replace(/>/g, '>')
|
|
157
|
+
.replace(/"/g, '"')
|
|
158
|
+
.replace(/'/g, ''');
|
|
159
|
+
}
|
|
@@ -323,8 +323,7 @@ export function injectRscPayload(
|
|
|
323
323
|
|
|
324
324
|
// Single transform: strip </body></html>, inject RSC scripts at
|
|
325
325
|
// body level, re-emit suffix at the very end.
|
|
326
|
-
return htmlStream
|
|
327
|
-
.pipeThrough(createFlightInjectionTransform(rscScriptStream));
|
|
326
|
+
return htmlStream.pipeThrough(createFlightInjectionTransform(rscScriptStream));
|
|
328
327
|
}
|
|
329
328
|
|
|
330
329
|
/**
|
|
@@ -354,7 +353,10 @@ function findManifestEntry(map: Record<string, string>, suffix: string): string
|
|
|
354
353
|
}
|
|
355
354
|
|
|
356
355
|
/** Find a manifest array entry by matching the key suffix. */
|
|
357
|
-
function findManifestEntryArray(
|
|
356
|
+
function findManifestEntryArray(
|
|
357
|
+
map: Record<string, string[]>,
|
|
358
|
+
suffix: string
|
|
359
|
+
): string[] | undefined {
|
|
358
360
|
for (const [key, value] of Object.entries(map)) {
|
|
359
361
|
if (key.endsWith(suffix)) return value;
|
|
360
362
|
}
|
|
@@ -431,7 +433,10 @@ export function buildClientScripts(runtimeConfig: {
|
|
|
431
433
|
|
|
432
434
|
if (browserEntryUrl) {
|
|
433
435
|
// Modulepreload hints for browser entry dependencies
|
|
434
|
-
const preloads =
|
|
436
|
+
const preloads =
|
|
437
|
+
(manifest
|
|
438
|
+
? findManifestEntryArray(manifest.modulepreload, 'client/browser-entry.ts')
|
|
439
|
+
: undefined) ?? [];
|
|
435
440
|
for (const url of preloads) {
|
|
436
441
|
preloadLinks += `<link rel="modulepreload" href="${url}">`;
|
|
437
442
|
}
|
package/src/server/pipeline.ts
CHANGED
|
@@ -121,6 +121,22 @@ export interface PipelineConfig {
|
|
|
121
121
|
* Undefined in production — zero overhead.
|
|
122
122
|
*/
|
|
123
123
|
onPipelineError?: (error: Error, phase: string) => void;
|
|
124
|
+
/**
|
|
125
|
+
* Fallback error renderer — called when a catastrophic error escapes the
|
|
126
|
+
* render phase. Produces an HTML Response instead of a bare empty 500.
|
|
127
|
+
*
|
|
128
|
+
* In dev mode, this renders a styled error page with the error message
|
|
129
|
+
* and stack trace. In production, this attempts to render the app's
|
|
130
|
+
* error.tsx / 5xx.tsx / 500.tsx from the root segment.
|
|
131
|
+
*
|
|
132
|
+
* If this function throws, the pipeline falls back to a bare
|
|
133
|
+
* `new Response(null, { status: 500 })`.
|
|
134
|
+
*/
|
|
135
|
+
renderFallbackError?: (
|
|
136
|
+
error: unknown,
|
|
137
|
+
req: Request,
|
|
138
|
+
responseHeaders: Headers
|
|
139
|
+
) => Response | Promise<Response>;
|
|
124
140
|
}
|
|
125
141
|
|
|
126
142
|
// ─── Pipeline ──────────────────────────────────────────────────────────────
|
|
@@ -403,6 +419,14 @@ export function createPipeline(config: PipelineConfig): (req: Request) => Promis
|
|
|
403
419
|
logRenderError({ method, path, error });
|
|
404
420
|
await fireOnRequestError(error, req, 'render');
|
|
405
421
|
if (onPipelineError && error instanceof Error) onPipelineError(error, 'render');
|
|
422
|
+
// Try fallback error page before bare 500
|
|
423
|
+
if (config.renderFallbackError) {
|
|
424
|
+
try {
|
|
425
|
+
return await config.renderFallbackError(error, req, responseHeaders);
|
|
426
|
+
} catch {
|
|
427
|
+
// Fallback rendering itself failed — fall through to bare 500
|
|
428
|
+
}
|
|
429
|
+
}
|
|
406
430
|
return new Response(null, { status: 500 });
|
|
407
431
|
}
|
|
408
432
|
}
|