@emeryld/rrroutes-contract 2.4.12 → 2.4.14
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/README.md +21 -20
- package/dist/core/routesV3.builder.d.ts +29 -21
- package/dist/core/routesV3.core.d.ts +72 -39
- package/dist/index.cjs +98 -128
- package/dist/index.cjs.map +1 -1
- package/dist/index.mjs +99 -129
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -37,8 +37,8 @@ import { z } from 'zod'
|
|
|
37
37
|
|
|
38
38
|
// 1) Describe your API
|
|
39
39
|
const leaves = resource('/v1')
|
|
40
|
-
.sub(
|
|
41
|
-
users
|
|
40
|
+
.sub(
|
|
41
|
+
resource('users')
|
|
42
42
|
.get({
|
|
43
43
|
querySchema: z.object({
|
|
44
44
|
search: z.string().optional(),
|
|
@@ -49,11 +49,13 @@ const leaves = resource('/v1')
|
|
|
49
49
|
),
|
|
50
50
|
description: 'Find users',
|
|
51
51
|
})
|
|
52
|
-
.
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
.sub(
|
|
53
|
+
resource(':userId', undefined, z.string().uuid())
|
|
54
|
+
.patch({
|
|
55
|
+
bodySchema: z.object({ name: z.string().min(1) }),
|
|
56
|
+
outputSchema: z.object({ ok: z.literal(true) }),
|
|
57
|
+
})
|
|
58
|
+
.done(),
|
|
57
59
|
)
|
|
58
60
|
.done(),
|
|
59
61
|
)
|
|
@@ -87,10 +89,9 @@ const key = buildCacheKey({
|
|
|
87
89
|
import { resource } from '@emeryld/rrroutes-contract'
|
|
88
90
|
import { z } from 'zod'
|
|
89
91
|
|
|
90
|
-
const leaves = resource('/api')
|
|
91
|
-
.
|
|
92
|
-
|
|
93
|
-
projects
|
|
92
|
+
const leaves = resource('/api')
|
|
93
|
+
.sub(
|
|
94
|
+
resource('projects')
|
|
94
95
|
.get({
|
|
95
96
|
feed: true, // infinite/feed for clients
|
|
96
97
|
querySchema: z.object({
|
|
@@ -107,15 +108,15 @@ const leaves = resource('/api') // base path, optional inherited cfg
|
|
|
107
108
|
outputSchema: z.object({ id: z.string(), name: z.string() }),
|
|
108
109
|
description: 'Create a project',
|
|
109
110
|
})
|
|
110
|
-
.
|
|
111
|
-
|
|
111
|
+
.sub(
|
|
112
|
+
resource(':projectId', undefined, z.string().uuid())
|
|
112
113
|
.get({ outputSchema: z.object({ id: z.string(), name: z.string() }) })
|
|
113
114
|
.patch({
|
|
114
115
|
bodySchema: z.object({ name: z.string().min(1) }),
|
|
115
116
|
outputSchema: z.object({ id: z.string(), name: z.string() }),
|
|
116
117
|
})
|
|
117
|
-
.sub(
|
|
118
|
-
avatar
|
|
118
|
+
.sub(
|
|
119
|
+
resource('avatar')
|
|
119
120
|
.put({
|
|
120
121
|
bodyFiles: [{ name: 'avatar', maxCount: 1 }], // signals multipart upload
|
|
121
122
|
bodySchema: z.object({ avatar: z.instanceof(Blob) }),
|
|
@@ -130,8 +131,8 @@ const leaves = resource('/api') // base path, optional inherited cfg
|
|
|
130
131
|
.done()
|
|
131
132
|
```
|
|
132
133
|
|
|
133
|
-
- `
|
|
134
|
-
- `
|
|
134
|
+
- `resource(segment, nodeCfg?, idSchema?)` scopes a branch. Pass a segment name (e.g. `'projects'`, `':projectId'`) plus optional per-node config. Supplying an `idSchema` along with a `:param` segment wires up the params schema for all descendants.
|
|
135
|
+
- `sub(childA, childB, ...)` mounts one or more child resources built elsewhere via `resource(...).get(...).done()`. Call it once per branch; pass multiple children at once when needed.
|
|
135
136
|
- Methods (`get/post/put/patch/delete`) merge the active param schema unless you override via `paramsSchema`.
|
|
136
137
|
- `done()` closes a branch and returns the collected readonly tuple of leaves.
|
|
137
138
|
|
|
@@ -201,8 +202,8 @@ const leaves = r
|
|
|
201
202
|
},
|
|
202
203
|
({ collection }) =>
|
|
203
204
|
collection
|
|
204
|
-
.sub(
|
|
205
|
-
stats
|
|
205
|
+
.sub(
|
|
206
|
+
resource('stats')
|
|
206
207
|
.get({
|
|
207
208
|
outputSchema: z.object({ total: z.number() }),
|
|
208
209
|
description: 'Extra endpoint alongside CRUD',
|
|
@@ -280,7 +281,7 @@ function onChatMessage(raw: unknown) {
|
|
|
280
281
|
|
|
281
282
|
### Edge cases and notes
|
|
282
283
|
|
|
283
|
-
- `paramsSchema` on a method overrides the merged schema from
|
|
284
|
+
- `paramsSchema` on a method overrides the merged schema from parent segments—useful when you need stricter validation per verb.
|
|
284
285
|
- `bodyFiles` marks a route as multipart; servers can attach upload middleware, and clients should send `FormData`.
|
|
285
286
|
- CRUD helper only emits create/update routes when the matching `bodySchema` is provided; delete can be disabled via `enable.remove: false`.
|
|
286
287
|
- Feed-only behavior (`feed: true`) is intended for GET endpoints; clients treat them as infinite queries.
|
|
@@ -4,7 +4,6 @@ type ZodTypeAny = z.ZodTypeAny;
|
|
|
4
4
|
type ParamZod<Name extends string, S extends ZodTypeAny> = z.ZodObject<{
|
|
5
5
|
[K in Name]: S;
|
|
6
6
|
}>;
|
|
7
|
-
type MergedParamsResult<PS, Name extends string, P extends ZodTypeAny> = PS extends ZodTypeAny ? z.ZodIntersection<PS, ParamZod<Name, P>> : ParamZod<Name, P>;
|
|
8
7
|
type BaseMethodCfg<C extends MethodCfg> = Merge<Omit<MethodCfg, 'querySchema' | 'outputSchema' | 'feed'>, Omit<C, 'querySchema' | 'outputSchema' | 'feed'>>;
|
|
9
8
|
type FeedField<C extends MethodCfg> = C['feed'] extends true ? {
|
|
10
9
|
feed: true;
|
|
@@ -22,9 +21,29 @@ type ParamsField<C extends MethodCfg, PS> = C['paramsSchema'] extends ZodTypeAny
|
|
|
22
21
|
paramsSchema: PS;
|
|
23
22
|
};
|
|
24
23
|
type EffectiveFeedFields<C extends MethodCfg, PS> = C['feed'] extends true ? FeedField<C> & FeedQueryField<C> & OutputField<C> & ParamsField<C, PS> : FeedField<C> & NonFeedQueryField<C> & OutputField<C> & ParamsField<C, PS>;
|
|
25
|
-
type
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
type WithNodeDefaults<C extends MethodCfg, I extends NodeCfg> = Merge<C, {
|
|
25
|
+
queryExtensionSchema: C['queryExtensionSchema'] extends ZodTypeAny ? C['queryExtensionSchema'] : NodeQueryExtension<I>;
|
|
26
|
+
outputMetaSchema: C['outputMetaSchema'] extends ZodTypeAny ? C['outputMetaSchema'] : NodeOutputMeta<I>;
|
|
27
|
+
}>;
|
|
28
|
+
type EffectiveCfg<C extends MethodCfg, PS, I extends NodeCfg> = Prettify<Merge<MethodCfg, BaseMethodCfg<WithNodeDefaults<C, I>> & EffectiveFeedFields<WithNodeDefaults<C, I>, PS>>>;
|
|
29
|
+
type NodeWithoutSchemas<I extends NodeCfg> = Omit<I, 'queryExtensionSchema' | 'outputMetaSchema'>;
|
|
30
|
+
type BuiltLeaf<M extends HttpMethod, Base extends string, I extends NodeCfg, C extends MethodCfg, PS> = Leaf<M, Base, Merge<NodeWithoutSchemas<I>, LowProfileCfg<EffectiveCfg<C, PS, I>>>>;
|
|
31
|
+
type StripParamName<Name extends string> = Name extends `:${infer P}` ? P : Name;
|
|
32
|
+
type NormalizeBaseLiteral<Base extends string, HasParam extends boolean> = HasParam extends true ? Base extends `:${string}` ? Base : Base extends '' ? '' : `:${Base}` : Base;
|
|
33
|
+
type ParamSchemaForBase<Base extends string, Param extends ZodTypeAny | undefined> = Param extends ZodTypeAny ? ParamZod<StripParamName<Base>, Param> : undefined;
|
|
34
|
+
type ResourceBase<Base extends string, Param extends ZodTypeAny | undefined> = NormalizeBaseLiteral<Base, Param extends ZodTypeAny ? true : false>;
|
|
35
|
+
type NodeQueryExtension<I extends NodeCfg> = I extends {
|
|
36
|
+
queryExtensionSchema?: infer QE;
|
|
37
|
+
} ? QE extends ZodTypeAny ? QE : undefined : undefined;
|
|
38
|
+
type NodeOutputMeta<I extends NodeCfg> = I extends {
|
|
39
|
+
outputMetaSchema?: infer OE;
|
|
40
|
+
} ? OE extends ZodTypeAny ? OE : undefined : undefined;
|
|
41
|
+
type SubResourceCollections = readonly [
|
|
42
|
+
ReadonlyArray<AnyLeafLowProfile>,
|
|
43
|
+
...ReadonlyArray<AnyLeafLowProfile>[]
|
|
44
|
+
];
|
|
45
|
+
type MergeAugmentedCollections<Base extends string, Param extends ZodTypeAny | undefined, Collections extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>>, Acc extends readonly AnyLeafLowProfile[] = []> = Collections extends readonly [infer First, ...infer Rest] ? First extends ReadonlyArray<AnyLeafLowProfile> ? Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>> ? MergeAugmentedCollections<Base, Param, Rest, MergeArray<Acc, AugmentLeaves<Base, Param, First>>> : MergeArray<Acc, AugmentLeaves<Base, Param, First>> : MergeAugmentedCollections<Base, Param, Rest extends ReadonlyArray<ReadonlyArray<AnyLeafLowProfile>> ? Rest : [], Acc> : Acc;
|
|
46
|
+
type MethodFns<Base extends string, Acc extends readonly AnyLeafLowProfile[], I extends NodeCfg, PS extends ZodTypeAny | undefined, Used extends HttpMethod | 'add' | 'sub'> = {
|
|
28
47
|
/**
|
|
29
48
|
* Register a GET leaf at the current path.
|
|
30
49
|
*/
|
|
@@ -55,24 +74,13 @@ type MethodFns<Base extends string, Acc extends readonly AnyLeafLowProfile[], I
|
|
|
55
74
|
}>, PS>>>, I, PS, Used | 'delete'>;
|
|
56
75
|
};
|
|
57
76
|
/** Builder surface used by `resource(...)` to accumulate leaves. */
|
|
58
|
-
export interface Branch<Base extends string, Acc extends readonly AnyLeafLowProfile[], I extends NodeCfg, PS extends ZodTypeAny | undefined, Used extends HttpMethod | 'add' = never> extends MethodFns<Base, Acc, I, PS, Used> {
|
|
59
|
-
/**
|
|
60
|
-
* Mount a static subtree under `name`.
|
|
61
|
-
* The `leaves` are built externally via `resource(...)` and will be
|
|
62
|
-
* rebased so that their paths become `${Base}/${name}${leaf.path}` and their
|
|
63
|
-
* paramsSchemas are merged with the parameters already accumulated on this branch.
|
|
64
|
-
*/
|
|
65
|
-
sub<Name extends string, const R extends readonly AnyLeafLowProfile[]>(name: Name, leaves: R): Branch<Base, MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>, I, PS, Used>;
|
|
66
|
-
/**
|
|
67
|
-
* Mount a static subtree under `name` and merge extra node-level config.
|
|
68
|
-
*/
|
|
69
|
-
sub<Name extends string, J extends NodeCfg, const R extends readonly AnyLeafLowProfile[]>(name: Name, cfg: J, leaves: R): Branch<Base, MergeArray<Acc, AugmentLeaves<`${Base}/${Name}`, PS, R>>, Merge<I, J>, PS, Used>;
|
|
77
|
+
export interface Branch<Base extends string, Acc extends readonly AnyLeafLowProfile[], I extends NodeCfg, PS extends ZodTypeAny | undefined, Used extends HttpMethod | 'add' | 'sub' = never> extends MethodFns<Base, Acc, I, PS, Used> {
|
|
70
78
|
/**
|
|
71
|
-
*
|
|
72
|
-
*
|
|
73
|
-
*
|
|
79
|
+
* Mount one or more sub-resources that were built via `resource(...)`.
|
|
80
|
+
* Each resource carries its own base path (e.g. `users`, `:userId`, `posts`)
|
|
81
|
+
* so this branch simply prefixes its current `Base` and merges param schemas.
|
|
74
82
|
*/
|
|
75
|
-
|
|
83
|
+
sub: 'sub' extends Used ? never : <const Collections extends SubResourceCollections, NextAcc extends readonly AnyLeafLowProfile[] = MergeArray<Acc, MergeAugmentedCollections<Base, PS, Collections>>>(...collections: Collections) => Branch<Base, NextAcc, I, PS, Used | 'sub'>;
|
|
76
84
|
/**
|
|
77
85
|
* Finish the branch and return the collected leaves.
|
|
78
86
|
* @returns Readonly tuple of accumulated leaves.
|
|
@@ -85,7 +93,7 @@ export interface Branch<Base extends string, Acc extends readonly AnyLeafLowProf
|
|
|
85
93
|
* @param inherited Optional node configuration applied to all descendants.
|
|
86
94
|
* @returns Root `Branch` instance used to compose the route tree.
|
|
87
95
|
*/
|
|
88
|
-
export declare function resource<Base extends string = '', I extends NodeCfg = {}>(base?: Base, inherited?: I): Branch<Base, readonly [], I,
|
|
96
|
+
export declare function resource<Base extends string = '', I extends NodeCfg = {}, Param extends ZodTypeAny | undefined = undefined>(base?: Base, inherited?: I, idSchema?: Param): Branch<ResourceBase<Base, Param>, readonly [], I, ParamSchemaForBase<Base, Param>>;
|
|
89
97
|
/**
|
|
90
98
|
* Merge two readonly tuples (preserves literal tuple information).
|
|
91
99
|
* @param arr1 First tuple.
|
|
@@ -9,29 +9,39 @@ export type FileField = {
|
|
|
9
9
|
maxCount: number;
|
|
10
10
|
};
|
|
11
11
|
/** Configuration that applies to an entire branch of the route tree. */
|
|
12
|
-
export
|
|
13
|
-
/**
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
12
|
+
export interface NodeCfg {
|
|
13
|
+
/**
|
|
14
|
+
* Feed-specific query schema applied to all descendants unless they override it.
|
|
15
|
+
*/
|
|
16
|
+
queryExtensionSchema?: ZodType;
|
|
17
|
+
/**
|
|
18
|
+
* Feed meta schema applied to all descendants unless they override it.
|
|
19
|
+
*/
|
|
20
|
+
outputMetaSchema?: ZodType;
|
|
21
|
+
}
|
|
22
|
+
export type RouteSchema<Output = unknown, Input = Output> = {
|
|
17
23
|
__out: Output;
|
|
24
|
+
__in?: Input;
|
|
18
25
|
};
|
|
19
26
|
export type FeedQueryField<C extends MethodCfg> = {
|
|
20
|
-
querySchema: IntersectZod<C['querySchema'] extends ZodObject ? C['querySchema'] : undefined, C['
|
|
27
|
+
querySchema: IntersectZod<C['querySchema'] extends ZodObject ? C['querySchema'] : undefined, C['queryExtensionSchema']>;
|
|
21
28
|
};
|
|
22
29
|
export type OutputField<C extends MethodCfg> = C['outputSchema'] extends ZodType ? {
|
|
23
30
|
outputSchema: ZodObject<{
|
|
24
31
|
out: C['outputSchema'];
|
|
25
|
-
meta: C['
|
|
32
|
+
meta: C['outputMetaSchema'] extends ZodType ? C['outputMetaSchema'] : z.ZodOptional<z.ZodString>;
|
|
26
33
|
}>;
|
|
27
34
|
} : {
|
|
28
35
|
outputSchema: ZodObject<{
|
|
29
|
-
meta: C['
|
|
36
|
+
meta: C['outputMetaSchema'] extends ZodType ? C['outputMetaSchema'] : z.ZodOptional<z.ZodString>;
|
|
30
37
|
}>;
|
|
31
38
|
};
|
|
32
39
|
export type RouteSchemaOutput<Schema extends RouteSchema> = Schema extends {
|
|
33
40
|
__out: infer Out;
|
|
34
41
|
} ? Out : unknown;
|
|
42
|
+
export type RouteSchemaInput<Schema extends RouteSchema> = Schema extends {
|
|
43
|
+
__in?: infer In;
|
|
44
|
+
} ? In : unknown;
|
|
35
45
|
export declare const lowProfileParse: <T extends RouteSchema>(schema: T, data: unknown) => RouteSchemaOutput<T>;
|
|
36
46
|
export declare const lowProfileSafeParse: <T extends RouteSchema>(schema: T, data: unknown) => ZodSafeParseResult<RouteSchemaOutput<T>>;
|
|
37
47
|
export declare const routeSchemaParse: <T>(routeSchema: RouteSchema<T>) => ZodType<T>;
|
|
@@ -47,14 +57,14 @@ export declare function mergeSchemas<B extends ZodType>(a: undefined, b: B): B;
|
|
|
47
57
|
export declare function mergeSchemas(a: ZodType | undefined, b: ZodType | undefined): ZodType | undefined;
|
|
48
58
|
export declare function getZodShape(schema: ZodObject): any;
|
|
49
59
|
export declare function collectNestedFieldSuggestions(shape: Record<string, ZodType> | undefined, prefix?: string[]): string[];
|
|
50
|
-
export type ToRouteSchema<S> = S extends ZodType<infer Out> ? RouteSchema<Out> : S;
|
|
51
|
-
export type LowProfileCfg<Cfg extends MethodCfg> = Prettify<Omit<Cfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | '
|
|
60
|
+
export type ToRouteSchema<S> = S extends ZodType<infer Out, infer In> ? RouteSchema<Out, In> : S;
|
|
61
|
+
export type LowProfileCfg<Cfg extends MethodCfg> = Prettify<Omit<Cfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'outputMetaSchema'> & {
|
|
52
62
|
bodySchema: ToRouteSchema<Cfg['bodySchema']>;
|
|
53
63
|
querySchema: ToRouteSchema<Cfg['querySchema']>;
|
|
54
64
|
paramsSchema: ToRouteSchema<Cfg['paramsSchema']>;
|
|
55
65
|
outputSchema: ToRouteSchema<Cfg['outputSchema']>;
|
|
56
|
-
|
|
57
|
-
|
|
66
|
+
outputMetaSchema: ToRouteSchema<Cfg['outputMetaSchema']>;
|
|
67
|
+
queryExtensionSchema: ToRouteSchema<Cfg['queryExtensionSchema']>;
|
|
58
68
|
}>;
|
|
59
69
|
/** Per-method configuration merged with inherited node config. */
|
|
60
70
|
export type MethodCfg = {
|
|
@@ -62,7 +72,7 @@ export type MethodCfg = {
|
|
|
62
72
|
bodySchema?: ZodType;
|
|
63
73
|
/** Zod schema describing the query string. */
|
|
64
74
|
querySchema?: ZodType;
|
|
65
|
-
/** Zod schema describing path params (
|
|
75
|
+
/** Zod schema describing path params (internal only, set through resource segments). */
|
|
66
76
|
paramsSchema?: ZodType;
|
|
67
77
|
/** Zod schema describing the response payload. */
|
|
68
78
|
outputSchema?: ZodType;
|
|
@@ -71,8 +81,8 @@ export type MethodCfg = {
|
|
|
71
81
|
/** Marks the route as an infinite feed (enables cursor helpers). */
|
|
72
82
|
feed?: boolean;
|
|
73
83
|
/** feed handlers */
|
|
74
|
-
|
|
75
|
-
|
|
84
|
+
outputMetaSchema?: ZodType;
|
|
85
|
+
queryExtensionSchema?: ZodType;
|
|
76
86
|
/** Optional human-readable description for docs/debugging. */
|
|
77
87
|
description?: string;
|
|
78
88
|
/**
|
|
@@ -127,12 +137,25 @@ export type Merge<A, B> = Prettify<Omit<A, keyof B> & B>;
|
|
|
127
137
|
export type Append<T extends readonly unknown[], X> = [...T, X];
|
|
128
138
|
/** Concatenate two readonly tuple types. */
|
|
129
139
|
export type MergeArray<A extends readonly unknown[], B extends readonly unknown[]> = [...A, ...B];
|
|
140
|
+
type TrimTrailingSlash<S extends string> = S extends `${infer R}/` ? TrimTrailingSlash<R> : S;
|
|
141
|
+
type TrimLeadingSlash<S extends string> = S extends `/${infer R}` ? TrimLeadingSlash<R> : S;
|
|
142
|
+
type NormalizedBase<Base extends string> = TrimTrailingSlash<Base>;
|
|
143
|
+
type NormalizedChild<Child extends string> = TrimLeadingSlash<Child>;
|
|
144
|
+
export type JoinPath<Base extends string, Child extends string> = NormalizedBase<Base> extends '' ? Child : NormalizedChild<Child> extends '' ? NormalizedBase<Base> : `${NormalizedBase<Base>}/${NormalizedChild<Child>}`;
|
|
130
145
|
export type IntersectZod<A extends ZodType | undefined, B extends ZodType | undefined> = B extends ZodType ? A extends ZodType ? z.ZodIntersection<A, B> : B : A extends ZodType ? A : undefined;
|
|
131
146
|
type MergeRouteSchemas<Existing extends RouteSchema | undefined, Parent extends ZodType | undefined> = Existing extends RouteSchema<infer ExistingOut> ? Parent extends ZodType<infer ParentOut> ? RouteSchema<ExistingOut & ParentOut> : Existing : Parent extends ZodType<infer ParentOut> ? RouteSchema<ParentOut> : undefined;
|
|
132
147
|
type AugmentedCfg<Cfg extends MethodCfgLowProfile, Param extends ZodType | undefined> = Prettify<Omit<Cfg, 'paramsSchema'> & {
|
|
133
148
|
paramsSchema: MergeRouteSchemas<Cfg['paramsSchema'], Param>;
|
|
134
149
|
}>;
|
|
135
|
-
export type AugmentLeaves<P extends string, Param extends ZodType | undefined, R extends readonly LeafLowProfile[], Acc extends readonly LeafLowProfile[] = []> = R extends readonly [infer First, ...infer Rest] ? First extends LeafLowProfile ? AugmentLeaves<P, Param, Rest extends readonly LeafLowProfile[] ? Rest : [], Append<Acc, LeafLowProfile<First['method'],
|
|
150
|
+
export type AugmentLeaves<P extends string, Param extends ZodType | undefined, R extends readonly LeafLowProfile[], Acc extends readonly LeafLowProfile[] = []> = R extends readonly [infer First, ...infer Rest] ? First extends LeafLowProfile ? AugmentLeaves<P, Param, Rest extends readonly LeafLowProfile[] ? Rest : [], Append<Acc, LeafLowProfile<First['method'], JoinPath<P, First['path']>, AugmentedCfg<First['cfg'], Param>>>> : never : Acc;
|
|
151
|
+
type NodeQueryExtension<Node> = Node extends {
|
|
152
|
+
queryExtensionSchema?: infer QE;
|
|
153
|
+
} ? QE extends ZodType ? QE : undefined : undefined;
|
|
154
|
+
type NodeOutputMeta<Node> = Node extends {
|
|
155
|
+
outputMetaSchema?: infer OM;
|
|
156
|
+
} ? OM extends ZodType ? OM : undefined : undefined;
|
|
157
|
+
type EffectiveQueryExtensionSchema<Method extends ZodType | undefined, Node extends NodeCfg | undefined> = Method extends ZodType ? Method : NodeQueryExtension<Node>;
|
|
158
|
+
type EffectiveOutputMetaSchema<Method extends ZodType | undefined, Node extends NodeCfg | undefined> = Method extends ZodType ? Method : NodeOutputMeta<Node>;
|
|
136
159
|
type SegmentParams<S extends string> = S extends `:${infer P}` ? P : never;
|
|
137
160
|
type Split<S extends string> = S extends '' ? [] : S extends `${infer A}/${infer B}` ? [A, ...Split<B>] : [S];
|
|
138
161
|
type ExtractParamNames<Path extends string> = SegmentParams<Split<Path>[number]>;
|
|
@@ -153,41 +176,42 @@ export declare function buildCacheKey<L extends AnyLeafLowProfile>(args: {
|
|
|
153
176
|
/** Definition-time method config (for clarity). */
|
|
154
177
|
export type MethodCfgDef = MethodCfg;
|
|
155
178
|
/** Low-profile method config where schemas carry a phantom __out like SocketSchema. */
|
|
156
|
-
export type MethodCfgLowProfile = Omit<MethodCfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | '
|
|
179
|
+
export type MethodCfgLowProfile = Omit<MethodCfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'outputMetaSchema' | 'queryExtensionSchema'> & {
|
|
157
180
|
bodySchema?: RouteSchema;
|
|
158
181
|
querySchema?: RouteSchema;
|
|
159
182
|
paramsSchema?: RouteSchema;
|
|
160
183
|
outputSchema?: RouteSchema;
|
|
161
|
-
|
|
162
|
-
|
|
184
|
+
outputMetaSchema?: RouteSchema;
|
|
185
|
+
queryExtensionSchema?: RouteSchema;
|
|
163
186
|
};
|
|
164
187
|
export type AnyLeafLowProfile = LeafLowProfile<HttpMethod, string, MethodCfgLowProfile>;
|
|
165
|
-
export declare function buildLowProfileLeaf<const M extends HttpMethod, const Path extends string, const O extends ZodType | undefined = undefined, const P extends ZodType | undefined = undefined, const Q extends ZodType | undefined = undefined, const B extends ZodType | undefined = undefined, const FO extends ZodType | undefined = undefined, const FQ extends ZodType | undefined = undefined, const Feed extends boolean = false>(leaf: {
|
|
188
|
+
export declare function buildLowProfileLeaf<const M extends HttpMethod, const Path extends string, const Node extends NodeCfg | undefined = undefined, const O extends ZodType | undefined = undefined, const P extends ZodType | undefined = undefined, const Q extends ZodType | undefined = undefined, const B extends ZodType | undefined = undefined, const FO extends ZodType | undefined = undefined, const FQ extends ZodType | undefined = undefined, const Feed extends boolean = false>(leaf: {
|
|
166
189
|
method: M;
|
|
167
190
|
path: Path;
|
|
168
|
-
|
|
191
|
+
node?: Node;
|
|
192
|
+
cfg: Omit<MethodCfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'feed' | 'outputMetaSchema' | 'queryExtensionSchema'> & {
|
|
169
193
|
feed?: Feed;
|
|
170
194
|
bodySchema?: B;
|
|
171
195
|
querySchema?: Q;
|
|
172
196
|
paramsSchema?: P;
|
|
173
197
|
outputSchema?: O;
|
|
174
|
-
|
|
175
|
-
|
|
198
|
+
outputMetaSchema?: FO;
|
|
199
|
+
queryExtensionSchema?: FQ;
|
|
176
200
|
};
|
|
177
|
-
}): LeafLowProfile<M, Path, Prettify<Omit<MethodCfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'feed' | '
|
|
201
|
+
}): LeafLowProfile<M, Path, Prettify<Omit<MethodCfg, 'bodySchema' | 'querySchema' | 'paramsSchema' | 'outputSchema' | 'feed' | 'outputMetaSchema' | 'queryExtensionSchema'> & {
|
|
178
202
|
feed: Feed;
|
|
179
|
-
bodySchema: B extends ZodType<infer BOut> ? RouteSchema<BOut> : undefined;
|
|
203
|
+
bodySchema: B extends ZodType<infer BOut, infer BIn> ? RouteSchema<BOut, BIn> : undefined;
|
|
180
204
|
querySchema: Feed extends true ? FeedQueryField<{
|
|
181
205
|
querySchema: Q;
|
|
182
|
-
|
|
183
|
-
}>['querySchema'] extends ZodType<infer QOut> ? RouteSchema<QOut> : never : Q extends ZodType<infer QOut> ? RouteSchema<QOut> : undefined;
|
|
184
|
-
paramsSchema: P extends ZodType<infer POut> ? RouteSchema<POut> : undefined;
|
|
185
|
-
outputSchema:
|
|
206
|
+
queryExtensionSchema: EffectiveQueryExtensionSchema<FQ, Node>;
|
|
207
|
+
}>['querySchema'] extends ZodType<infer QOut, infer QIn> ? RouteSchema<QOut, QIn> : never : Q extends ZodType<infer QOut, infer QIn> ? RouteSchema<QOut, QIn> : undefined;
|
|
208
|
+
paramsSchema: P extends ZodType<infer POut, infer PIn> ? RouteSchema<POut, PIn> : undefined;
|
|
209
|
+
outputSchema: OutputField<{
|
|
186
210
|
outputSchema: O;
|
|
187
|
-
|
|
188
|
-
}>['outputSchema'] extends
|
|
189
|
-
|
|
190
|
-
|
|
211
|
+
outputMetaSchema: EffectiveOutputMetaSchema<FO, Node>;
|
|
212
|
+
}>['outputSchema'] extends ZodType<infer OOut, infer OIn> ? RouteSchema<OOut, OIn> : never;
|
|
213
|
+
outputMetaSchema: EffectiveOutputMetaSchema<FO, Node> extends ZodType<infer OOut, infer OIn> ? RouteSchema<OOut, OIn> : undefined;
|
|
214
|
+
queryExtensionSchema: EffectiveQueryExtensionSchema<FQ, Node> extends ZodType<infer QOut, infer QIn> ? RouteSchema<QOut, QIn> : undefined;
|
|
191
215
|
}>>;
|
|
192
216
|
export type LeafLowProfile<M extends HttpMethod = HttpMethod, P extends string = string, C extends MethodCfgLowProfile = MethodCfgLowProfile> = {
|
|
193
217
|
/** Lowercase HTTP method (get/post/...). */
|
|
@@ -198,15 +222,24 @@ export type LeafLowProfile<M extends HttpMethod = HttpMethod, P extends string =
|
|
|
198
222
|
readonly cfg: Readonly<C>;
|
|
199
223
|
};
|
|
200
224
|
/** Infer params either from the explicit params schema or from the path literal. */
|
|
201
|
-
export type InferParams<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['paramsSchema'] extends RouteSchema<infer
|
|
225
|
+
export type InferParams<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['paramsSchema'] extends RouteSchema<any, infer PIn> ? PIn : L['cfg']['paramsSchema'] extends ZodType<any, infer PIn> ? PIn : Fallback;
|
|
202
226
|
/** Infer query shape from a Zod schema when present. */
|
|
203
|
-
export type InferQuery<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['querySchema'] extends RouteSchema<infer
|
|
227
|
+
export type InferQuery<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['querySchema'] extends RouteSchema<any, infer QIn> ? QIn : L['cfg']['querySchema'] extends ZodType<any, infer QIn> ? QIn : Fallback;
|
|
204
228
|
/** Infer request body shape from a Zod schema when present. */
|
|
205
|
-
export type InferBody<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['bodySchema'] extends RouteSchema<infer
|
|
229
|
+
export type InferBody<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['bodySchema'] extends RouteSchema<any, infer BIn> ? BIn : L['cfg']['bodySchema'] extends ZodType<any, infer BIn> ? BIn : Fallback;
|
|
206
230
|
/** Infer handler output shape from a Zod schema. Defaults to unknown. */
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
231
|
+
type InferMetaFromCfg<L extends AnyLeafLowProfile> = L['cfg']['outputMetaSchema'] extends RouteSchema<infer O> ? O : L['cfg']['outputMetaSchema'] extends ZodType<infer O> ? O : string | undefined;
|
|
232
|
+
type ResolvedMeta<L extends AnyLeafLowProfile, M> = [M] extends [never] | [unknown] ? InferMetaFromCfg<L> : M;
|
|
233
|
+
type ApplyMetaFallback<L extends AnyLeafLowProfile, O> = O extends {
|
|
234
|
+
meta: infer M;
|
|
235
|
+
} ? (undefined extends ResolvedMeta<L, M> ? {
|
|
236
|
+
meta?: ResolvedMeta<L, M>;
|
|
237
|
+
} : {
|
|
238
|
+
meta: ResolvedMeta<L, M>;
|
|
239
|
+
}) & Omit<O, 'meta'> : O;
|
|
240
|
+
export type InferOutput<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['outputSchema'] extends RouteSchema<infer O> ? ApplyMetaFallback<L, O> : L['cfg']['outputSchema'] extends ZodType<infer O> ? ApplyMetaFallback<L, O> : Fallback;
|
|
241
|
+
export type InferFeedOutputMeta<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['outputMetaSchema'] extends RouteSchema<infer O> ? O : L['cfg']['outputMetaSchema'] extends ZodType<infer O> ? O : Fallback;
|
|
242
|
+
export type InferFeedQuery<L extends AnyLeafLowProfile, Fallback = never> = L['cfg']['queryExtensionSchema'] extends RouteSchema<any, infer QIn> ? QIn : L['cfg']['queryExtensionSchema'] extends ZodType<any, infer QIn> ? QIn : Fallback;
|
|
210
243
|
/** Render a type as if it were a simple object literal. */
|
|
211
244
|
export type Prettify<T> = {
|
|
212
245
|
[K in keyof T]: T[K];
|