@timber-js/app 0.2.0-alpha.115 → 0.2.0-alpha.117
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/{actions-ILhDUzES.js → actions-Cw-7NfJJ.js} +24 -17
- package/dist/_chunks/actions-Cw-7NfJJ.js.map +1 -0
- package/dist/_chunks/{define-a0CCE6Nx.js → define-zQX6e1tN.js} +2 -2
- package/dist/_chunks/{define-a0CCE6Nx.js.map → define-zQX6e1tN.js.map} +1 -1
- package/dist/_chunks/{navigation-root-CY3pRMxF.js → navigation-root-DKsJ5Di7.js} +2 -2
- package/dist/_chunks/{navigation-root-CY3pRMxF.js.map → navigation-root-DKsJ5Di7.js.map} +1 -1
- package/dist/_chunks/{resolve-schema-DO8B0mO9.js → resolve-schema-23Mc8aLi.js} +1 -1
- package/dist/_chunks/{resolve-schema-DO8B0mO9.js.map → resolve-schema-23Mc8aLi.js.map} +1 -1
- package/dist/_chunks/{segment-context-EsfQpS--.js → segment-context-Bg0pFbLT.js} +1 -1
- package/dist/_chunks/{segment-context-EsfQpS--.js.map → segment-context-Bg0pFbLT.js.map} +1 -1
- package/dist/_chunks/tracing-DvKLzCFa.js.map +1 -1
- package/dist/_chunks/{use-segment-params-BSt_O2cb.js → use-segment-params-CskiK-59.js} +2 -2
- package/dist/_chunks/{use-segment-params-BSt_O2cb.js.map → use-segment-params-CskiK-59.js.map} +1 -1
- package/dist/_chunks/{walkers-DGV9dQRq.js → walkers-DgOXkTts.js} +12 -10
- package/dist/_chunks/walkers-DgOXkTts.js.map +1 -0
- package/dist/client/index.js +4 -4
- package/dist/client/internal.js +3 -3
- package/dist/client/use-segment-params.d.ts +3 -3
- package/dist/client/use-segment-params.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/params/index.js +1 -1
- package/dist/routing/codegen-types.d.ts +3 -0
- package/dist/routing/codegen-types.d.ts.map +1 -1
- package/dist/routing/index.js +1 -1
- package/dist/segment-params/index.js +1 -1
- package/dist/server/als-registry.d.ts +17 -4
- package/dist/server/als-registry.d.ts.map +1 -1
- package/dist/server/index.js +1 -1
- package/dist/server/internal.js +70 -69
- package/dist/server/internal.js.map +1 -1
- package/dist/server/param-coercion.d.ts +18 -0
- package/dist/server/param-coercion.d.ts.map +1 -1
- package/dist/server/pipeline-phases.d.ts.map +1 -1
- package/dist/server/pipeline.d.ts +7 -0
- package/dist/server/pipeline.d.ts.map +1 -1
- package/dist/server/request-context.d.ts +18 -9
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/route-element-builder.d.ts.map +1 -1
- package/dist/server/route-matcher.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/tree-match.d.ts +41 -0
- package/dist/server/tree-match.d.ts.map +1 -0
- package/package.json +1 -1
- package/src/client/use-segment-params.ts +4 -4
- package/src/routing/codegen-types.ts +3 -0
- package/src/routing/codegen.ts +18 -9
- package/src/server/als-registry.ts +17 -4
- package/src/server/param-coercion.ts +58 -0
- package/src/server/pipeline-phases.ts +14 -7
- package/src/server/pipeline.ts +7 -0
- package/src/server/request-context.ts +48 -17
- package/src/server/route-element-builder.ts +12 -2
- package/src/server/route-matcher.ts +8 -168
- package/src/server/slot-resolver.ts +79 -112
- package/src/server/tree-match.ts +198 -0
- package/dist/_chunks/actions-ILhDUzES.js.map +0 -1
- package/dist/_chunks/walkers-DGV9dQRq.js.map +0 -1
|
@@ -19,6 +19,24 @@ import type { RouteMatch } from './pipeline.js';
|
|
|
19
19
|
* @internal
|
|
20
20
|
*/
|
|
21
21
|
export declare function setGlobalSchemaCodecs(codecs: Record<string, Codec<unknown>> | null): void;
|
|
22
|
+
/**
|
|
23
|
+
* Coerce raw slot params through global schema codecs.
|
|
24
|
+
*
|
|
25
|
+
* Each slot segment that has a paramName is looked up in the global codec
|
|
26
|
+
* map by its bracket key (e.g. '[...year]' for catch-all). If a codec
|
|
27
|
+
* exists, the raw value is parsed through it. If no codec exists or no
|
|
28
|
+
* global codecs are registered, the raw value passes through unchanged.
|
|
29
|
+
*
|
|
30
|
+
* Unlike main route coercion, this does NOT throw ParamCoercionError on
|
|
31
|
+
* failure — slots degrade gracefully. A failed coercion logs a warning
|
|
32
|
+
* in dev mode and keeps the raw value.
|
|
33
|
+
*
|
|
34
|
+
* @internal — framework use only
|
|
35
|
+
*/
|
|
36
|
+
export declare function coerceSlotParams(slotChain: Array<{
|
|
37
|
+
segmentType: string;
|
|
38
|
+
paramName?: string;
|
|
39
|
+
}>, rawParams: Record<string, string | string[]>): Record<string, string | string[]>;
|
|
22
40
|
/**
|
|
23
41
|
* Run segment param coercion on the matched route's segments.
|
|
24
42
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"param-coercion.d.ts","sourceRoot":"","sources":["../../src/server/param-coercion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAahD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAEzF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgG1E"}
|
|
1
|
+
{"version":3,"file":"param-coercion.d.ts","sourceRoot":"","sources":["../../src/server/param-coercion.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAahD;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,GAAG,IAAI,GAAG,IAAI,CAEzF;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,KAAK,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,EAC7D,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAC3C,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAuCnC;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAgG1E"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAID;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAavB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"pipeline-phases.d.ts","sourceRoot":"","sources":["../../src/server/pipeline-phases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAoBH,OAAO,EAA2C,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAC7E,OAAO,KAAK,EAAE,mBAAmB,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAKrF,UAAU,aAAa;IACrB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,CAAC,EAAE,mBAAmB,CAAC;CACpC;AAID;;;;;GAKG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,QAAQ,EAAE,aAAa,EACvB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,YAAY,CAAC,CAavB;AAID;;;;GAIG;AACH,wBAAsB,kBAAkB,CACtC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,aAAa,EAAE,aAAa,GAC3B,OAAO,CAAC,YAAY,CAAC,CA6DvB;AAID;;;GAGG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,eAAe,EAAE,OAAO,EACxB,oBAAoB,EAAE,OAAO,EAC7B,EAAE,iBAAiB,EAAE,YAAY,EAAE,EAAE,aAAa,GACjD,OAAO,CAAC,YAAY,CAAC,CAkBvB;AAID;;;;;;;;;;GAUG;AACH,wBAAsB,aAAa,CACjC,MAAM,EAAE,cAAc,EACtB,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,QAAQ,CAAC,CAiQnB"}
|
|
@@ -32,6 +32,13 @@ export interface RouteMatch {
|
|
|
32
32
|
segments: ManifestSegmentNode[];
|
|
33
33
|
/** Extracted segment params (catch-all segments produce string[]). */
|
|
34
34
|
segmentParams: Record<string, string | string[]>;
|
|
35
|
+
/**
|
|
36
|
+
* Raw segment params before codec coercion. Always string or string[].
|
|
37
|
+
* Used by slot resolution to reconstruct URL parts — coerced params may
|
|
38
|
+
* have been transformed by codecs and are unsuitable for URL matching.
|
|
39
|
+
* Set by the pipeline before coercion runs.
|
|
40
|
+
*/
|
|
41
|
+
rawSegmentParams?: Record<string, string | string[]>;
|
|
35
42
|
/** Middleware chain from the segment tree, ordered root-to-leaf. */
|
|
36
43
|
middlewareChain: MiddlewareFn[];
|
|
37
44
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"pipeline.d.ts","sourceRoot":"","sources":["../../src/server/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -40,16 +40,16 @@ export declare function getSearchParams(): URLSearchParams;
|
|
|
40
40
|
/**
|
|
41
41
|
* Returns the current request's coerced segment params.
|
|
42
42
|
*
|
|
43
|
-
* The optional `
|
|
44
|
-
* it does not affect the runtime return value. Pass a
|
|
45
|
-
* (e.g. `'/[artistSlug]/[year]'`) to narrow the return type to the
|
|
46
|
-
* exact params shape for that
|
|
43
|
+
* The optional `segmentPath` argument exists only for TypeScript narrowing —
|
|
44
|
+
* it does not affect the runtime return value. Pass a segment path
|
|
45
|
+
* (e.g. `'/(browse)/[artistSlug]/[year]'`) to narrow the return type to the
|
|
46
|
+
* exact params shape for that segment.
|
|
47
47
|
*
|
|
48
|
-
* Without
|
|
48
|
+
* Without an argument, returns all coerced params with optional types.
|
|
49
49
|
*
|
|
50
50
|
* See design/41-global-params.md §Function Signatures
|
|
51
51
|
*/
|
|
52
|
-
export declare function getSegmentParams(
|
|
52
|
+
export declare function getSegmentParams(segmentPath?: string): Record<string, string | string[]>;
|
|
53
53
|
/**
|
|
54
54
|
* Set the segment params on the current request context.
|
|
55
55
|
* Called by the pipeline after route matching and param coercion.
|
|
@@ -58,12 +58,21 @@ export declare function getSegmentParams(route?: string): Record<string, string
|
|
|
58
58
|
*/
|
|
59
59
|
export declare function setSegmentParams(params: Record<string, string | string[]>): void;
|
|
60
60
|
/**
|
|
61
|
-
* Store
|
|
62
|
-
*
|
|
61
|
+
* Store per-slot coerced segment params in the current request context.
|
|
62
|
+
* Called by the route element builder when resolving parallel slots.
|
|
63
63
|
*
|
|
64
|
+
* @param segmentPath — The slot's full tree path (e.g. '/(browse)/@shows/[artistSlug]/[...year]')
|
|
65
|
+
* @param params — The slot's coerced segment params
|
|
64
66
|
* @internal — framework use only
|
|
65
67
|
*/
|
|
66
|
-
export declare function
|
|
68
|
+
export declare function setSlotParams(segmentPath: string, params: Record<string, string | string[]>): void;
|
|
69
|
+
/**
|
|
70
|
+
* Store the matched segment path (e.g. '/(browse)/[artistSlug]/[year]') for
|
|
71
|
+
* dev-mode validation in getSegmentParams().
|
|
72
|
+
*
|
|
73
|
+
* @internal — framework use only
|
|
74
|
+
*/
|
|
75
|
+
export declare function setMatchedSegmentPath(segmentPath: string): void;
|
|
67
76
|
/**
|
|
68
77
|
* Returns the raw search string from the current request URL (e.g. "?foo=bar").
|
|
69
78
|
* Synchronous — safe for use in `redirect()` which throws synchronously.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,iBAAiB,EAA4B,MAAM,mBAAmB,CAAC;AAOhF,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAQ7B;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAS5C;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,eAAe,CASjD;AAaD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,iBAAiB,EAA4B,MAAM,mBAAmB,CAAC;AAOhF,OAAO,EAAE,iBAAiB,EAAE,CAAC;AAQ7B;;;;;GAKG;AACH,wBAAgB,UAAU,IAAI,eAAe,CAS5C;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAG1D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,eAAe,CASjD;AAaD;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CA+CxF;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GAAG,IAAI,CAMhF;AAED;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,WAAW,EAAE,MAAM,EACnB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,GACxC,IAAI,CAKN;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAI/D;AAkBD;;;;;;;;GAQG;AACH,wBAAgB,sBAAsB,IAAI,MAAM,CAG/C;AAID;;;;GAIG;AACH,MAAM,MAAM,eAAe,GAAG,IAAI,CAChC,OAAO,EACP,KAAK,GAAG,KAAK,GAAG,SAAS,GAAG,MAAM,GAAG,QAAQ,GAAG,SAAS,GAAG,OAAO,MAAM,CAAC,QAAQ,CACnF,CAAC;AAIF;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAmBrE;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAK9D;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,IAAI,IAAI,CAK1C;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAmBhE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"route-element-builder.d.ts","sourceRoot":"","sources":["../../src/server/route-element-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAa7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAezD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAM7D;AAID;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAID,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACvC;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC;IAC5B,2CAA2C;IAC3C,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,wDAAwD;IACxD,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,qCAAqC;IACrC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,MAAM,EAAE,UAAU,GAAG,cAAc;aACnC,gBAAgB,EAAE,oBAAoB,EAAE;aACxC,QAAQ,EAAE,mBAAmB,EAAE;gBAF/B,MAAM,EAAE,UAAU,GAAG,cAAc,EACnC,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,QAAQ,EAAE,mBAAmB,EAAE;CAIlD;AA8DD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,YAAY,CAAC,EAAE,mBAAmB,EAClC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GACnC,OAAO,CAAC,kBAAkB,CAAC,
|
|
1
|
+
{"version":3,"file":"route-element-builder.d.ts","sourceRoot":"","sources":["../../src/server/route-element-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAKH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,OAAO,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAa7D,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAezD;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,OAAO,GAAG,OAAO,CAM7D;AAID;;;GAGG;AACH,qBAAa,kBAAmB,SAAQ,KAAK;gBAC/B,OAAO,EAAE,MAAM;CAI5B;AAID,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;CACvC;AAED,+CAA+C;AAC/C,MAAM,WAAW,oBAAoB;IACnC,SAAS,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC;IAC3C,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,+CAA+C;AAC/C,MAAM,WAAW,kBAAkB;IACjC,wFAAwF;IACxF,OAAO,EAAE,KAAK,CAAC,YAAY,CAAC;IAC5B,2CAA2C;IAC3C,YAAY,EAAE,WAAW,EAAE,CAAC;IAC5B,wDAAwD;IACxD,gBAAgB,EAAE,oBAAoB,EAAE,CAAC;IACzC,qCAAqC;IACrC,QAAQ,EAAE,mBAAmB,EAAE,CAAC;IAChC,4DAA4D;IAC5D,gBAAgB,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,eAAe,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;;;;;;GAOG;AACH,qBAAa,sBAAuB,SAAQ,KAAK;aAE7B,MAAM,EAAE,UAAU,GAAG,cAAc;aACnC,gBAAgB,EAAE,oBAAoB,EAAE;aACxC,QAAQ,EAAE,mBAAmB,EAAE;gBAF/B,MAAM,EAAE,UAAU,GAAG,cAAc,EACnC,gBAAgB,EAAE,oBAAoB,EAAE,EACxC,QAAQ,EAAE,mBAAmB,EAAE;CAIlD;AA8DD;;;;;;;;;;;;;GAaG;AACH,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,OAAO,EACZ,KAAK,EAAE,UAAU,EACjB,YAAY,CAAC,EAAE,mBAAmB,EAClC,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI,GACnC,OAAO,CAAC,kBAAkB,CAAC,CAqW7B"}
|
|
@@ -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,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;
|
|
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,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAIL,KAAK,iBAAiB,EACvB,MAAM,sBAAsB,CAAC;AAY9B,6DAA6D;AAC7D,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,mBAAmB,GAAG,WAAW,CAAC,YAAY,CAAC,CAAC;AAE5D;;;;;;;;GAQG;AACH,MAAM,WAAW,YAAa,SAAQ,SAAS,CAAC,YAAY,CAAC;IAC3D,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,YAAY,GACrB,CAAC,QAAQ,EAAE,MAAM,KAAK,UAAU,GAAG,IAAI,CAEzC;AAsCD,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;IAC7B;;;OAGG;IACH,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,YAAY,GACrB,CAAC,QAAQ,EAAE,MAAM,KAAK,kBAAkB,GAAG,IAAI,CAMjD"}
|
|
@@ -29,6 +29,6 @@ type CreateElementFn = (...args: unknown[]) => React.ReactElement;
|
|
|
29
29
|
* 2. Layouts from each segment in the slot's matched chain
|
|
30
30
|
* 3. SlotAccessGate if the slot root has access.ts
|
|
31
31
|
*/
|
|
32
|
-
export declare function resolveSlotElement(slotNode: ManifestSegmentNode, match: RouteMatch, h: CreateElementFn, interception?: InterceptionContext): Promise<React.ReactElement | null>;
|
|
32
|
+
export declare function resolveSlotElement(slotNode: ManifestSegmentNode, match: RouteMatch, h: CreateElementFn, interception?: InterceptionContext, parentTreePath?: string): Promise<React.ReactElement | null>;
|
|
33
33
|
export {};
|
|
34
34
|
//# sourceMappingURL=slot-resolver.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slot-resolver.d.ts","sourceRoot":"","sources":["../../src/server/slot-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"slot-resolver.d.ts","sourceRoot":"","sources":["../../src/server/slot-resolver.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAQH,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAK9D,KAAK,eAAe,GAAG,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,KAAK,CAAC,YAAY,CAAC;AAgClE;;;;;;;;;;GAUG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,mBAAmB,EAC7B,KAAK,EAAE,UAAU,EACjB,CAAC,EAAE,eAAe,EAClB,YAAY,CAAC,EAAE,mBAAmB,EAClC,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,KAAK,CAAC,YAAY,GAAG,IAAI,CAAC,CAgHpC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared URL-matching tree walker for segment trees.
|
|
3
|
+
*
|
|
4
|
+
* Both the main route matcher (`route-matcher.ts`) and slot resolver
|
|
5
|
+
* (`slot-resolver.ts`) need to walk a SegmentNode tree, matching URL
|
|
6
|
+
* parts against children with the same priority semantics:
|
|
7
|
+
*
|
|
8
|
+
* static > dynamic > catch-all > optional-catch-all
|
|
9
|
+
*
|
|
10
|
+
* Before this module, each had its own walker with subtle divergences
|
|
11
|
+
* (different group handling, missing backtracking, incomplete
|
|
12
|
+
* optional-catch-all support). This shared walker is the single
|
|
13
|
+
* source of truth for URL-to-segment matching.
|
|
14
|
+
*
|
|
15
|
+
* See design/07-routing.md §"Request Lifecycle" and TIM-940.
|
|
16
|
+
*/
|
|
17
|
+
import type { SegmentNode } from '../routing/types.js';
|
|
18
|
+
/** Result of matching URL parts against a segment tree. */
|
|
19
|
+
export interface TreeMatchResult<TFile> {
|
|
20
|
+
/** Matched segment chain from root to leaf, inclusive. */
|
|
21
|
+
chain: SegmentNode<TFile>[];
|
|
22
|
+
/** Collected params, keyed by param name. Catch-all params are string[]. */
|
|
23
|
+
params: Record<string, string | string[]>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Match URL path parts against a segment tree.
|
|
27
|
+
*
|
|
28
|
+
* Walks the tree depth-first with backtracking, applying priority
|
|
29
|
+
* ordering globally across group boundaries. Returns the matched
|
|
30
|
+
* segment chain and collected params, or null if no route matches.
|
|
31
|
+
*
|
|
32
|
+
* A match requires a terminal node (one with `page` or `route`) at
|
|
33
|
+
* the leaf. Catch-all and optional-catch-all segments only match if
|
|
34
|
+
* they are terminal.
|
|
35
|
+
*
|
|
36
|
+
* @param root The root segment node to start matching from.
|
|
37
|
+
* @param parts URL path parts (e.g. ['blog', 'hello-world']).
|
|
38
|
+
* Empty array matches the root itself (if terminal).
|
|
39
|
+
*/
|
|
40
|
+
export declare function matchUrlParts<TFile>(root: SegmentNode<TFile>, parts: string[]): TreeMatchResult<TFile> | null;
|
|
41
|
+
//# sourceMappingURL=tree-match.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree-match.d.ts","sourceRoot":"","sources":["../../src/server/tree-match.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIvD,2DAA2D;AAC3D,MAAM,WAAW,eAAe,CAAC,KAAK;IACpC,0DAA0D;IAC1D,KAAK,EAAE,WAAW,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5B,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;CAC3C;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,aAAa,CAAC,KAAK,EACjC,IAAI,EAAE,WAAW,CAAC,KAAK,CAAC,EACxB,KAAK,EAAE,MAAM,EAAE,GACd,eAAe,CAAC,KAAK,CAAC,GAAG,IAAI,CAQ/B"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@timber-js/app",
|
|
3
|
-
"version": "0.2.0-alpha.
|
|
3
|
+
"version": "0.2.0-alpha.117",
|
|
4
4
|
"description": "Vite-native React framework built for Servers and Serverless Platforms — correct HTTP semantics, real status codes, pages that work without JavaScript",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cloudflare-workers",
|
|
@@ -115,15 +115,15 @@ export function notifyParamsListeners(): void {
|
|
|
115
115
|
* When called outside a React component (e.g., in test assertions),
|
|
116
116
|
* falls back to the module-level snapshot.
|
|
117
117
|
*
|
|
118
|
-
* @overload Typed — when a known
|
|
118
|
+
* @overload Typed — when a known segment path is passed, returns the
|
|
119
119
|
* exact params shape from the generated Routes interface.
|
|
120
120
|
* @overload Fallback — returns the generic params record.
|
|
121
121
|
*/
|
|
122
122
|
export function useSegmentParams<R extends keyof Routes>(
|
|
123
|
-
|
|
123
|
+
segmentPath: R
|
|
124
124
|
): Routes[R] extends { segmentParams: infer P } ? P : Record<string, string | string[]>;
|
|
125
|
-
export function useSegmentParams(
|
|
126
|
-
export function useSegmentParams(
|
|
125
|
+
export function useSegmentParams(segmentPath?: string): Record<string, string | string[]>;
|
|
126
|
+
export function useSegmentParams(_segmentPath?: string): Record<string, string | string[]> {
|
|
127
127
|
// Try reading from NavigationContext (client-side, inside React tree).
|
|
128
128
|
// During SSR, no NavigationProvider is mounted, so this returns null.
|
|
129
129
|
// When called outside a React component, useContext throws — caught below.
|
|
@@ -10,6 +10,9 @@
|
|
|
10
10
|
export interface RouteEntry {
|
|
11
11
|
/** URL path pattern (e.g. "/products/[id]") */
|
|
12
12
|
urlPath: string;
|
|
13
|
+
/** Full tree path including groups and slots (e.g. "/(browse)/[artistSlug]/@shows/[year]").
|
|
14
|
+
* Uniquely identifies a segment — unlike urlPath which strips groups/slots. */
|
|
15
|
+
segmentPath: string;
|
|
13
16
|
/** Accumulated params from all ancestor dynamic segments */
|
|
14
17
|
params: ParamEntry[];
|
|
15
18
|
/** Whether the page.tsx exports searchParams */
|
package/src/routing/codegen.ts
CHANGED
|
@@ -48,7 +48,7 @@ export function generateRouteMap(tree: RouteTree, options: CodegenOptions = {}):
|
|
|
48
48
|
const hasSchema = options.hasSchema ?? detectSchema(options.appDir);
|
|
49
49
|
|
|
50
50
|
const routes: RouteEntry[] = [];
|
|
51
|
-
collectRoutes(tree.root, [], [], routes, hasSchema);
|
|
51
|
+
collectRoutes(tree.root, [], [], '', routes, hasSchema);
|
|
52
52
|
|
|
53
53
|
// Sort routes alphabetically for deterministic output
|
|
54
54
|
routes.sort((a, b) => a.urlPath.localeCompare(b.urlPath));
|
|
@@ -80,9 +80,13 @@ function collectRoutes(
|
|
|
80
80
|
node: SegmentNode,
|
|
81
81
|
ancestorParams: ParamEntry[],
|
|
82
82
|
ancestorParamsFiles: string[],
|
|
83
|
+
parentTreePath: string,
|
|
83
84
|
routes: RouteEntry[],
|
|
84
85
|
hasSchema: boolean
|
|
85
86
|
): void {
|
|
87
|
+
// Build the tree path (includes groups, slots — uniquely identifies this segment).
|
|
88
|
+
// Root node has empty segmentName, producing treePath = ''.
|
|
89
|
+
const treePath = node.segmentName ? `${parentTreePath}/${node.segmentName}` : parentTreePath;
|
|
86
90
|
// TIM-834: Identify this segment's own params.ts (if it has a
|
|
87
91
|
// segmentParams export). The full chain of params.ts files in the
|
|
88
92
|
// route ancestry is threaded down via `ancestorParamsFiles`; codec
|
|
@@ -148,6 +152,7 @@ function collectRoutes(
|
|
|
148
152
|
|
|
149
153
|
const entry: RouteEntry = {
|
|
150
154
|
urlPath: node.urlPath,
|
|
155
|
+
segmentPath: treePath || '/',
|
|
151
156
|
params: resolvedParams,
|
|
152
157
|
hasSearchParams: false,
|
|
153
158
|
isApiRoute,
|
|
@@ -170,12 +175,12 @@ function collectRoutes(
|
|
|
170
175
|
|
|
171
176
|
// Recurse into children
|
|
172
177
|
for (const child of node.children) {
|
|
173
|
-
collectRoutes(child, params, nextAncestorFiles, routes, hasSchema);
|
|
178
|
+
collectRoutes(child, params, nextAncestorFiles, treePath, routes, hasSchema);
|
|
174
179
|
}
|
|
175
180
|
|
|
176
181
|
// Recurse into slots (they share the parent's URL path, but may have their own pages)
|
|
177
182
|
for (const slot of Object.values(node.slots)) {
|
|
178
|
-
collectRoutes(slot, params, nextAncestorFiles, routes, hasSchema);
|
|
183
|
+
collectRoutes(slot, params, nextAncestorFiles, treePath, routes, hasSchema);
|
|
179
184
|
}
|
|
180
185
|
}
|
|
181
186
|
|
|
@@ -245,14 +250,14 @@ function formatSchemaTypes(routes: RouteEntry[]): string[] {
|
|
|
245
250
|
lines.push('/** Union of all valid route patterns. */');
|
|
246
251
|
lines.push('export type TimberRoute = keyof TimberSegmentParams;');
|
|
247
252
|
lines.push('');
|
|
248
|
-
lines.push('/** Maps each
|
|
253
|
+
lines.push('/** Maps each segment path to its accumulated segment params. */');
|
|
249
254
|
lines.push('export interface TimberSegmentParams {');
|
|
250
255
|
|
|
251
256
|
for (const route of routes) {
|
|
252
257
|
if (route.params.length === 0) {
|
|
253
|
-
lines.push(` '${route.
|
|
258
|
+
lines.push(` '${route.segmentPath}': {};`);
|
|
254
259
|
} else {
|
|
255
|
-
lines.push(` '${route.
|
|
260
|
+
lines.push(` '${route.segmentPath}': {`);
|
|
256
261
|
for (const p of route.params) {
|
|
257
262
|
lines.push(` ${p.name}: ${buildSchemaParamType(p)};`);
|
|
258
263
|
}
|
|
@@ -356,7 +361,9 @@ function formatDeclarationFile(
|
|
|
356
361
|
lines.push("declare module '@timber-js/app/server' {");
|
|
357
362
|
for (const route of dynamicRoutes) {
|
|
358
363
|
const paramsType = formatParamsType(route.params, importBase, hasSchema);
|
|
359
|
-
lines.push(
|
|
364
|
+
lines.push(
|
|
365
|
+
` export function getSegmentParams(segmentPath: '${route.segmentPath}'): ${paramsType}`
|
|
366
|
+
);
|
|
360
367
|
}
|
|
361
368
|
lines.push(' export function getSegmentParams(): Record<string, string | string[]>');
|
|
362
369
|
lines.push('}');
|
|
@@ -372,11 +379,13 @@ function formatDeclarationFile(
|
|
|
372
379
|
);
|
|
373
380
|
lines.push('');
|
|
374
381
|
|
|
375
|
-
//
|
|
382
|
+
// useSegmentParams overloads
|
|
376
383
|
if (dynamicRoutes.length > 0) {
|
|
377
384
|
for (const route of dynamicRoutes) {
|
|
378
385
|
const paramsType = formatParamsType(route.params, importBase, hasSchema);
|
|
379
|
-
lines.push(
|
|
386
|
+
lines.push(
|
|
387
|
+
` export function useSegmentParams(segmentPath: '${route.segmentPath}'): ${paramsType}`
|
|
388
|
+
);
|
|
380
389
|
}
|
|
381
390
|
lines.push(' export function useSegmentParams(): Record<string, string | string[]>');
|
|
382
391
|
lines.push('');
|
|
@@ -60,12 +60,25 @@ export interface RequestContextStore {
|
|
|
60
60
|
*/
|
|
61
61
|
segmentParams?: Record<string, string | string[]>;
|
|
62
62
|
/**
|
|
63
|
-
* The matched
|
|
64
|
-
*
|
|
65
|
-
*
|
|
63
|
+
* The matched segment path (e.g. '/(browse)/[artistSlug]/[year]').
|
|
64
|
+
* Includes route groups and parallel slots — uniquely identifies the
|
|
65
|
+
* segment in the route tree. Set by the pipeline alongside segmentParams.
|
|
66
|
+
* Used by getSegmentParams() for dev-mode validation.
|
|
66
67
|
* See design/41-global-params.md §Runtime Validation
|
|
67
68
|
*/
|
|
68
|
-
|
|
69
|
+
matchedSegmentPath?: string;
|
|
70
|
+
/**
|
|
71
|
+
* Per-slot coerced segment params, keyed by the slot's full tree path
|
|
72
|
+
* (e.g. '/(browse)/@shows/[artistSlug]/[...year]').
|
|
73
|
+
*
|
|
74
|
+
* Each slot walks its own segment tree and may interpret URL parts
|
|
75
|
+
* differently from the main route (e.g. catch-all vs dynamic). This
|
|
76
|
+
* map stores slot-specific params so getSegmentParams(segmentPath)
|
|
77
|
+
* returns the correct types for slot pages.
|
|
78
|
+
*
|
|
79
|
+
* See design/07-routing.md §"Parallel Slot Params"
|
|
80
|
+
*/
|
|
81
|
+
slotParamsMap?: Map<string, Record<string, string | string[]>>;
|
|
69
82
|
/** Outgoing Set-Cookie entries (name → serialized value + options). Last write wins. */
|
|
70
83
|
cookieJar: Map<string, CookieEntry>;
|
|
71
84
|
/** Whether the response has flushed (headers committed). */
|
|
@@ -36,6 +36,64 @@ export function setGlobalSchemaCodecs(codecs: Record<string, Codec<unknown>> | n
|
|
|
36
36
|
_globalCodecs = codecs;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
/**
|
|
40
|
+
* Coerce raw slot params through global schema codecs.
|
|
41
|
+
*
|
|
42
|
+
* Each slot segment that has a paramName is looked up in the global codec
|
|
43
|
+
* map by its bracket key (e.g. '[...year]' for catch-all). If a codec
|
|
44
|
+
* exists, the raw value is parsed through it. If no codec exists or no
|
|
45
|
+
* global codecs are registered, the raw value passes through unchanged.
|
|
46
|
+
*
|
|
47
|
+
* Unlike main route coercion, this does NOT throw ParamCoercionError on
|
|
48
|
+
* failure — slots degrade gracefully. A failed coercion logs a warning
|
|
49
|
+
* in dev mode and keeps the raw value.
|
|
50
|
+
*
|
|
51
|
+
* @internal — framework use only
|
|
52
|
+
*/
|
|
53
|
+
export function coerceSlotParams(
|
|
54
|
+
slotChain: Array<{ segmentType: string; paramName?: string }>,
|
|
55
|
+
rawParams: Record<string, string | string[]>
|
|
56
|
+
): Record<string, string | string[]> {
|
|
57
|
+
const globalCodecs = _globalCodecs;
|
|
58
|
+
if (!globalCodecs) return rawParams;
|
|
59
|
+
|
|
60
|
+
const result: Record<string, string | string[]> = Object.create(null);
|
|
61
|
+
for (const key of Object.keys(rawParams)) {
|
|
62
|
+
result[key] = rawParams[key];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
for (const segment of slotChain) {
|
|
66
|
+
if (!segment.paramName) continue;
|
|
67
|
+
const bracketKey = toBracketKey(segment.segmentType, segment.paramName);
|
|
68
|
+
const codec = globalCodecs[bracketKey];
|
|
69
|
+
if (!codec) continue;
|
|
70
|
+
|
|
71
|
+
const key = segment.paramName;
|
|
72
|
+
if (!(key in result)) continue;
|
|
73
|
+
|
|
74
|
+
try {
|
|
75
|
+
result[key] = sanitizeParamValue(codec.parse(result[key] as string | string[])) as
|
|
76
|
+
| string
|
|
77
|
+
| string[];
|
|
78
|
+
} catch (err) {
|
|
79
|
+
// Slot param coercion failures are non-fatal — keep the raw value.
|
|
80
|
+
// The main route already validated the URL; the slot just interprets
|
|
81
|
+
// the same parts differently.
|
|
82
|
+
if (isDebug()) {
|
|
83
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
84
|
+
console.warn(
|
|
85
|
+
`[timber] Slot param coercion failed for "${key}" (codec: ${bracketKey})\n` +
|
|
86
|
+
` Error: ${message}\n` +
|
|
87
|
+
` Raw value: ${JSON.stringify(result[key])}\n` +
|
|
88
|
+
` Keeping raw value.`
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return result as Record<string, string | string[]>;
|
|
95
|
+
}
|
|
96
|
+
|
|
39
97
|
/**
|
|
40
98
|
* Run segment param coercion on the matched route's segments.
|
|
41
99
|
*
|
|
@@ -20,7 +20,7 @@ import {
|
|
|
20
20
|
applyRequestHeaderOverlay,
|
|
21
21
|
setMutableCookieContext,
|
|
22
22
|
setSegmentParams,
|
|
23
|
-
|
|
23
|
+
setMatchedSegmentPath,
|
|
24
24
|
} from './request-context.js';
|
|
25
25
|
import { withSpan } from './tracing.js';
|
|
26
26
|
import { logRenderError } from './logger.js';
|
|
@@ -380,6 +380,11 @@ export async function handleRequest(
|
|
|
380
380
|
// Load params.ts modules from matched segments and coerce raw string
|
|
381
381
|
// params through defineSegmentParams codecs. Coercion failure → 404
|
|
382
382
|
// (middleware never runs). See design/07-routing.md §"Where Coercion Runs"
|
|
383
|
+
//
|
|
384
|
+
// Snapshot raw params before coercion — slot resolution needs the
|
|
385
|
+
// original string values to reconstruct URL parts for tree matching.
|
|
386
|
+
// Coerced params may have been transformed by codecs.
|
|
387
|
+
match.rawSegmentParams = { ...match.segmentParams };
|
|
383
388
|
try {
|
|
384
389
|
await coerceSegmentParams(match);
|
|
385
390
|
} catch (error) {
|
|
@@ -419,12 +424,14 @@ export async function handleRequest(
|
|
|
419
424
|
// See design/07-routing.md §"params.ts — Convention File for Typed Params"
|
|
420
425
|
setSegmentParams(match.segmentParams);
|
|
421
426
|
|
|
422
|
-
// Store the matched
|
|
423
|
-
//
|
|
424
|
-
const
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
427
|
+
// Store the matched segment path for dev-mode validation in getSegmentParams().
|
|
428
|
+
// Build the tree path from the segment chain (includes groups and slots).
|
|
429
|
+
const segmentPath =
|
|
430
|
+
match.segments
|
|
431
|
+
.map((s) => s.segmentName)
|
|
432
|
+
.filter(Boolean)
|
|
433
|
+
.join('/') || '/';
|
|
434
|
+
setMatchedSegmentPath(segmentPath.startsWith('/') ? segmentPath : `/${segmentPath}`);
|
|
428
435
|
|
|
429
436
|
// Bypass middleware for synthetic re-render requests built by the
|
|
430
437
|
// action-dispatch wrapper after a no-JS form validation failure.
|
package/src/server/pipeline.ts
CHANGED
|
@@ -50,6 +50,13 @@ export interface RouteMatch {
|
|
|
50
50
|
segments: ManifestSegmentNode[];
|
|
51
51
|
/** Extracted segment params (catch-all segments produce string[]). */
|
|
52
52
|
segmentParams: Record<string, string | string[]>;
|
|
53
|
+
/**
|
|
54
|
+
* Raw segment params before codec coercion. Always string or string[].
|
|
55
|
+
* Used by slot resolution to reconstruct URL parts — coerced params may
|
|
56
|
+
* have been transformed by codecs and are unsuitable for URL matching.
|
|
57
|
+
* Set by the pipeline before coercion runs.
|
|
58
|
+
*/
|
|
59
|
+
rawSegmentParams?: Record<string, string | string[]>;
|
|
53
60
|
/** Middleware chain from the segment tree, ordered root-to-leaf. */
|
|
54
61
|
middlewareChain: MiddlewareFn[];
|
|
55
62
|
}
|
|
@@ -89,16 +89,16 @@ _setGetSegmentParamsFn(getSegmentParams);
|
|
|
89
89
|
/**
|
|
90
90
|
* Returns the current request's coerced segment params.
|
|
91
91
|
*
|
|
92
|
-
* The optional `
|
|
93
|
-
* it does not affect the runtime return value. Pass a
|
|
94
|
-
* (e.g. `'/[artistSlug]/[year]'`) to narrow the return type to the
|
|
95
|
-
* exact params shape for that
|
|
92
|
+
* The optional `segmentPath` argument exists only for TypeScript narrowing —
|
|
93
|
+
* it does not affect the runtime return value. Pass a segment path
|
|
94
|
+
* (e.g. `'/(browse)/[artistSlug]/[year]'`) to narrow the return type to the
|
|
95
|
+
* exact params shape for that segment.
|
|
96
96
|
*
|
|
97
|
-
* Without
|
|
97
|
+
* Without an argument, returns all coerced params with optional types.
|
|
98
98
|
*
|
|
99
99
|
* See design/41-global-params.md §Function Signatures
|
|
100
100
|
*/
|
|
101
|
-
export function getSegmentParams(
|
|
101
|
+
export function getSegmentParams(segmentPath?: string): Record<string, string | string[]> {
|
|
102
102
|
const store = requestContextAls.getStore();
|
|
103
103
|
if (!store) {
|
|
104
104
|
throw new Error(
|
|
@@ -113,18 +113,31 @@ export function getSegmentParams(route?: string): Record<string, string | string
|
|
|
113
113
|
);
|
|
114
114
|
}
|
|
115
115
|
|
|
116
|
-
//
|
|
117
|
-
//
|
|
118
|
-
//
|
|
116
|
+
// Check slot params map first — parallel slots may have different param
|
|
117
|
+
// types than the main route (e.g. catch-all [..year] → string[] vs
|
|
118
|
+
// dynamic [year] → string). If the requested segment path matches a
|
|
119
|
+
// stored slot, return its params merged with the main route's.
|
|
120
|
+
if (segmentPath && store.slotParamsMap?.has(segmentPath)) {
|
|
121
|
+
const slotParams = store.slotParamsMap.get(segmentPath)!;
|
|
122
|
+
// Merge: main params as base, slot-specific params override.
|
|
123
|
+
// This ensures params from segments above the slot (that the slot
|
|
124
|
+
// doesn't re-derive) are still available.
|
|
125
|
+
return { ...store.segmentParams, ...slotParams };
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Dev-mode validation: warn when the segment path expects dynamic
|
|
129
|
+
// segments that don't exist on the actual matched segment. This catches
|
|
130
|
+
// bugs like passing a child segment's $segment to a parent layout.
|
|
131
|
+
// Skip for slot paths — they're validated against their own chain.
|
|
119
132
|
// See design/41-global-params.md §Runtime Validation
|
|
120
|
-
if (
|
|
121
|
-
const expected = extractDynamicSegments(
|
|
122
|
-
const actual = extractDynamicSegments(store.
|
|
133
|
+
if (segmentPath && isDebug() && store.matchedSegmentPath) {
|
|
134
|
+
const expected = extractDynamicSegments(segmentPath);
|
|
135
|
+
const actual = extractDynamicSegments(store.matchedSegmentPath);
|
|
123
136
|
const missing = expected.filter((s) => !actual.includes(s));
|
|
124
137
|
|
|
125
138
|
if (missing.length > 0) {
|
|
126
139
|
console.warn(
|
|
127
|
-
`[timber] getSegmentParams('${
|
|
140
|
+
`[timber] getSegmentParams('${segmentPath}') called but current segment is '${store.matchedSegmentPath}'\n` +
|
|
128
141
|
` Missing params: ${missing.join(', ')}\n` +
|
|
129
142
|
` These will be undefined at runtime despite the type annotation.`
|
|
130
143
|
);
|
|
@@ -149,15 +162,33 @@ export function setSegmentParams(params: Record<string, string | string[]>): voi
|
|
|
149
162
|
}
|
|
150
163
|
|
|
151
164
|
/**
|
|
152
|
-
* Store
|
|
153
|
-
*
|
|
165
|
+
* Store per-slot coerced segment params in the current request context.
|
|
166
|
+
* Called by the route element builder when resolving parallel slots.
|
|
167
|
+
*
|
|
168
|
+
* @param segmentPath — The slot's full tree path (e.g. '/(browse)/@shows/[artistSlug]/[...year]')
|
|
169
|
+
* @param params — The slot's coerced segment params
|
|
170
|
+
* @internal — framework use only
|
|
171
|
+
*/
|
|
172
|
+
export function setSlotParams(
|
|
173
|
+
segmentPath: string,
|
|
174
|
+
params: Record<string, string | string[]>
|
|
175
|
+
): void {
|
|
176
|
+
const store = requestContextAls.getStore();
|
|
177
|
+
if (!store) return; // non-throwing — optional diagnostic
|
|
178
|
+
if (!store.slotParamsMap) store.slotParamsMap = new Map();
|
|
179
|
+
store.slotParamsMap.set(segmentPath, params);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Store the matched segment path (e.g. '/(browse)/[artistSlug]/[year]') for
|
|
184
|
+
* dev-mode validation in getSegmentParams().
|
|
154
185
|
*
|
|
155
186
|
* @internal — framework use only
|
|
156
187
|
*/
|
|
157
|
-
export function
|
|
188
|
+
export function setMatchedSegmentPath(segmentPath: string): void {
|
|
158
189
|
const store = requestContextAls.getStore();
|
|
159
190
|
if (!store) return; // non-throwing — optional diagnostic
|
|
160
|
-
store.
|
|
191
|
+
store.matchedSegmentPath = segmentPath;
|
|
161
192
|
}
|
|
162
193
|
|
|
163
194
|
/**
|
|
@@ -465,7 +465,16 @@ export async function buildRouteElement(
|
|
|
465
465
|
// This prevents leaking layout UI (sidebars, nav) on denied pages.
|
|
466
466
|
// See design/04-authorization.md §"Access Failure".
|
|
467
467
|
if (layoutComponent) {
|
|
468
|
-
// Resolve parallel slots for this layout
|
|
468
|
+
// Resolve parallel slots for this layout.
|
|
469
|
+
// Compute the parent tree path so slots can build their full
|
|
470
|
+
// segment path for per-slot param storage in ALS.
|
|
471
|
+
const parentTreePath =
|
|
472
|
+
'/' +
|
|
473
|
+
segments
|
|
474
|
+
.slice(0, i + 1)
|
|
475
|
+
.map((s) => s.segmentName)
|
|
476
|
+
.filter(Boolean)
|
|
477
|
+
.join('/');
|
|
469
478
|
const slotProps: Record<string, unknown> = {};
|
|
470
479
|
const slotEntries = Object.entries(segment.slots ?? {});
|
|
471
480
|
for (const [slotName, slotNode] of slotEntries) {
|
|
@@ -473,7 +482,8 @@ export async function buildRouteElement(
|
|
|
473
482
|
slotNode as ManifestSegmentNode,
|
|
474
483
|
match,
|
|
475
484
|
h,
|
|
476
|
-
interception
|
|
485
|
+
interception,
|
|
486
|
+
parentTreePath
|
|
477
487
|
);
|
|
478
488
|
}
|
|
479
489
|
|