zodvex 0.5.1 → 0.6.0-beta.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/README.md +12 -61
- package/dist/actionCtx.d.ts +14 -0
- package/dist/actionCtx.d.ts.map +1 -0
- package/dist/builders.d.ts.map +1 -1
- package/dist/cli/commands.d.ts +9 -0
- package/dist/cli/commands.d.ts.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +446 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +42 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +78 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/zodvexClient.d.ts +18 -0
- package/dist/client/zodvexClient.d.ts.map +1 -0
- package/dist/codec.d.ts +15 -0
- package/dist/codec.d.ts.map +1 -1
- package/dist/codegen/discover.d.ts +32 -0
- package/dist/codegen/discover.d.ts.map +1 -0
- package/dist/codegen/generate.d.ts +20 -0
- package/dist/codegen/generate.d.ts.map +1 -0
- package/dist/codegen/index.d.ts +4 -0
- package/dist/codegen/index.d.ts.map +1 -0
- package/dist/codegen/index.js +271 -0
- package/dist/codegen/index.js.map +1 -0
- package/dist/codegen/zodToSource.d.ts +22 -0
- package/dist/codegen/zodToSource.d.ts.map +1 -0
- package/dist/core/index.d.ts +3 -0
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +257 -46
- package/dist/core/index.js.map +1 -1
- package/dist/custom.d.ts +3 -86
- package/dist/custom.d.ts.map +1 -1
- package/dist/customization.d.ts +41 -0
- package/dist/customization.d.ts.map +1 -0
- package/dist/db.d.ts +118 -0
- package/dist/db.d.ts.map +1 -0
- package/dist/index.js +720 -220
- package/dist/index.js.map +1 -1
- package/dist/init.d.ts +101 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/mapping/types.d.ts +35 -10
- package/dist/mapping/types.d.ts.map +1 -1
- package/dist/meta.d.ts +21 -0
- package/dist/meta.d.ts.map +1 -0
- package/dist/model.d.ts +116 -0
- package/dist/model.d.ts.map +1 -0
- package/dist/react/hooks.d.ts +35 -0
- package/dist/react/hooks.d.ts.map +1 -0
- package/dist/react/index.d.ts +3 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +54 -0
- package/dist/react/index.js.map +1 -0
- package/dist/schema.d.ts +130 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/server/index.d.ts +5 -0
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js +395 -39
- package/dist/server/index.js.map +1 -1
- package/dist/tables.d.ts +24 -0
- package/dist/tables.d.ts.map +1 -1
- package/dist/types.d.ts +16 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +26 -2
- package/src/actionCtx.ts +45 -0
- package/src/builders.ts +34 -6
- package/src/cli/commands.ts +85 -0
- package/src/cli/index.ts +48 -0
- package/src/cli/init.ts +99 -0
- package/src/client/index.ts +2 -0
- package/src/client/zodvexClient.ts +78 -0
- package/src/codec.ts +33 -0
- package/src/codegen/discover.ts +115 -0
- package/src/codegen/generate.ts +185 -0
- package/src/codegen/index.ts +13 -0
- package/src/codegen/zodToSource.ts +131 -0
- package/src/core/index.ts +6 -2
- package/src/custom.ts +37 -190
- package/src/customization.ts +39 -0
- package/src/db.ts +399 -0
- package/src/init.ts +231 -0
- package/src/mapping/types.ts +173 -172
- package/src/meta.ts +39 -0
- package/src/model.ts +379 -0
- package/src/react/hooks.ts +96 -0
- package/src/react/index.ts +2 -0
- package/src/schema.ts +210 -0
- package/src/server/index.ts +11 -1
- package/src/tables.ts +55 -25
- package/src/types.ts +45 -34
package/README.md
CHANGED
|
@@ -528,80 +528,31 @@ export const updateProfile = authMutation({
|
|
|
528
528
|
})
|
|
529
529
|
```
|
|
530
530
|
|
|
531
|
-
####
|
|
531
|
+
#### onSuccess Hook
|
|
532
532
|
|
|
533
|
-
|
|
533
|
+
The `onSuccess` callback follows convex-helpers' `Customization` convention — return it from your customization's `input` function:
|
|
534
534
|
|
|
535
535
|
```ts
|
|
536
|
-
import { zCustomMutationBuilder
|
|
536
|
+
import { zCustomMutationBuilder } from 'zodvex'
|
|
537
537
|
import { type MutationCtx, mutation } from './_generated/server'
|
|
538
538
|
|
|
539
|
-
export const secureMutation = zCustomMutationBuilder(
|
|
540
|
-
|
|
541
|
-
|
|
539
|
+
export const secureMutation = zCustomMutationBuilder(mutation, {
|
|
540
|
+
args: {},
|
|
541
|
+
input: async (ctx: MutationCtx) => {
|
|
542
542
|
const securityCtx = await getSecurityContext(ctx)
|
|
543
|
-
|
|
544
543
|
return {
|
|
545
|
-
// Custom context (same as customCtx)
|
|
546
544
|
ctx: { securityCtx },
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
onSuccess: ({ ctx, args, result }) => {
|
|
551
|
-
// Called after successful execution
|
|
552
|
-
console.log('Mutation succeeded:', { args, result })
|
|
553
|
-
analytics.track('mutation_success', { userId: ctx.securityCtx.userId })
|
|
554
|
-
}
|
|
555
|
-
},
|
|
556
|
-
|
|
557
|
-
// Transforms: modify data in the flow
|
|
558
|
-
transforms: {
|
|
559
|
-
// Transform args after validation, before handler
|
|
560
|
-
input: (args, schema) => {
|
|
561
|
-
// e.g., Convert wire format to runtime objects
|
|
562
|
-
return transformIncomingArgs(args, securityCtx)
|
|
563
|
-
},
|
|
564
|
-
// Transform result after handler, before response
|
|
565
|
-
output: (result, schema) => {
|
|
566
|
-
// e.g., Mask sensitive fields based on permissions
|
|
567
|
-
return transformOutgoingResult(result, securityCtx)
|
|
568
|
-
}
|
|
545
|
+
args: {},
|
|
546
|
+
onSuccess: ({ ctx, args, result }) => {
|
|
547
|
+
console.log('Mutation succeeded:', { args, result })
|
|
569
548
|
}
|
|
570
549
|
}
|
|
571
|
-
})
|
|
572
|
-
)
|
|
573
|
-
```
|
|
574
|
-
|
|
575
|
-
**Execution order:**
|
|
576
|
-
|
|
577
|
-
1. Args received from client
|
|
578
|
-
2. Zod validation on args
|
|
579
|
-
3. `transforms.input` runs (if provided)
|
|
580
|
-
4. Handler executes
|
|
581
|
-
5. Zod validation on returns (if provided)
|
|
582
|
-
6. `hooks.onSuccess` runs (if provided)
|
|
583
|
-
7. `transforms.output` runs (if provided)
|
|
584
|
-
8. Response sent to client
|
|
585
|
-
|
|
586
|
-
**Use cases:**
|
|
587
|
-
|
|
588
|
-
| Feature | Use Case |
|
|
589
|
-
|---------|----------|
|
|
590
|
-
| `hooks.onSuccess` | Logging, analytics, audit trails, cache invalidation |
|
|
591
|
-
| `transforms.input` | Wire format → runtime objects, field decryption, data hydration |
|
|
592
|
-
| `transforms.output` | Sensitive field masking, data redaction, format conversion |
|
|
593
|
-
|
|
594
|
-
**Note:** Both `transforms.input` and `transforms.output` can be async:
|
|
595
|
-
|
|
596
|
-
```ts
|
|
597
|
-
transforms: {
|
|
598
|
-
input: async (args, schema) => {
|
|
599
|
-
const decrypted = await decrypt(args.sensitiveField)
|
|
600
|
-
return { ...args, sensitiveField: decrypted }
|
|
601
550
|
}
|
|
602
|
-
}
|
|
551
|
+
})
|
|
603
552
|
```
|
|
604
553
|
|
|
554
|
+
`onSuccess` runs after the handler and Zod return validation, seeing runtime types (e.g., `Date`, not timestamps).
|
|
555
|
+
|
|
605
556
|
### Custom Codecs
|
|
606
557
|
|
|
607
558
|
For complex type transformations beyond the built-in `zx.date()` and `zx.id()`, use `zx.codec()` to create custom codecs that automatically work with validator generation and runtime encoding/decoding.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { GenericActionCtx, GenericDataModel } from 'convex/server';
|
|
2
|
+
import type { AnyRegistry } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Wraps an action context's runQuery/runMutation with automatic
|
|
5
|
+
* codec transforms via the zodvex registry.
|
|
6
|
+
*
|
|
7
|
+
* - Args are encoded (runtime -> wire) before calling the inner function
|
|
8
|
+
* - Results are decoded (wire -> runtime) before returning to the handler
|
|
9
|
+
* - Functions not in the registry pass through unchanged
|
|
10
|
+
*
|
|
11
|
+
* @internal Used by initZodvex when registry option is provided.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createZodvexActionCtx<DM extends GenericDataModel>(registry: AnyRegistry, ctx: GenericActionCtx<DM>): GenericActionCtx<DM>;
|
|
14
|
+
//# sourceMappingURL=actionCtx.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"actionCtx.d.ts","sourceRoot":"","sources":["../src/actionCtx.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAA;AAGvE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAA;AAG1C;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,EAAE,SAAS,gBAAgB,EAC/D,QAAQ,EAAE,WAAW,EACrB,GAAG,EAAE,gBAAgB,CAAC,EAAE,CAAC,GACxB,gBAAgB,CAAC,EAAE,CAAC,CAyBtB"}
|
package/dist/builders.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../src/builders.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EAChB,MAAM,eAAe,CAAA;AACtB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAA;AACvD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AAC1E,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AACvB,OAAO,EAAE,KAAK,aAAa,EAAmB,MAAM,UAAU,CAAA;AAC9D,OAAO,KAAK,EACV,UAAU,EACV,iBAAiB,EACjB,mBAAmB,EACnB,YAAY,EACZ,eAAe,EAChB,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"builders.d.ts","sourceRoot":"","sources":["../src/builders.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot codegen. Discovers modules, generates files.
|
|
3
|
+
*/
|
|
4
|
+
export declare function generate(convexDir?: string): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Watch mode. Runs generate() once, then watches for changes.
|
|
7
|
+
*/
|
|
8
|
+
export declare function dev(convexDir?: string): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=commands.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commands.d.ts","sourceRoot":"","sources":["../../src/cli/commands.ts"],"names":[],"mappings":"AAKA;;GAEG;AACH,wBAAsB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBhE;AAED;;GAEG;AACH,wBAAsB,GAAG,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAoC3D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
import path2 from 'path';
|
|
4
|
+
import { Glob } from 'bun';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
// src/cli/init.ts
|
|
18
|
+
var init_exports = {};
|
|
19
|
+
__export(init_exports, {
|
|
20
|
+
ensureConcurrently: () => ensureConcurrently,
|
|
21
|
+
generateStubs: () => generateStubs,
|
|
22
|
+
gitignoreEntry: () => gitignoreEntry,
|
|
23
|
+
init: () => init,
|
|
24
|
+
rewriteDeployScript: () => rewriteDeployScript,
|
|
25
|
+
rewriteDevScript: () => rewriteDevScript
|
|
26
|
+
});
|
|
27
|
+
function rewriteDevScript(script) {
|
|
28
|
+
if (script.includes("zodvex dev")) return null;
|
|
29
|
+
const match = script.match(/\b((?:bunx|npx)\s+convex\s+dev)\b/);
|
|
30
|
+
if (!match) return null;
|
|
31
|
+
return `concurrently "zodvex dev" "${script}"`;
|
|
32
|
+
}
|
|
33
|
+
function rewriteDeployScript(script) {
|
|
34
|
+
if (script.includes("zodvex generate")) return null;
|
|
35
|
+
const match = script.match(/\b((?:bunx|npx)\s+convex\s+deploy)\b/);
|
|
36
|
+
if (!match) return null;
|
|
37
|
+
const idx = script.indexOf(match[1]);
|
|
38
|
+
const before = script.slice(0, idx);
|
|
39
|
+
const after = script.slice(idx);
|
|
40
|
+
return `${before}zodvex generate && ${after}`;
|
|
41
|
+
}
|
|
42
|
+
function ensureConcurrently(pkg) {
|
|
43
|
+
if (pkg.dependencies?.concurrently) return "exists";
|
|
44
|
+
if (pkg.devDependencies?.concurrently) return "exists";
|
|
45
|
+
return "add";
|
|
46
|
+
}
|
|
47
|
+
function gitignoreEntry(content) {
|
|
48
|
+
if (content.includes("convex/_zodvex/")) return null;
|
|
49
|
+
const lines = content ? content.split("\n") : [];
|
|
50
|
+
lines.push("# zodvex generated files", "convex/_zodvex/");
|
|
51
|
+
return lines.join("\n");
|
|
52
|
+
}
|
|
53
|
+
function generateStubs(convexDir2) {
|
|
54
|
+
const zodvexDir = path2.join(convexDir2, "_zodvex");
|
|
55
|
+
fs.mkdirSync(zodvexDir, { recursive: true });
|
|
56
|
+
const apiStub = `// Auto-generated stub. Run \`zodvex generate\` to populate.
|
|
57
|
+
export const zodvexRegistry = {} as const
|
|
58
|
+
`;
|
|
59
|
+
fs.writeFileSync(path2.join(zodvexDir, "api.ts"), apiStub);
|
|
60
|
+
const clientStub = `// Auto-generated stub. Run \`zodvex generate\` to populate.
|
|
61
|
+
import { zodvexRegistry } from './api'
|
|
62
|
+
|
|
63
|
+
export const useZodQuery = undefined as any
|
|
64
|
+
export const useZodMutation = undefined as any
|
|
65
|
+
export const createClient = undefined as any
|
|
66
|
+
`;
|
|
67
|
+
fs.writeFileSync(path2.join(zodvexDir, "client.ts"), clientStub);
|
|
68
|
+
}
|
|
69
|
+
async function init() {
|
|
70
|
+
const convexDir2 = path2.resolve("convex");
|
|
71
|
+
if (!fs.existsSync(convexDir2)) {
|
|
72
|
+
console.error("[zodvex] No convex/ directory found. Run this from your project root.");
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
generateStubs(convexDir2);
|
|
76
|
+
console.log("[zodvex] Generated stub files in convex/_zodvex/");
|
|
77
|
+
console.log("[zodvex] Run `zodvex generate` to populate with your models and functions.");
|
|
78
|
+
}
|
|
79
|
+
var init_init = __esm({
|
|
80
|
+
"src/cli/init.ts"() {
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
// src/meta.ts
|
|
85
|
+
var META_KEY = "__zodvexMeta";
|
|
86
|
+
function readMeta(target) {
|
|
87
|
+
if (target == null || typeof target !== "object" && typeof target !== "function") {
|
|
88
|
+
return void 0;
|
|
89
|
+
}
|
|
90
|
+
return target[META_KEY];
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// src/codegen/discover.ts
|
|
94
|
+
async function discoverModules(convexDir2) {
|
|
95
|
+
const models = [];
|
|
96
|
+
const functions = [];
|
|
97
|
+
const codecs = [];
|
|
98
|
+
const glob = new Glob("**/*.{ts,js}");
|
|
99
|
+
const files = [];
|
|
100
|
+
for await (const file of glob.scan({ cwd: convexDir2 })) {
|
|
101
|
+
if (file.startsWith("_generated/") || file.startsWith("_zodvex/") || file.startsWith("node_modules/") || file.endsWith(".d.ts")) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
files.push(file);
|
|
105
|
+
}
|
|
106
|
+
for (const file of files) {
|
|
107
|
+
const absPath = path2.resolve(convexDir2, file);
|
|
108
|
+
let moduleExports;
|
|
109
|
+
try {
|
|
110
|
+
moduleExports = await import(absPath);
|
|
111
|
+
} catch (err) {
|
|
112
|
+
console.warn(`[zodvex] Warning: Failed to import ${file}:`, err.message);
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
const moduleName = file.replace(/\.(ts|js)$/, "").replace(/\\/g, "/");
|
|
116
|
+
for (const [exportName, value] of Object.entries(moduleExports)) {
|
|
117
|
+
const meta = readMeta(value);
|
|
118
|
+
if (meta) {
|
|
119
|
+
if (meta.type === "model") {
|
|
120
|
+
models.push({
|
|
121
|
+
exportName,
|
|
122
|
+
tableName: meta.tableName,
|
|
123
|
+
sourceFile: file,
|
|
124
|
+
schemas: meta.schemas
|
|
125
|
+
});
|
|
126
|
+
} else if (meta.type === "function") {
|
|
127
|
+
functions.push({
|
|
128
|
+
functionPath: `${moduleName}:${exportName}`,
|
|
129
|
+
exportName,
|
|
130
|
+
sourceFile: file,
|
|
131
|
+
zodArgs: meta.zodArgs,
|
|
132
|
+
zodReturns: meta.zodReturns
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (value instanceof z.ZodCodec) {
|
|
137
|
+
const def = value._zod?.def;
|
|
138
|
+
const isZxDate = def?.in instanceof z.ZodNumber && def?.out instanceof z.ZodCustom;
|
|
139
|
+
if (!isZxDate) {
|
|
140
|
+
if (!codecs.some((c) => c.schema === value)) {
|
|
141
|
+
codecs.push({
|
|
142
|
+
exportName,
|
|
143
|
+
sourceFile: file,
|
|
144
|
+
schema: value
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return { models, functions, codecs };
|
|
152
|
+
}
|
|
153
|
+
function zodToSource(schema, ctx) {
|
|
154
|
+
const def = schema._zod?.def;
|
|
155
|
+
if (schema instanceof z.ZodOptional) {
|
|
156
|
+
return `${zodToSource(def.innerType, ctx)}.optional()`;
|
|
157
|
+
}
|
|
158
|
+
if (schema instanceof z.ZodNullable) {
|
|
159
|
+
return `${zodToSource(def.innerType, ctx)}.nullable()`;
|
|
160
|
+
}
|
|
161
|
+
if (schema instanceof z.ZodString && schema.description?.startsWith("convexId:")) {
|
|
162
|
+
const tableName = schema.description.slice("convexId:".length);
|
|
163
|
+
return `zx.id("${tableName}")`;
|
|
164
|
+
}
|
|
165
|
+
if (schema instanceof z.ZodCodec && def.in instanceof z.ZodNumber && def.out instanceof z.ZodCustom) {
|
|
166
|
+
return "zx.date()";
|
|
167
|
+
}
|
|
168
|
+
if (schema instanceof z.ZodCodec) {
|
|
169
|
+
if (ctx?.codecMap) {
|
|
170
|
+
const ref = ctx.codecMap.get(schema);
|
|
171
|
+
if (ref) {
|
|
172
|
+
if (!ctx.neededCodecImports.has(ref.sourceFile)) {
|
|
173
|
+
ctx.neededCodecImports.set(ref.sourceFile, /* @__PURE__ */ new Set());
|
|
174
|
+
}
|
|
175
|
+
ctx.neededCodecImports.get(ref.sourceFile).add(ref.exportName);
|
|
176
|
+
return ref.exportName;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
const wireSource = zodToSource(def.in, ctx);
|
|
180
|
+
return `${wireSource} /* codec: transforms lost */`;
|
|
181
|
+
}
|
|
182
|
+
if (schema instanceof z.ZodString) return "z.string()";
|
|
183
|
+
if (schema instanceof z.ZodNumber) return "z.number()";
|
|
184
|
+
if (schema instanceof z.ZodBoolean) return "z.boolean()";
|
|
185
|
+
if (schema instanceof z.ZodNull) return "z.null()";
|
|
186
|
+
if (schema instanceof z.ZodUndefined) return "z.undefined()";
|
|
187
|
+
if (schema instanceof z.ZodAny) return "z.any()";
|
|
188
|
+
if (schema instanceof z.ZodObject) {
|
|
189
|
+
const shape = def.shape;
|
|
190
|
+
const fields = Object.entries(shape).map(([key, value]) => `${key}: ${zodToSource(value, ctx)}`).join(", ");
|
|
191
|
+
return `z.object({ ${fields} })`;
|
|
192
|
+
}
|
|
193
|
+
if (schema instanceof z.ZodArray) {
|
|
194
|
+
return `z.array(${zodToSource(def.element, ctx)})`;
|
|
195
|
+
}
|
|
196
|
+
if (schema instanceof z.ZodEnum) {
|
|
197
|
+
const values = schema.options.map((v) => `"${v}"`).join(", ");
|
|
198
|
+
return `z.enum([${values}])`;
|
|
199
|
+
}
|
|
200
|
+
if (schema instanceof z.ZodLiteral) {
|
|
201
|
+
const values = def.values;
|
|
202
|
+
const value = values.values().next().value;
|
|
203
|
+
if (typeof value === "string") return `z.literal("${value}")`;
|
|
204
|
+
return `z.literal(${value})`;
|
|
205
|
+
}
|
|
206
|
+
if (schema instanceof z.ZodUnion) {
|
|
207
|
+
const members = def.options.map((s) => zodToSource(s, ctx)).join(", ");
|
|
208
|
+
return `z.union([${members}])`;
|
|
209
|
+
}
|
|
210
|
+
if (schema instanceof z.ZodTuple) {
|
|
211
|
+
const items = def.items.map((s) => zodToSource(s, ctx)).join(", ");
|
|
212
|
+
return `z.tuple([${items}])`;
|
|
213
|
+
}
|
|
214
|
+
if (schema instanceof z.ZodRecord) {
|
|
215
|
+
return `z.record(${zodToSource(def.keyType, ctx)}, ${zodToSource(def.valueType, ctx)})`;
|
|
216
|
+
}
|
|
217
|
+
const typeName = def?.type ?? "unknown";
|
|
218
|
+
return `z.any() /* unsupported: ${typeName} */`;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// src/codegen/generate.ts
|
|
222
|
+
var HEADER = `// AUTO-GENERATED by zodvex \u2014 do not edit
|
|
223
|
+
// Run \`zodvex generate\` to regenerate
|
|
224
|
+
`;
|
|
225
|
+
function generateSchemaFile(models) {
|
|
226
|
+
const exports$1 = models.map((m) => {
|
|
227
|
+
const importPath = `../${m.sourceFile.replace(/\.ts$/, "")}`;
|
|
228
|
+
return `export { ${m.exportName} } from '${importPath}'`;
|
|
229
|
+
}).join("\n");
|
|
230
|
+
return `${HEADER}
|
|
231
|
+
${exports$1}
|
|
232
|
+
`;
|
|
233
|
+
}
|
|
234
|
+
function tryUnwrapToIdentity(schema, identityMap) {
|
|
235
|
+
let current = schema;
|
|
236
|
+
const suffixes = [];
|
|
237
|
+
const maxDepth = 5;
|
|
238
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
239
|
+
const def = current._zod?.def;
|
|
240
|
+
if (current instanceof z.ZodOptional) {
|
|
241
|
+
suffixes.push(".optional()");
|
|
242
|
+
current = def.innerType;
|
|
243
|
+
} else if (current instanceof z.ZodNullable) {
|
|
244
|
+
suffixes.push(".nullable()");
|
|
245
|
+
current = def.innerType;
|
|
246
|
+
} else {
|
|
247
|
+
break;
|
|
248
|
+
}
|
|
249
|
+
const ref = identityMap.get(current);
|
|
250
|
+
if (ref) {
|
|
251
|
+
return { ref, suffix: suffixes.reverse().join("") };
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
function generateApiFile(functions, models, codecs) {
|
|
257
|
+
const identityMap = /* @__PURE__ */ new Map();
|
|
258
|
+
const neededModelImports = /* @__PURE__ */ new Set();
|
|
259
|
+
for (const model of models) {
|
|
260
|
+
const importPath = `../${model.sourceFile.replace(/\.ts$/, "")}`;
|
|
261
|
+
for (const key of ["doc", "insert", "update", "docArray", "paginatedDoc"]) {
|
|
262
|
+
identityMap.set(model.schemas[key], {
|
|
263
|
+
importPath,
|
|
264
|
+
exportName: model.exportName,
|
|
265
|
+
schemaKey: key
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
const codecMap = /* @__PURE__ */ new Map();
|
|
270
|
+
if (codecs) {
|
|
271
|
+
for (const codec of codecs) {
|
|
272
|
+
const importPath = `../${codec.sourceFile.replace(/\.ts$/, "")}`;
|
|
273
|
+
codecMap.set(codec.schema, {
|
|
274
|
+
exportName: codec.exportName,
|
|
275
|
+
sourceFile: importPath
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
const zodToSourceCtx = {
|
|
280
|
+
codecMap,
|
|
281
|
+
neededCodecImports: /* @__PURE__ */ new Map()
|
|
282
|
+
};
|
|
283
|
+
let needsZod = false;
|
|
284
|
+
let needsZx = false;
|
|
285
|
+
function resolveSchema(schema) {
|
|
286
|
+
if (!schema) return "undefined";
|
|
287
|
+
const ref = identityMap.get(schema);
|
|
288
|
+
if (ref) {
|
|
289
|
+
neededModelImports.add(ref.exportName);
|
|
290
|
+
return `${ref.exportName}.schema.${ref.schemaKey}`;
|
|
291
|
+
}
|
|
292
|
+
const unwrapped = tryUnwrapToIdentity(schema, identityMap);
|
|
293
|
+
if (unwrapped) {
|
|
294
|
+
neededModelImports.add(unwrapped.ref.exportName);
|
|
295
|
+
return `${unwrapped.ref.exportName}.schema.${unwrapped.ref.schemaKey}${unwrapped.suffix}`;
|
|
296
|
+
}
|
|
297
|
+
const source = zodToSource(schema, zodToSourceCtx);
|
|
298
|
+
if (source.includes("z.")) needsZod = true;
|
|
299
|
+
if (source.includes("zx.")) needsZx = true;
|
|
300
|
+
return source;
|
|
301
|
+
}
|
|
302
|
+
const entries = functions.map((fn) => {
|
|
303
|
+
const args = resolveSchema(fn.zodArgs);
|
|
304
|
+
const returns = resolveSchema(fn.zodReturns);
|
|
305
|
+
return ` '${fn.functionPath}': {
|
|
306
|
+
args: ${args},
|
|
307
|
+
returns: ${returns},
|
|
308
|
+
}`;
|
|
309
|
+
}).join(",\n");
|
|
310
|
+
const imports = [];
|
|
311
|
+
if (needsZod) imports.push("import { z } from 'zod'");
|
|
312
|
+
if (needsZx) imports.push("import { zx } from 'zodvex/core'");
|
|
313
|
+
for (const exportName of neededModelImports) {
|
|
314
|
+
const model = models.find((m) => m.exportName === exportName);
|
|
315
|
+
if (model) {
|
|
316
|
+
const importPath = `../${model.sourceFile.replace(/\.ts$/, "")}`;
|
|
317
|
+
imports.push(`import { ${exportName} } from '${importPath}'`);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
for (const [importPath, exportNames] of zodToSourceCtx.neededCodecImports) {
|
|
321
|
+
const names = Array.from(exportNames).sort().join(", ");
|
|
322
|
+
imports.push(`import { ${names} } from '${importPath}'`);
|
|
323
|
+
}
|
|
324
|
+
const importSection = imports.length > 0 ? `${imports.join("\n")}
|
|
325
|
+
|
|
326
|
+
` : "";
|
|
327
|
+
return `${HEADER}
|
|
328
|
+
${importSection}export const zodvexRegistry = {
|
|
329
|
+
${entries},
|
|
330
|
+
} as const
|
|
331
|
+
`;
|
|
332
|
+
}
|
|
333
|
+
function generateClientFile() {
|
|
334
|
+
return `${HEADER}
|
|
335
|
+
import { createZodvexHooks } from 'zodvex/react'
|
|
336
|
+
import { createZodvexClient, type ZodvexClientOptions } from 'zodvex/client'
|
|
337
|
+
import { zodvexRegistry } from './api'
|
|
338
|
+
|
|
339
|
+
export const { useZodQuery, useZodMutation } = createZodvexHooks(zodvexRegistry)
|
|
340
|
+
|
|
341
|
+
export const createClient = (options: ZodvexClientOptions) =>
|
|
342
|
+
createZodvexClient(zodvexRegistry, options)
|
|
343
|
+
`;
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
// src/cli/commands.ts
|
|
347
|
+
async function generate(convexDir2) {
|
|
348
|
+
const resolved = resolveConvexDir(convexDir2);
|
|
349
|
+
const zodvexDir = path2.join(resolved, "_zodvex");
|
|
350
|
+
const result = await discoverModules(resolved);
|
|
351
|
+
const schemaContent = generateSchemaFile(result.models);
|
|
352
|
+
const apiContent = generateApiFile(result.functions, result.models, result.codecs);
|
|
353
|
+
const clientContent = generateClientFile();
|
|
354
|
+
fs.mkdirSync(zodvexDir, { recursive: true });
|
|
355
|
+
fs.writeFileSync(path2.join(zodvexDir, "schema.ts"), schemaContent);
|
|
356
|
+
fs.writeFileSync(path2.join(zodvexDir, "api.ts"), apiContent);
|
|
357
|
+
fs.writeFileSync(path2.join(zodvexDir, "client.ts"), clientContent);
|
|
358
|
+
console.log(
|
|
359
|
+
`[zodvex] Generated ${result.models.length} model(s), ${result.functions.length} function(s), ${result.codecs.length} codec(s)`
|
|
360
|
+
);
|
|
361
|
+
}
|
|
362
|
+
async function dev(convexDir2) {
|
|
363
|
+
const resolved = resolveConvexDir(convexDir2);
|
|
364
|
+
console.log("[zodvex] Starting watch mode...");
|
|
365
|
+
await generate(resolved);
|
|
366
|
+
let debounceTimer = null;
|
|
367
|
+
const watcher = fs.watch(resolved, { recursive: true }, (_event, filename) => {
|
|
368
|
+
if (!filename) return;
|
|
369
|
+
if (filename.startsWith("_zodvex") || filename.startsWith("_generated") || !filename.endsWith(".ts") && !filename.endsWith(".js")) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
373
|
+
debounceTimer = setTimeout(async () => {
|
|
374
|
+
console.log("[zodvex] Regenerating...");
|
|
375
|
+
try {
|
|
376
|
+
await generate(resolved);
|
|
377
|
+
} catch (err) {
|
|
378
|
+
console.error("[zodvex] Generation failed:", err.message);
|
|
379
|
+
}
|
|
380
|
+
}, 300);
|
|
381
|
+
});
|
|
382
|
+
process.on("SIGINT", () => {
|
|
383
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
384
|
+
watcher.close();
|
|
385
|
+
process.exit(0);
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
function resolveConvexDir(dir) {
|
|
389
|
+
if (dir) {
|
|
390
|
+
const resolved = path2.resolve(dir);
|
|
391
|
+
if (!fs.existsSync(resolved)) {
|
|
392
|
+
throw new Error(`Convex directory not found: ${resolved}`);
|
|
393
|
+
}
|
|
394
|
+
return resolved;
|
|
395
|
+
}
|
|
396
|
+
const defaultDir = path2.resolve("convex");
|
|
397
|
+
if (!fs.existsSync(defaultDir)) {
|
|
398
|
+
throw new Error("No convex/ directory found. Specify the path: zodvex generate <path>");
|
|
399
|
+
}
|
|
400
|
+
return defaultDir;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// src/cli/index.ts
|
|
404
|
+
var command = process.argv[2];
|
|
405
|
+
var convexDir = process.argv[3];
|
|
406
|
+
async function main() {
|
|
407
|
+
switch (command) {
|
|
408
|
+
case "generate":
|
|
409
|
+
await generate(convexDir);
|
|
410
|
+
break;
|
|
411
|
+
case "dev":
|
|
412
|
+
await dev(convexDir);
|
|
413
|
+
break;
|
|
414
|
+
case "init":
|
|
415
|
+
const { init: init2 } = await Promise.resolve().then(() => (init_init(), init_exports));
|
|
416
|
+
await init2();
|
|
417
|
+
break;
|
|
418
|
+
case "help":
|
|
419
|
+
case "--help":
|
|
420
|
+
case "-h":
|
|
421
|
+
case void 0:
|
|
422
|
+
printHelp();
|
|
423
|
+
break;
|
|
424
|
+
default:
|
|
425
|
+
console.error(`Unknown command: ${command}`);
|
|
426
|
+
printHelp();
|
|
427
|
+
process.exit(1);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function printHelp() {
|
|
431
|
+
console.log(`
|
|
432
|
+
zodvex - Convex codegen for Zod schemas
|
|
433
|
+
|
|
434
|
+
Usage:
|
|
435
|
+
zodvex generate [convex-dir] Generate schema and validator files
|
|
436
|
+
zodvex dev [convex-dir] Watch mode \u2014 regenerate on changes
|
|
437
|
+
zodvex init Set up zodvex in an existing Convex project
|
|
438
|
+
zodvex help Show this help message
|
|
439
|
+
`);
|
|
440
|
+
}
|
|
441
|
+
main().catch((err) => {
|
|
442
|
+
console.error(err.message);
|
|
443
|
+
process.exit(1);
|
|
444
|
+
});
|
|
445
|
+
//# sourceMappingURL=index.js.map
|
|
446
|
+
//# sourceMappingURL=index.js.map
|