zodvex 0.3.2 → 0.4.0
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/__type-tests__/infer-returns.d.ts +2 -0
- package/dist/__type-tests__/infer-returns.d.ts.map +1 -0
- package/dist/__type-tests__/zodTable-inference.d.ts +2 -0
- package/dist/__type-tests__/zodTable-inference.d.ts.map +1 -0
- package/dist/builders.d.ts +173 -0
- package/dist/builders.d.ts.map +1 -0
- package/dist/codec.d.ts +11 -0
- package/dist/codec.d.ts.map +1 -0
- package/dist/custom.d.ts +142 -0
- package/dist/custom.d.ts.map +1 -0
- package/dist/ids.d.ts +23 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/index.d.ts +10 -599
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -11
- package/dist/index.js.map +1 -1
- package/dist/mapping/core.d.ts +5 -0
- package/dist/mapping/core.d.ts.map +1 -0
- package/dist/mapping/handlers/enum.d.ts +4 -0
- package/dist/mapping/handlers/enum.d.ts.map +1 -0
- package/dist/mapping/handlers/index.d.ts +5 -0
- package/dist/mapping/handlers/index.d.ts.map +1 -0
- package/dist/mapping/handlers/nullable.d.ts +7 -0
- package/dist/mapping/handlers/nullable.d.ts.map +1 -0
- package/dist/mapping/handlers/record.d.ts +4 -0
- package/dist/mapping/handlers/record.d.ts.map +1 -0
- package/dist/mapping/handlers/union.d.ts +5 -0
- package/dist/mapping/handlers/union.d.ts.map +1 -0
- package/dist/mapping/index.d.ts +4 -0
- package/dist/mapping/index.d.ts.map +1 -0
- package/dist/mapping/types.d.ts +43 -0
- package/dist/mapping/types.d.ts.map +1 -0
- package/dist/mapping/utils.d.ts +6 -0
- package/dist/mapping/utils.d.ts.map +1 -0
- package/dist/registry.d.ts +110 -0
- package/dist/registry.d.ts.map +1 -0
- package/dist/tables.d.ts +122 -0
- package/dist/tables.d.ts.map +1 -0
- package/dist/transform/index.d.ts +26 -0
- package/dist/transform/index.d.ts.map +1 -0
- package/dist/transform/index.js +442 -0
- package/dist/transform/index.js.map +1 -0
- package/dist/transform/transform.d.ts +47 -0
- package/dist/transform/transform.d.ts.map +1 -0
- package/dist/transform/traverse.d.ts +62 -0
- package/dist/transform/traverse.d.ts.map +1 -0
- package/dist/transform/types.d.ts +115 -0
- package/dist/transform/types.d.ts.map +1 -0
- package/dist/types.d.ts +29 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils.d.ts +39 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/wrappers.d.ts +22 -0
- package/dist/wrappers.d.ts.map +1 -0
- package/package.json +13 -6
- package/src/__type-tests__/infer-returns.ts +24 -0
- package/src/custom.ts +170 -15
- package/src/transform/index.ts +38 -0
- package/src/transform/transform.ts +409 -0
- package/src/transform/traverse.ts +320 -0
- package/src/transform/types.ts +128 -0
- package/src/types.ts +3 -2
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform layer type definitions.
|
|
3
|
+
*
|
|
4
|
+
* General-purpose types for schema traversal and value transformation.
|
|
5
|
+
*/
|
|
6
|
+
import type { z } from 'zod';
|
|
7
|
+
/**
|
|
8
|
+
* Information about a field during schema traversal.
|
|
9
|
+
*/
|
|
10
|
+
export type FieldInfo = {
|
|
11
|
+
/** Dot-notation path (e.g., 'profile.email', 'contacts[].email') */
|
|
12
|
+
path: string;
|
|
13
|
+
/** The Zod schema for this field */
|
|
14
|
+
schema: z.ZodTypeAny;
|
|
15
|
+
/** Metadata from schema.meta() if present */
|
|
16
|
+
meta: Record<string, unknown> | undefined;
|
|
17
|
+
/** Whether the field is wrapped in optional/nullable */
|
|
18
|
+
isOptional: boolean;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Visitor functions for walkSchema().
|
|
22
|
+
*/
|
|
23
|
+
export type SchemaVisitor = {
|
|
24
|
+
/** Called for every field. Return 'skip' to skip children. */
|
|
25
|
+
onField?: (info: FieldInfo) => void | 'skip';
|
|
26
|
+
/** Called when entering an object schema */
|
|
27
|
+
onObject?: (info: FieldInfo) => void;
|
|
28
|
+
/** Called when entering an array schema */
|
|
29
|
+
onArray?: (info: FieldInfo) => void;
|
|
30
|
+
/** Called when entering a union schema */
|
|
31
|
+
onUnion?: (info: FieldInfo, variants: z.ZodTypeAny[]) => void;
|
|
32
|
+
};
|
|
33
|
+
/**
|
|
34
|
+
* Options for walkSchema().
|
|
35
|
+
*/
|
|
36
|
+
export type WalkSchemaOptions = {
|
|
37
|
+
/** Starting path prefix */
|
|
38
|
+
path?: string;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Context passed to transform functions.
|
|
42
|
+
*/
|
|
43
|
+
export type TransformContext<TCtx = unknown> = {
|
|
44
|
+
/** Current field path */
|
|
45
|
+
path: string;
|
|
46
|
+
/** The Zod schema for this field */
|
|
47
|
+
schema: z.ZodTypeAny;
|
|
48
|
+
/** Metadata from schema.meta() if present */
|
|
49
|
+
meta: Record<string, unknown> | undefined;
|
|
50
|
+
/** User-provided context */
|
|
51
|
+
ctx: TCtx;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Synchronous transform function signature.
|
|
55
|
+
*/
|
|
56
|
+
export type TransformFn<TCtx = unknown> = (value: unknown, context: TransformContext<TCtx>) => unknown;
|
|
57
|
+
/**
|
|
58
|
+
* Async transform function signature.
|
|
59
|
+
*/
|
|
60
|
+
export type AsyncTransformFn<TCtx = unknown> = (value: unknown, context: TransformContext<TCtx>) => unknown | Promise<unknown>;
|
|
61
|
+
/**
|
|
62
|
+
* Options for transformBySchema().
|
|
63
|
+
*/
|
|
64
|
+
export type TransformOptions = {
|
|
65
|
+
/** Starting path prefix */
|
|
66
|
+
path?: string;
|
|
67
|
+
/**
|
|
68
|
+
* How to handle values that don't match any union variant.
|
|
69
|
+
* - 'passthrough': Return value unchanged (default)
|
|
70
|
+
* - 'error': Throw an error
|
|
71
|
+
* - 'null': Replace with null (fail-closed for security)
|
|
72
|
+
*/
|
|
73
|
+
unmatchedUnion?: 'passthrough' | 'error' | 'null';
|
|
74
|
+
/** Callback when a union doesn't match */
|
|
75
|
+
onUnmatchedUnion?: (path: string) => void;
|
|
76
|
+
/**
|
|
77
|
+
* Fast predicate to check if a schema needs transformation.
|
|
78
|
+
*
|
|
79
|
+
* When provided, this predicate is called before the transform callback.
|
|
80
|
+
* If it returns false, the transform callback is skipped for this schema
|
|
81
|
+
* (but recursion into children continues).
|
|
82
|
+
*
|
|
83
|
+
* This optimization avoids callback overhead for schemas that don't need
|
|
84
|
+
* transformation, which is useful when only a small subset of fields
|
|
85
|
+
* require processing (e.g., only sensitive fields).
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* // Only call transform for schemas with sensitive metadata
|
|
90
|
+
* transformBySchema(value, schema, ctx, transform, {
|
|
91
|
+
* shouldTransform: (sch) => getSensitiveMetadata(sch) !== undefined
|
|
92
|
+
* })
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
shouldTransform?: (schema: z.ZodTypeAny) => boolean;
|
|
96
|
+
/**
|
|
97
|
+
* Process array elements in parallel (async only).
|
|
98
|
+
*
|
|
99
|
+
* When true, array elements are processed with Promise.all() instead of
|
|
100
|
+
* sequentially. This can significantly improve performance for large arrays
|
|
101
|
+
* when transforms involve async operations like entitlement checks.
|
|
102
|
+
*
|
|
103
|
+
* Default: false (sequential processing for backwards compatibility)
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* // Process user entitlements for all items in parallel
|
|
108
|
+
* const result = await transformBySchemaAsync(docs, schema, ctx, transform, {
|
|
109
|
+
* parallel: true
|
|
110
|
+
* })
|
|
111
|
+
* ```
|
|
112
|
+
*/
|
|
113
|
+
parallel?: boolean;
|
|
114
|
+
};
|
|
115
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/transform/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B;;GAEG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,oEAAoE;IACpE,IAAI,EAAE,MAAM,CAAA;IACZ,oCAAoC;IACpC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAA;IACpB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACzC,wDAAwD;IACxD,UAAU,EAAE,OAAO,CAAA;CACpB,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,8DAA8D;IAC9D,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,GAAG,MAAM,CAAA;IAC5C,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACpC,2CAA2C;IAC3C,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,KAAK,IAAI,CAAA;IACnC,0CAA0C;IAC1C,OAAO,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC,UAAU,EAAE,KAAK,IAAI,CAAA;CAC9D,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,GAAG,OAAO,IAAI;IAC7C,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAA;IACZ,oCAAoC;IACpC,MAAM,EAAE,CAAC,CAAC,UAAU,CAAA;IACpB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,SAAS,CAAA;IACzC,4BAA4B;IAC5B,GAAG,EAAE,IAAI,CAAA;CACV,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,IAAI,GAAG,OAAO,IAAI,CACxC,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAC5B,OAAO,CAAA;AAEZ;;GAEG;AACH,MAAM,MAAM,gBAAgB,CAAC,IAAI,GAAG,OAAO,IAAI,CAC7C,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,gBAAgB,CAAC,IAAI,CAAC,KAC5B,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;AAE/B;;GAEG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAA;IACb;;;;;OAKG;IACH,cAAc,CAAC,EAAE,aAAa,GAAG,OAAO,GAAG,MAAM,CAAA;IACjD,0CAA0C;IAC1C,gBAAgB,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACzC;;;;;;;;;;;;;;;;;;OAkBG;IACH,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,UAAU,KAAK,OAAO,CAAA;IACnD;;;;;;;;;;;;;;;;OAgBG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;CACnB,CAAA"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type DefaultFunctionArgs, type RegisteredAction, type RegisteredMutation, type RegisteredQuery } from 'convex/server';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
export type InferArgs<A> = A extends z.ZodObject<infer S> ? z.infer<z.ZodObject<S>> : A extends Record<string, z.ZodTypeAny> ? {
|
|
4
|
+
[K in keyof A]: z.infer<A[K]>;
|
|
5
|
+
} : A extends z.ZodTypeAny ? z.infer<A> : Record<string, never>;
|
|
6
|
+
export type InferReturns<R> = R extends z.ZodType<any, any, any> ? z.output<R> : R extends undefined ? any : R;
|
|
7
|
+
export type InferHandlerReturns<R> = R extends z.ZodType<any, any, any> ? z.output<R> : any;
|
|
8
|
+
/**
|
|
9
|
+
* Extract the visibility type from a Convex builder function
|
|
10
|
+
*/
|
|
11
|
+
export type ExtractVisibility<Builder extends (...args: any) => any> = ReturnType<Builder> extends RegisteredQuery<infer V, any, any> ? V : ReturnType<Builder> extends RegisteredMutation<infer V, any, any> ? V : ReturnType<Builder> extends RegisteredAction<infer V, any, any> ? V : 'public';
|
|
12
|
+
/**
|
|
13
|
+
* @deprecated Use GenericQueryCtx, GenericMutationCtx, or GenericActionCtx directly instead
|
|
14
|
+
*/
|
|
15
|
+
export type ExtractCtx<Builder> = Builder extends {
|
|
16
|
+
(fn: {
|
|
17
|
+
handler: (ctx: infer Ctx, ...args: any[]) => any;
|
|
18
|
+
}): any;
|
|
19
|
+
} ? Ctx : never;
|
|
20
|
+
/**
|
|
21
|
+
* @deprecated Return types are now specified explicitly using RegisteredQuery, RegisteredMutation, or RegisteredAction
|
|
22
|
+
*/
|
|
23
|
+
export type PreserveReturnType<Builder extends (...args: any) => any, ArgsType, ReturnsType> = ReturnType<Builder> extends RegisteredQuery<infer V, any, any> ? RegisteredQuery<V, ArgsType extends DefaultFunctionArgs ? ArgsType : DefaultFunctionArgs, Promise<ReturnsType>> : ReturnType<Builder> extends RegisteredMutation<infer V, any, any> ? RegisteredMutation<V, ArgsType extends DefaultFunctionArgs ? ArgsType : DefaultFunctionArgs, Promise<ReturnsType>> : ReturnType<Builder> extends RegisteredAction<infer V, any, any> ? RegisteredAction<V, ArgsType extends DefaultFunctionArgs ? ArgsType : DefaultFunctionArgs, Promise<ReturnsType>> : ReturnType<Builder>;
|
|
24
|
+
export type ZodToConvexArgs<A> = A extends z.ZodObject<any> ? z.infer<A> : A extends Record<string, z.ZodTypeAny> ? {
|
|
25
|
+
[K in keyof A]: z.infer<A[K]>;
|
|
26
|
+
} : A extends z.ZodTypeAny ? {
|
|
27
|
+
value: z.infer<A>;
|
|
28
|
+
} : Record<string, never>;
|
|
29
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare function pick<T extends Record<string, any>, K extends keyof T>(obj: T, keys: K[]): Pick<T, K>;
|
|
3
|
+
export declare function returnsAs<R extends z.ZodTypeAny>(): <T extends z.input<R>>(v: T) => T;
|
|
4
|
+
export declare function formatZodIssues(error: z.ZodError, context?: 'args' | 'returns' | 'input' | 'output' | 'codec'): {
|
|
5
|
+
error: string;
|
|
6
|
+
context: "output" | "input" | "args" | "returns" | "codec" | undefined;
|
|
7
|
+
issues: {
|
|
8
|
+
path: string;
|
|
9
|
+
code: "custom" | "invalid_type" | "unrecognized_keys" | "invalid_union" | "invalid_value" | "invalid_key" | "too_big" | "too_small" | "invalid_format" | "not_multiple_of" | "invalid_element";
|
|
10
|
+
message: string;
|
|
11
|
+
}[];
|
|
12
|
+
flatten: any;
|
|
13
|
+
};
|
|
14
|
+
export declare function handleZodValidationError(e: unknown, context: 'args' | 'returns' | 'input' | 'output' | 'codec'): never;
|
|
15
|
+
export declare function zPaginated<T extends z.ZodTypeAny>(item: T): z.ZodObject<{
|
|
16
|
+
page: z.ZodArray<T>;
|
|
17
|
+
isDone: z.ZodBoolean;
|
|
18
|
+
continueCursor: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
19
|
+
}, z.core.$strip>;
|
|
20
|
+
/**
|
|
21
|
+
* Maps Date fields to number fields for docSchema generation.
|
|
22
|
+
* Handles Date, Date.optional(), Date.nullable(), and Date.default() cases.
|
|
23
|
+
* Returns the original field for non-Date types.
|
|
24
|
+
*/
|
|
25
|
+
export declare function mapDateFieldToNumber(field: z.ZodTypeAny): z.ZodTypeAny;
|
|
26
|
+
type Mask = readonly string[] | Record<string, boolean | 1 | true>;
|
|
27
|
+
/**
|
|
28
|
+
* Returns a plain shape object containing only the selected fields.
|
|
29
|
+
* Accepts either a ZodObject or a raw shape object.
|
|
30
|
+
*/
|
|
31
|
+
export declare function pickShape(schemaOrShape: z.ZodObject<any> | Record<string, any>, mask: Mask): Record<string, any>;
|
|
32
|
+
export declare function safePick(schema: z.ZodObject<any>, mask: Mask): z.ZodObject<any>;
|
|
33
|
+
/**
|
|
34
|
+
* Convenience: omit a set of keys by building the complement.
|
|
35
|
+
* Avoids using Zod's .omit() which can cause type depth issues.
|
|
36
|
+
*/
|
|
37
|
+
export declare function safeOmit(schema: z.ZodObject<any>, mask: Mask): z.ZodObject<any>;
|
|
38
|
+
export {};
|
|
39
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,wBAAgB,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC,SAAS,MAAM,CAAC,EACnE,GAAG,EAAE,CAAC,EACN,IAAI,EAAE,CAAC,EAAE,GACR,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAMZ;AAGD,wBAAgB,SAAS,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,MACtC,CAAC,SAAS,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,CAAC,OACnC;AAGD,wBAAgB,eAAe,CAC7B,KAAK,EAAE,CAAC,CAAC,QAAQ,EACjB,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO;;;;;;;;;EAa5D;AAID,wBAAgB,wBAAwB,CACtC,CAAC,EAAE,OAAO,EACV,OAAO,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GACzD,KAAK,CAKP;AAGD,wBAAgB,UAAU,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC;;;;kBAMzD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,CA0BtE;AAGD,KAAK,IAAI,GAAG,SAAS,MAAM,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;AAOlE;;;GAGG;AACH,wBAAgB,SAAS,CACvB,aAAa,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACrD,IAAI,EAAE,IAAI,GACT,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAUrB;AAGD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAE/E;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAM/E"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { FunctionVisibility, RegisteredAction, RegisteredMutation, RegisteredQuery } from 'convex/server';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import type { ExtractCtx, ExtractVisibility, InferHandlerReturns, InferReturns, ZodToConvexArgs } from './types';
|
|
4
|
+
export declare function zQuery<Builder extends (fn: any) => any, A extends z.ZodTypeAny | Record<string, z.ZodTypeAny>, R extends z.ZodTypeAny | undefined = undefined, Visibility extends FunctionVisibility = ExtractVisibility<Builder>>(query: Builder, input: A, handler: (ctx: ExtractCtx<Builder>, args: ZodToConvexArgs<A>) => InferHandlerReturns<R> | Promise<InferHandlerReturns<R>>, options?: {
|
|
5
|
+
returns?: R;
|
|
6
|
+
}): RegisteredQuery<Visibility, ZodToConvexArgs<A>, Promise<InferReturns<R>>>;
|
|
7
|
+
export declare function zInternalQuery<Builder extends (fn: any) => any, A extends z.ZodTypeAny | Record<string, z.ZodTypeAny>, R extends z.ZodTypeAny | undefined = undefined, Visibility extends FunctionVisibility = ExtractVisibility<Builder>>(internalQuery: Builder, input: A, handler: (ctx: ExtractCtx<Builder>, args: ZodToConvexArgs<A>) => InferHandlerReturns<R> | Promise<InferHandlerReturns<R>>, options?: {
|
|
8
|
+
returns?: R;
|
|
9
|
+
}): RegisteredQuery<Visibility, ZodToConvexArgs<A>, Promise<InferReturns<R>>>;
|
|
10
|
+
export declare function zMutation<Builder extends (fn: any) => any, A extends z.ZodTypeAny | Record<string, z.ZodTypeAny>, R extends z.ZodTypeAny | undefined = undefined, Visibility extends FunctionVisibility = ExtractVisibility<Builder>>(mutation: Builder, input: A, handler: (ctx: ExtractCtx<Builder>, args: ZodToConvexArgs<A>) => InferHandlerReturns<R> | Promise<InferHandlerReturns<R>>, options?: {
|
|
11
|
+
returns?: R;
|
|
12
|
+
}): RegisteredMutation<Visibility, ZodToConvexArgs<A>, Promise<InferReturns<R>>>;
|
|
13
|
+
export declare function zInternalMutation<Builder extends (fn: any) => any, A extends z.ZodTypeAny | Record<string, z.ZodTypeAny>, R extends z.ZodTypeAny | undefined = undefined, Visibility extends FunctionVisibility = ExtractVisibility<Builder>>(internalMutation: Builder, input: A, handler: (ctx: ExtractCtx<Builder>, args: ZodToConvexArgs<A>) => InferHandlerReturns<R> | Promise<InferHandlerReturns<R>>, options?: {
|
|
14
|
+
returns?: R;
|
|
15
|
+
}): RegisteredMutation<Visibility, ZodToConvexArgs<A>, Promise<InferReturns<R>>>;
|
|
16
|
+
export declare function zAction<Builder extends (fn: any) => any, A extends z.ZodTypeAny | Record<string, z.ZodTypeAny>, R extends z.ZodTypeAny | undefined = undefined, Visibility extends FunctionVisibility = ExtractVisibility<Builder>>(action: Builder, input: A, handler: (ctx: ExtractCtx<Builder>, args: ZodToConvexArgs<A>) => InferHandlerReturns<R> | Promise<InferHandlerReturns<R>>, options?: {
|
|
17
|
+
returns?: R;
|
|
18
|
+
}): RegisteredAction<Visibility, ZodToConvexArgs<A>, Promise<InferReturns<R>>>;
|
|
19
|
+
export declare function zInternalAction<Builder extends (fn: any) => any, A extends z.ZodTypeAny | Record<string, z.ZodTypeAny>, R extends z.ZodTypeAny | undefined = undefined, Visibility extends FunctionVisibility = ExtractVisibility<Builder>>(internalAction: Builder, input: A, handler: (ctx: ExtractCtx<Builder>, args: ZodToConvexArgs<A>) => InferHandlerReturns<R> | Promise<InferHandlerReturns<R>>, options?: {
|
|
20
|
+
returns?: R;
|
|
21
|
+
}): RegisteredAction<Visibility, ZodToConvexArgs<A>, Promise<InferReturns<R>>>;
|
|
22
|
+
//# sourceMappingURL=wrappers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"wrappers.d.ts","sourceRoot":"","sources":["../src/wrappers.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zodvex",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Zod <=> Convex integration, supporting Zod 4",
|
|
5
5
|
"keywords": ["zod", "convex", "validators", "codec", "mapping", "schema", "validation"],
|
|
6
6
|
"homepage": "https://github.com/panzacoder/zodvex#readme",
|
|
@@ -21,18 +21,23 @@
|
|
|
21
21
|
"types": "./dist/index.d.ts",
|
|
22
22
|
"import": "./dist/index.js",
|
|
23
23
|
"default": "./dist/index.js"
|
|
24
|
+
},
|
|
25
|
+
"./transform": {
|
|
26
|
+
"types": "./dist/transform/index.d.ts",
|
|
27
|
+
"import": "./dist/transform/index.js",
|
|
28
|
+
"default": "./dist/transform/index.js"
|
|
24
29
|
}
|
|
25
30
|
},
|
|
26
31
|
"files": ["dist", "src", "README.md", "LICENSE"],
|
|
27
32
|
"scripts": {
|
|
28
|
-
"build": "tsup",
|
|
33
|
+
"build": "tsup && tsc --emitDeclarationOnly",
|
|
29
34
|
"dev": "bun run tsup --watch",
|
|
30
35
|
"type-check": "bun run tsc --noEmit",
|
|
31
36
|
"test": "bun test",
|
|
32
37
|
"lint": "bun x biome check src __tests__",
|
|
33
38
|
"lint:fix": "bun x biome check --write src __tests__",
|
|
34
39
|
"format": "bun x biome format --write src __tests__",
|
|
35
|
-
"prepare": "tsup",
|
|
40
|
+
"prepare": "tsup && tsc --emitDeclarationOnly",
|
|
36
41
|
"prepublishOnly": "bun test && bun run type-check"
|
|
37
42
|
},
|
|
38
43
|
"peerDependencies": {
|
|
@@ -40,13 +45,15 @@
|
|
|
40
45
|
"convex-helpers": "^0.1.104",
|
|
41
46
|
"zod": "^4.1.12"
|
|
42
47
|
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"tsup": "^8.5.0",
|
|
50
|
+
"typescript": "^5.9.3"
|
|
51
|
+
},
|
|
43
52
|
"devDependencies": {
|
|
44
53
|
"@biomejs/biome": "^2.2.6",
|
|
45
54
|
"@types/bun": "^1.3.0",
|
|
46
55
|
"@types/node": "^24.8.0",
|
|
47
|
-
"ai": "^6.0.6"
|
|
48
|
-
"tsup": "^8.5.0",
|
|
49
|
-
"typescript": "^5.9.3"
|
|
56
|
+
"ai": "^6.0.6"
|
|
50
57
|
},
|
|
51
58
|
"engines": {
|
|
52
59
|
"node": ">=20",
|
|
@@ -152,3 +152,27 @@ const treeNodeSchema = z.object({
|
|
|
152
152
|
})
|
|
153
153
|
declare const treeNodeResult: InferReturns<typeof treeNodeSchema>
|
|
154
154
|
expectNotAny(treeNodeResult)
|
|
155
|
+
|
|
156
|
+
// --- Codec/Transform schemas: handler returns z.output (internal type), not z.input (wire type) ---
|
|
157
|
+
// This tests the fix for Zod 4.1 codec support where input !== output
|
|
158
|
+
|
|
159
|
+
// Simulate a pipe/transform schema where input !== output
|
|
160
|
+
// z.input = string (wire format), z.output = Date (internal representation)
|
|
161
|
+
declare const codecSchema: z.ZodPipe<z.ZodString, z.ZodDate>
|
|
162
|
+
declare const codecResult: InferReturns<typeof codecSchema>
|
|
163
|
+
expectNotAny(codecResult)
|
|
164
|
+
// Handler should return Date (z.output), not string (z.input)
|
|
165
|
+
// @ts-expect-error - If this errors with "unused directive", Result is string (the bug)
|
|
166
|
+
const _codecInvalid: typeof codecResult = 'not a date'
|
|
167
|
+
|
|
168
|
+
// Test with transform (coerce pattern)
|
|
169
|
+
const coerceNumberSchema = z.coerce.number()
|
|
170
|
+
declare const coerceResult: InferReturns<typeof coerceNumberSchema>
|
|
171
|
+
expectNotAny(coerceResult)
|
|
172
|
+
// @ts-expect-error - Result should be number, not string/any
|
|
173
|
+
const _coerceInvalid: typeof coerceResult = 'not a number'
|
|
174
|
+
|
|
175
|
+
// Test with preprocess (another transform pattern)
|
|
176
|
+
const preprocessedSchema = z.preprocess(val => String(val), z.string())
|
|
177
|
+
declare const preprocessResult: InferReturns<typeof preprocessedSchema>
|
|
178
|
+
expectNotAny(preprocessResult)
|
package/src/custom.ts
CHANGED
|
@@ -18,6 +18,127 @@ import { type ZodValidator, zodToConvex, zodToConvexFields } from './mapping'
|
|
|
18
18
|
import type { ExtractCtx, ExtractVisibility } from './types'
|
|
19
19
|
import { handleZodValidationError, pick } from './utils'
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* Hooks for observing the function execution (side effects, no return value).
|
|
23
|
+
*/
|
|
24
|
+
export type CustomizationHooks = {
|
|
25
|
+
/** Called after successful execution with access to ctx, args, and result */
|
|
26
|
+
onSuccess?: (info: {
|
|
27
|
+
ctx: unknown
|
|
28
|
+
args: Record<string, unknown>
|
|
29
|
+
result: unknown
|
|
30
|
+
}) => void | Promise<void>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Transforms for modifying data in the function flow.
|
|
35
|
+
*/
|
|
36
|
+
export type CustomizationTransforms = {
|
|
37
|
+
/** Transform the output after validation but before wire encoding */
|
|
38
|
+
output?: (result: unknown, schema: z.ZodTypeAny) => unknown | Promise<unknown>
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Result returned from a customization input function.
|
|
43
|
+
* Separates Convex concepts (ctx, args) from hooks (side effects) and transforms (data modifications).
|
|
44
|
+
*/
|
|
45
|
+
export type CustomizationResult<
|
|
46
|
+
CustomCtx extends Record<string, any> = Record<string, any>,
|
|
47
|
+
CustomArgs extends Record<string, any> = Record<string, any>
|
|
48
|
+
> = {
|
|
49
|
+
/** Custom context to merge with base context */
|
|
50
|
+
ctx?: CustomCtx
|
|
51
|
+
/** Custom args to merge with parsed args */
|
|
52
|
+
args?: CustomArgs
|
|
53
|
+
/** Hooks for observing execution (side effects) */
|
|
54
|
+
hooks?: CustomizationHooks
|
|
55
|
+
/** Transforms for modifying the data flow */
|
|
56
|
+
transforms?: CustomizationTransforms
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Extended input result that includes hooks and transforms.
|
|
61
|
+
* This is what the input function returns internally.
|
|
62
|
+
*/
|
|
63
|
+
export type CustomizationInputResult<
|
|
64
|
+
OutCtx extends Record<string, any>,
|
|
65
|
+
OutArgs extends Record<string, any>
|
|
66
|
+
> = {
|
|
67
|
+
ctx: OutCtx
|
|
68
|
+
args: OutArgs
|
|
69
|
+
hooks?: CustomizationHooks
|
|
70
|
+
transforms?: CustomizationTransforms
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Customization type that supports hooks and transforms.
|
|
75
|
+
* This extends convex-helpers' Customization pattern to include
|
|
76
|
+
* hooks (side effects) and transforms (data modifications).
|
|
77
|
+
*
|
|
78
|
+
* Use customCtxWithHooks() to create instances of this type.
|
|
79
|
+
*/
|
|
80
|
+
export type CustomizationWithHooks<
|
|
81
|
+
InCtx extends Record<string, any>,
|
|
82
|
+
OutCtx extends Record<string, any> = Record<string, any>,
|
|
83
|
+
OutArgs extends Record<string, any> = Record<string, any>,
|
|
84
|
+
ExtraArgs extends Record<string, any> = Record<string, any>
|
|
85
|
+
> = {
|
|
86
|
+
args: Record<string, never>
|
|
87
|
+
input: (
|
|
88
|
+
ctx: InCtx,
|
|
89
|
+
args?: Record<string, unknown>,
|
|
90
|
+
extra?: ExtraArgs
|
|
91
|
+
) =>
|
|
92
|
+
| Promise<CustomizationInputResult<OutCtx, OutArgs>>
|
|
93
|
+
| CustomizationInputResult<OutCtx, OutArgs>
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* A helper for defining a Customization with full support for hooks and transforms.
|
|
98
|
+
* Use this instead of customCtx when you need onSuccess, transforms.output, etc.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```ts
|
|
102
|
+
* const secureQuery = zCustomQueryBuilder(
|
|
103
|
+
* query,
|
|
104
|
+
* customCtxWithHooks(async (ctx: QueryCtx) => {
|
|
105
|
+
* const securityCtx = await getSecurityContext(ctx)
|
|
106
|
+
* return {
|
|
107
|
+
* ctx: { securityCtx },
|
|
108
|
+
* hooks: {
|
|
109
|
+
* onSuccess: ({ result }) => console.log('Query returned:', result),
|
|
110
|
+
* },
|
|
111
|
+
* transforms: {
|
|
112
|
+
* output: (result, schema) => transformSensitiveFields(result, securityCtx),
|
|
113
|
+
* },
|
|
114
|
+
* }
|
|
115
|
+
* })
|
|
116
|
+
* )
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export function customCtxWithHooks<
|
|
120
|
+
InCtx extends Record<string, any>,
|
|
121
|
+
OutCtx extends Record<string, any> = Record<string, any>,
|
|
122
|
+
OutArgs extends Record<string, any> = Record<string, any>
|
|
123
|
+
>(
|
|
124
|
+
fn: (
|
|
125
|
+
ctx: InCtx
|
|
126
|
+
) => Promise<CustomizationResult<OutCtx, OutArgs>> | CustomizationResult<OutCtx, OutArgs>
|
|
127
|
+
): CustomizationWithHooks<InCtx, OutCtx, OutArgs> {
|
|
128
|
+
return {
|
|
129
|
+
args: {},
|
|
130
|
+
input: async (ctx: InCtx): Promise<CustomizationInputResult<OutCtx, OutArgs>> => {
|
|
131
|
+
const result = await fn(ctx)
|
|
132
|
+
return {
|
|
133
|
+
ctx: result.ctx ?? ({} as OutCtx),
|
|
134
|
+
args: result.args ?? ({} as OutArgs),
|
|
135
|
+
hooks: result.hooks,
|
|
136
|
+
transforms: result.transforms
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
21
142
|
// Type helpers for args transformation (from zodV3 example)
|
|
22
143
|
type OneArgArray<ArgsObject extends DefaultFunctionArgs = DefaultFunctionArgs> = [ArgsObject]
|
|
23
144
|
|
|
@@ -26,12 +147,14 @@ type NullToUndefinedOrNull<T> = T extends null ? T | undefined | void : T
|
|
|
26
147
|
type Returns<T> = Promise<NullToUndefinedOrNull<T>> | NullToUndefinedOrNull<T>
|
|
27
148
|
|
|
28
149
|
// The return value before it's been validated: returned by the handler
|
|
150
|
+
// Uses z.output since the handler produces the internal representation (e.g., Date),
|
|
151
|
+
// which is then encoded to wire format (e.g., string) before sending to the client
|
|
29
152
|
type ReturnValueInput<ReturnsValidator extends z.ZodTypeAny | ZodValidator | void> = [
|
|
30
153
|
ReturnsValidator
|
|
31
154
|
] extends [z.ZodTypeAny]
|
|
32
|
-
? Returns<z.
|
|
155
|
+
? Returns<z.output<ReturnsValidator>>
|
|
33
156
|
: [ReturnsValidator] extends [ZodValidator]
|
|
34
|
-
? Returns<z.
|
|
157
|
+
? Returns<z.output<z.ZodObject<ReturnsValidator>>>
|
|
35
158
|
: any
|
|
36
159
|
|
|
37
160
|
// The return value after it's been validated: returned to the client
|
|
@@ -171,7 +294,9 @@ export function customFnBuilder<
|
|
|
171
294
|
ExtraArgs extends Record<string, any> = Record<string, any>
|
|
172
295
|
>(
|
|
173
296
|
builder: Builder,
|
|
174
|
-
customization:
|
|
297
|
+
customization:
|
|
298
|
+
| Customization<Ctx, CustomArgsValidator, CustomCtx, CustomMadeArgs, ExtraArgs>
|
|
299
|
+
| CustomizationWithHooks<Ctx, CustomCtx, CustomMadeArgs, ExtraArgs>
|
|
175
300
|
) {
|
|
176
301
|
const customInput = customization.input ?? NoOp.input
|
|
177
302
|
const inputArgs = customization.args ?? NoOp.args
|
|
@@ -213,6 +338,13 @@ export function customFnBuilder<
|
|
|
213
338
|
args: convexArgs,
|
|
214
339
|
...returnValidator,
|
|
215
340
|
handler: async (ctx: Ctx, allArgs: any) => {
|
|
341
|
+
// Cast justification: customInput expects ObjectType<CustomArgsValidator>, but pick()
|
|
342
|
+
// returns Partial<T>. The cast is safe because inputArgs keys are derived from
|
|
343
|
+
// CustomArgsValidator at the type level. The 'added' result is typed as 'any' because
|
|
344
|
+
// it may include hooks/transforms from CustomizationWithHooks which aren't in the
|
|
345
|
+
// convex-helpers Customization type.
|
|
346
|
+
// TODO: Create a type-safe pickArgs<T>() helper that preserves the ObjectType<T>
|
|
347
|
+
// return type when the keys are statically known from the validator.
|
|
216
348
|
const added: any = await customInput(
|
|
217
349
|
ctx,
|
|
218
350
|
pick(allArgs, Object.keys(inputArgs)) as any,
|
|
@@ -239,17 +371,21 @@ export function customFnBuilder<
|
|
|
239
371
|
} catch (e) {
|
|
240
372
|
handleZodValidationError(e, 'returns')
|
|
241
373
|
}
|
|
242
|
-
if (added?.onSuccess) {
|
|
243
|
-
await added.onSuccess({
|
|
374
|
+
if (added?.hooks?.onSuccess) {
|
|
375
|
+
await added.hooks.onSuccess({
|
|
244
376
|
ctx,
|
|
245
377
|
args: parsed.data,
|
|
246
378
|
result: validated
|
|
247
379
|
})
|
|
248
380
|
}
|
|
249
|
-
|
|
381
|
+
// Apply output transform if provided
|
|
382
|
+
const transformed = added?.transforms?.output
|
|
383
|
+
? await added.transforms.output(validated, returns as z.ZodTypeAny)
|
|
384
|
+
: validated
|
|
385
|
+
return toConvexJS(returns as z.ZodTypeAny, transformed)
|
|
250
386
|
}
|
|
251
|
-
if (added?.onSuccess) {
|
|
252
|
-
await added.onSuccess({ ctx, args: parsed.data, result: ret })
|
|
387
|
+
if (added?.hooks?.onSuccess) {
|
|
388
|
+
await added.hooks.onSuccess({ ctx, args: parsed.data, result: ret })
|
|
253
389
|
}
|
|
254
390
|
return ret
|
|
255
391
|
}
|
|
@@ -259,6 +395,9 @@ export function customFnBuilder<
|
|
|
259
395
|
args: inputArgs,
|
|
260
396
|
...returnValidator,
|
|
261
397
|
handler: async (ctx: Ctx, allArgs: any) => {
|
|
398
|
+
// Cast justification: Same as above - customInput expects ObjectType<CustomArgsValidator>
|
|
399
|
+
// but pick() returns Partial<T>. Safe because inputArgs keys match CustomArgsValidator.
|
|
400
|
+
// TODO: Create a type-safe pickArgs<T>() helper (see comment in with-args path above).
|
|
262
401
|
const added: any = await customInput(
|
|
263
402
|
ctx,
|
|
264
403
|
pick(allArgs, Object.keys(inputArgs)) as any,
|
|
@@ -277,13 +416,17 @@ export function customFnBuilder<
|
|
|
277
416
|
} catch (e) {
|
|
278
417
|
handleZodValidationError(e, 'returns')
|
|
279
418
|
}
|
|
280
|
-
if (added?.onSuccess) {
|
|
281
|
-
await added.onSuccess({ ctx, args: allArgs, result: validated })
|
|
419
|
+
if (added?.hooks?.onSuccess) {
|
|
420
|
+
await added.hooks.onSuccess({ ctx, args: allArgs, result: validated })
|
|
282
421
|
}
|
|
283
|
-
|
|
422
|
+
// Apply output transform if provided
|
|
423
|
+
const transformed = added?.transforms?.output
|
|
424
|
+
? await added.transforms.output(validated, returns as z.ZodTypeAny)
|
|
425
|
+
: validated
|
|
426
|
+
return toConvexJS(returns as z.ZodTypeAny, transformed)
|
|
284
427
|
}
|
|
285
|
-
if (added?.onSuccess) {
|
|
286
|
-
await added.onSuccess({ ctx, args: allArgs, result: ret })
|
|
428
|
+
if (added?.hooks?.onSuccess) {
|
|
429
|
+
await added.hooks.onSuccess({ ctx, args: allArgs, result: ret })
|
|
287
430
|
}
|
|
288
431
|
return ret
|
|
289
432
|
}
|
|
@@ -343,8 +486,16 @@ export function zCustomQuery<
|
|
|
343
486
|
query: QueryBuilder<any, Visibility>,
|
|
344
487
|
customization: Customization<any, CustomArgsValidator, CustomCtx, CustomMadeArgs, ExtraArgs>
|
|
345
488
|
) {
|
|
346
|
-
//
|
|
347
|
-
//
|
|
489
|
+
// Cast justification: This is the TypeScript overload implementation pattern. The function
|
|
490
|
+
// has two overloads (with/without DataModel constraint) that provide precise types to callers.
|
|
491
|
+
// The implementation must satisfy both overloads, which requires a broader signature.
|
|
492
|
+
// The 'as any' casts allow the implementation to delegate to customFnBuilder without
|
|
493
|
+
// TypeScript complaining about the generic parameter differences between overloads.
|
|
494
|
+
// This is type-safe because: (1) callers only see the overload signatures which are strict,
|
|
495
|
+
// (2) the runtime behavior is identical regardless of which overload matched.
|
|
496
|
+
// TODO: Consider using a conditional type or branded types to create a single signature
|
|
497
|
+
// that satisfies both overloads without casts. Alternatively, accept this as idiomatic
|
|
498
|
+
// TypeScript for overloaded functions and keep the casts.
|
|
348
499
|
return customFnBuilder<
|
|
349
500
|
any,
|
|
350
501
|
typeof query,
|
|
@@ -388,6 +539,8 @@ export function zCustomMutation<
|
|
|
388
539
|
mutation: Builder,
|
|
389
540
|
customization: Customization<any, CustomArgsValidator, CustomCtx, CustomMadeArgs, ExtraArgs>
|
|
390
541
|
) {
|
|
542
|
+
// Cast justification: Same overload implementation pattern as zCustomQuery.
|
|
543
|
+
// See detailed comment there. Type safety is enforced by the overload signature above.
|
|
391
544
|
return customFnBuilder<any, Builder, CustomArgsValidator, CustomCtx, CustomMadeArgs, ExtraArgs>(
|
|
392
545
|
mutation as any,
|
|
393
546
|
customization as any
|
|
@@ -427,6 +580,8 @@ export function zCustomAction<
|
|
|
427
580
|
action: Builder,
|
|
428
581
|
customization: Customization<any, CustomArgsValidator, CustomCtx, CustomMadeArgs, ExtraArgs>
|
|
429
582
|
) {
|
|
583
|
+
// Cast justification: Same overload implementation pattern as zCustomQuery.
|
|
584
|
+
// See detailed comment there. Type safety is enforced by the overload signature above.
|
|
430
585
|
return customFnBuilder<any, Builder, CustomArgsValidator, CustomCtx, CustomMadeArgs, ExtraArgs>(
|
|
431
586
|
action as any,
|
|
432
587
|
customization as any
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Transform layer - General-purpose schema traversal and value transformation utilities.
|
|
3
|
+
*
|
|
4
|
+
* This module provides primitives for:
|
|
5
|
+
* - Walking Zod schemas (walkSchema, findFieldsWithMeta)
|
|
6
|
+
* - Extracting metadata from schemas (getMetadata, hasMetadata)
|
|
7
|
+
* - Recursively transforming values based on schema structure (transformBySchema, transformBySchemaAsync)
|
|
8
|
+
*
|
|
9
|
+
* @example
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { findFieldsWithMeta, transformBySchema } from 'zodvex/transform'
|
|
12
|
+
*
|
|
13
|
+
* // Find all fields with custom metadata
|
|
14
|
+
* const sensitiveFields = findFieldsWithMeta(schema, meta => meta?.sensitive === true)
|
|
15
|
+
*
|
|
16
|
+
* // Transform values based on metadata
|
|
17
|
+
* const masked = transformBySchema(value, schema, ctx, (val, info) => {
|
|
18
|
+
* if (info.meta?.pii) return '[REDACTED]'
|
|
19
|
+
* return val
|
|
20
|
+
* })
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
// Transformation
|
|
25
|
+
export { transformBySchema, transformBySchemaAsync } from './transform'
|
|
26
|
+
|
|
27
|
+
// Traversal
|
|
28
|
+
export { findFieldsWithMeta, getMetadata, hasMetadata, walkSchema } from './traverse'
|
|
29
|
+
// Types
|
|
30
|
+
export type {
|
|
31
|
+
AsyncTransformFn,
|
|
32
|
+
FieldInfo,
|
|
33
|
+
SchemaVisitor,
|
|
34
|
+
TransformContext,
|
|
35
|
+
TransformFn,
|
|
36
|
+
TransformOptions,
|
|
37
|
+
WalkSchemaOptions
|
|
38
|
+
} from './types'
|