zodvex 0.7.7-beta.1 → 0.7.7-beta.2

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.
Files changed (47) hide show
  1. package/dist/cli/index.js +251 -68
  2. package/dist/cli/index.js.map +1 -1
  3. package/dist/client/index.js +2 -2
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/codegen/index.js +211 -28
  6. package/dist/codegen/index.js.map +1 -1
  7. package/dist/core/index.js +33 -16
  8. package/dist/core/index.js.map +1 -1
  9. package/dist/index.js +33 -16
  10. package/dist/index.js.map +1 -1
  11. package/dist/internal/boundaryHelpers.d.ts +2 -15
  12. package/dist/internal/boundaryHelpers.d.ts.map +1 -1
  13. package/dist/internal/registry.d.ts.map +1 -1
  14. package/dist/internal/zx.d.ts.map +1 -1
  15. package/dist/internal/zxDateBrand.d.ts +5 -0
  16. package/dist/internal/zxDateBrand.d.ts.map +1 -0
  17. package/dist/legacy/index.js +21 -10
  18. package/dist/legacy/index.js.map +1 -1
  19. package/dist/mini/client/index.js +2 -2
  20. package/dist/mini/client/index.js.map +1 -1
  21. package/dist/mini/index.js +33 -16
  22. package/dist/mini/index.js.map +1 -1
  23. package/dist/mini/react/index.js +2 -2
  24. package/dist/mini/react/index.js.map +1 -1
  25. package/dist/mini/server/index.js +23 -12
  26. package/dist/mini/server/index.js.map +1 -1
  27. package/dist/public/codegen/discover.d.ts.map +1 -1
  28. package/dist/public/codegen/discovery-hooks.d.ts +2 -1
  29. package/dist/public/codegen/discovery-hooks.d.ts.map +1 -1
  30. package/dist/public/codegen/extractCodec.d.ts.map +1 -1
  31. package/dist/public/codegen/tsconfigPaths.d.ts +41 -0
  32. package/dist/public/codegen/tsconfigPaths.d.ts.map +1 -0
  33. package/dist/public/codegen/zodToSource.d.ts.map +1 -1
  34. package/dist/react/index.js +2 -2
  35. package/dist/react/index.js.map +1 -1
  36. package/dist/server/index.js +23 -12
  37. package/dist/server/index.js.map +1 -1
  38. package/package.json +1 -1
  39. package/src/internal/boundaryHelpers.ts +15 -3
  40. package/src/internal/registry.ts +12 -9
  41. package/src/internal/zx.ts +12 -9
  42. package/src/internal/zxDateBrand.ts +34 -0
  43. package/src/public/codegen/discover.ts +27 -15
  44. package/src/public/codegen/discovery-hooks.ts +42 -3
  45. package/src/public/codegen/extractCodec.ts +5 -11
  46. package/src/public/codegen/tsconfigPaths.ts +224 -0
  47. package/src/public/codegen/zodToSource.ts +5 -6
package/dist/cli/index.js CHANGED
@@ -1,12 +1,12 @@
1
1
  #!/usr/bin/env node
2
- import fs2, { readFileSync, writeFileSync, existsSync } from 'fs';
3
- import path3, { resolve, relative, join } from 'path';
2
+ import fs3, { readFileSync, writeFileSync, existsSync } from 'fs';
3
+ import path4, { resolve, relative, join } from 'path';
4
4
  import { Project, SyntaxKind } from 'ts-morph';
5
5
  import { globSync } from 'tinyglobby';
6
6
  import { spawn } from 'child_process';
7
7
  import { fileURLToPath } from 'url';
8
8
  import { z } from 'zod';
9
- import { $ZodCodec, $ZodNumber, $ZodCustom, $ZodType, $ZodOptional, $ZodNullable, $ZodObject, $ZodUnion, $ZodArray, $ZodRecord, $ZodTuple, clone, $ZodString, $ZodBoolean, $ZodNull, $ZodUndefined, $ZodAny, $ZodEnum, $ZodLiteral, $ZodDiscriminatedUnion } from 'zod/v4/core';
9
+ import { $ZodCodec, $ZodType, $ZodOptional, $ZodNullable, $ZodObject, $ZodUnion, $ZodArray, $ZodRecord, $ZodTuple, clone, $ZodString, $ZodNumber, $ZodBoolean, $ZodNull, $ZodUndefined, $ZodAny, $ZodEnum, $ZodLiteral, $ZodDiscriminatedUnion } from 'zod/v4/core';
10
10
  import 'convex/values';
11
11
 
12
12
  var __defProp = Object.defineProperty;
@@ -62,12 +62,12 @@ function gitignoreEntry(content) {
62
62
  return lines.join("\n");
63
63
  }
64
64
  function generateStubs(convexDir2) {
65
- const zodvexDir = path3.join(convexDir2, "_zodvex");
66
- fs2.mkdirSync(zodvexDir, { recursive: true });
65
+ const zodvexDir = path4.join(convexDir2, "_zodvex");
66
+ fs3.mkdirSync(zodvexDir, { recursive: true });
67
67
  const apiStub = `// Auto-generated stub. Run \`zodvex generate\` to populate.
68
68
  export const zodvexRegistry = {} as const
69
69
  `;
70
- fs2.writeFileSync(path3.join(zodvexDir, "api.ts"), apiStub);
70
+ fs3.writeFileSync(path4.join(zodvexDir, "api.ts"), apiStub);
71
71
  const clientStub = `// Auto-generated stub. Run \`zodvex generate\` to populate.
72
72
  import { zodvexRegistry } from './api'
73
73
 
@@ -75,11 +75,11 @@ export const useZodQuery = undefined as any
75
75
  export const useZodMutation = undefined as any
76
76
  export const createClient = undefined as any
77
77
  `;
78
- fs2.writeFileSync(path3.join(zodvexDir, "client.ts"), clientStub);
78
+ fs3.writeFileSync(path4.join(zodvexDir, "client.ts"), clientStub);
79
79
  }
80
80
  async function init() {
81
- const convexDir2 = path3.resolve("convex");
82
- if (!fs2.existsSync(convexDir2)) {
81
+ const convexDir2 = path4.resolve("convex");
82
+ if (!fs3.existsSync(convexDir2)) {
83
83
  console.error("[zodvex] No convex/ directory found. Run this from your project root.");
84
84
  return;
85
85
  }
@@ -100,14 +100,14 @@ __export(migrate_exports, {
100
100
  function collectFiles(dir) {
101
101
  const results = [];
102
102
  function walk(current) {
103
- const entries = fs2.readdirSync(current, { withFileTypes: true });
103
+ const entries = fs3.readdirSync(current, { withFileTypes: true });
104
104
  for (const entry of entries) {
105
105
  if (entry.isDirectory()) {
106
106
  if (!SKIP_DIRS.has(entry.name)) {
107
- walk(path3.join(current, entry.name));
107
+ walk(path4.join(current, entry.name));
108
108
  }
109
- } else if (entry.isFile() && TS_EXTENSIONS.has(path3.extname(entry.name))) {
110
- results.push(path3.join(current, entry.name));
109
+ } else if (entry.isFile() && TS_EXTENSIONS.has(path4.extname(entry.name))) {
110
+ results.push(path4.join(current, entry.name));
111
111
  }
112
112
  }
113
113
  }
@@ -204,7 +204,7 @@ function migrate(dir, options) {
204
204
  let wouldChange = 0;
205
205
  const allDeprecations = [];
206
206
  for (const filePath of files) {
207
- const original = fs2.readFileSync(filePath, "utf-8");
207
+ const original = fs3.readFileSync(filePath, "utf-8");
208
208
  let content = original;
209
209
  content = applyIdentifierRenames(content);
210
210
  content = applyZidTransform(content);
@@ -214,7 +214,7 @@ function migrate(dir, options) {
214
214
  if (options.dryRun) {
215
215
  wouldChange++;
216
216
  } else {
217
- fs2.writeFileSync(filePath, content);
217
+ fs3.writeFileSync(filePath, content);
218
218
  filesChanged++;
219
219
  }
220
220
  }
@@ -1054,18 +1054,34 @@ function zodvexCodec(wire, runtime, transforms) {
1054
1054
  return z.codec(wire, runtime, transforms);
1055
1055
  }
1056
1056
 
1057
+ // src/internal/zxDateBrand.ts
1058
+ var ZX_DATE_BRAND = /* @__PURE__ */ Symbol.for("zodvex.zxDate");
1059
+ function brandZxDate(codec2) {
1060
+ codec2[ZX_DATE_BRAND] = true;
1061
+ const def = codec2._zod?.def;
1062
+ if (def) def[ZX_DATE_BRAND] = true;
1063
+ return codec2;
1064
+ }
1065
+ function isZxDateCodec(schema) {
1066
+ if (!schema || typeof schema !== "object") return false;
1067
+ const s = schema;
1068
+ return s[ZX_DATE_BRAND] === true || s._zod?.def?.[ZX_DATE_BRAND] === true;
1069
+ }
1070
+
1057
1071
  // src/internal/zx.ts
1058
1072
  function date() {
1059
- return zodvexCodec(
1060
- z.number(),
1061
- // Wire: timestamp
1062
- z.custom((val) => val instanceof Date, {
1063
- message: "Expected Date instance"
1064
- }),
1065
- {
1066
- decode: (timestamp) => new Date(timestamp),
1067
- encode: (date2) => date2.getTime()
1068
- }
1073
+ return brandZxDate(
1074
+ zodvexCodec(
1075
+ z.number(),
1076
+ // Wire: timestamp
1077
+ z.custom((val) => val instanceof Date, {
1078
+ message: "Expected Date instance"
1079
+ }),
1080
+ {
1081
+ decode: (timestamp) => new Date(timestamp),
1082
+ encode: (date2) => date2.getTime()
1083
+ }
1084
+ )
1069
1085
  );
1070
1086
  }
1071
1087
  function id(tableName) {
@@ -1304,9 +1320,35 @@ function createSchemaUpdateSchema(name, inputSchema) {
1304
1320
  }
1305
1321
  return inputSchema;
1306
1322
  }
1307
- var HOOKS_SOURCE = `
1323
+ function buildHooksSource(aliases) {
1324
+ return `
1325
+ import { pathToFileURL } from 'node:url';
1326
+
1308
1327
  const EXT_CANDIDATES = ['.ts', '.tsx', '.mts', '.js', '.mjs', '.jsx', '/index.ts', '/index.js'];
1309
1328
 
1329
+ // tsconfig path aliases compiled by loadTsconfigAliases (#99). Bun resolves
1330
+ // these natively; Node's ESM loader needs them replayed here.
1331
+ const ALIASES = ${JSON.stringify(aliases)};
1332
+
1333
+ function aliasCandidates(specifier) {
1334
+ const out = [];
1335
+ for (const a of ALIASES) {
1336
+ if (a.star) {
1337
+ if (
1338
+ specifier.length >= a.prefix.length + a.suffix.length &&
1339
+ specifier.startsWith(a.prefix) &&
1340
+ specifier.endsWith(a.suffix)
1341
+ ) {
1342
+ const captured = specifier.slice(a.prefix.length, specifier.length - a.suffix.length);
1343
+ for (const t of a.targets) out.push(t.prefix + captured + t.suffix);
1344
+ }
1345
+ } else if (specifier === a.prefix) {
1346
+ for (const t of a.targets) out.push(t.prefix);
1347
+ }
1348
+ }
1349
+ return out;
1350
+ }
1351
+
1310
1352
  export async function resolve(specifier, context, nextResolve) {
1311
1353
  if (/_generated\\/api(\\.[mc]?[jt]sx?)?$/.test(specifier)) {
1312
1354
  return { shortCircuit: true, url: 'zodvex-stub://api' };
@@ -1314,6 +1356,15 @@ export async function resolve(specifier, context, nextResolve) {
1314
1356
  try {
1315
1357
  return await nextResolve(specifier, context);
1316
1358
  } catch (err) {
1359
+ // tsconfig path aliases (e.g. '@/convex/...'). Try each mapped absolute
1360
+ // path as-is, then with the usual extension/index candidates.
1361
+ for (const base of aliasCandidates(specifier)) {
1362
+ for (const ext of ['', ...EXT_CANDIDATES]) {
1363
+ try {
1364
+ return await nextResolve(pathToFileURL(base + ext).href, context);
1365
+ } catch {}
1366
+ }
1367
+ }
1317
1368
  // Convex code uses extensionless relative imports (bundler resolution).
1318
1369
  // Bun resolves those natively; Node's ESM loader does not \u2014 retry with
1319
1370
  // the usual extension candidates before giving up.
@@ -1358,8 +1409,9 @@ export function load(url, context, nextLoad) {
1358
1409
  return nextLoad(url, context);
1359
1410
  }
1360
1411
  `;
1412
+ }
1361
1413
  var hooksRegistered = false;
1362
- function registerDiscoveryHooks() {
1414
+ function registerDiscoveryHooks(aliases = []) {
1363
1415
  if (hooksRegistered) return true;
1364
1416
  try {
1365
1417
  const nodeModule = typeof process.getBuiltinModule === "function" ? process.getBuiltinModule("node:module") : (
@@ -1368,7 +1420,7 @@ function registerDiscoveryHooks() {
1368
1420
  );
1369
1421
  const { register } = nodeModule;
1370
1422
  if (typeof register !== "function") return false;
1371
- register(`data:text/javascript,${encodeURIComponent(HOOKS_SOURCE)}`);
1423
+ register(`data:text/javascript,${encodeURIComponent(buildHooksSource(aliases))}`);
1372
1424
  hooksRegistered = true;
1373
1425
  return true;
1374
1426
  } catch {
@@ -1393,22 +1445,22 @@ export const components = p;
1393
1445
  export const httpRouter = p;
1394
1446
  `;
1395
1447
  function writeGeneratedStubs(convexDir2) {
1396
- const generatedDir = path3.join(convexDir2, "_generated");
1397
- const apiPath = path3.join(generatedDir, "api.ts");
1448
+ const generatedDir = path4.join(convexDir2, "_generated");
1449
+ const apiPath = path4.join(generatedDir, "api.ts");
1398
1450
  let original;
1399
1451
  try {
1400
- original = fs2.readFileSync(apiPath, "utf8");
1452
+ original = fs3.readFileSync(apiPath, "utf8");
1401
1453
  } catch {
1402
1454
  original = null;
1403
1455
  }
1404
- fs2.mkdirSync(generatedDir, { recursive: true });
1405
- fs2.writeFileSync(apiPath, PROXY_STUB_API);
1456
+ fs3.mkdirSync(generatedDir, { recursive: true });
1457
+ fs3.writeFileSync(apiPath, PROXY_STUB_API);
1406
1458
  return () => {
1407
1459
  if (original !== null) {
1408
- fs2.writeFileSync(apiPath, original);
1460
+ fs3.writeFileSync(apiPath, original);
1409
1461
  } else {
1410
1462
  try {
1411
- fs2.unlinkSync(apiPath);
1463
+ fs3.unlinkSync(apiPath);
1412
1464
  } catch {
1413
1465
  }
1414
1466
  }
@@ -1420,8 +1472,7 @@ function findCodec(schema) {
1420
1472
  let current = schema;
1421
1473
  for (let i = 0; i < 10; i++) {
1422
1474
  if (current instanceof $ZodCodec) {
1423
- const isZxDate = current._zod.def.in instanceof $ZodNumber && current._zod.def.out instanceof $ZodCustom;
1424
- if (isZxDate) return void 0;
1475
+ if (isZxDateCodec(current)) return void 0;
1425
1476
  return current;
1426
1477
  }
1427
1478
  if (current instanceof $ZodOptional || current instanceof $ZodNullable) {
@@ -1432,6 +1483,134 @@ function findCodec(schema) {
1432
1483
  }
1433
1484
  return void 0;
1434
1485
  }
1486
+ function stripJsonComments(input) {
1487
+ let out = "";
1488
+ let inString = false;
1489
+ let inLine = false;
1490
+ let inBlock = false;
1491
+ for (let i = 0; i < input.length; i++) {
1492
+ const ch = input[i];
1493
+ const next = input[i + 1];
1494
+ if (inLine) {
1495
+ if (ch === "\n") {
1496
+ inLine = false;
1497
+ out += ch;
1498
+ }
1499
+ continue;
1500
+ }
1501
+ if (inBlock) {
1502
+ if (ch === "*" && next === "/") {
1503
+ inBlock = false;
1504
+ i++;
1505
+ }
1506
+ continue;
1507
+ }
1508
+ if (inString) {
1509
+ out += ch;
1510
+ if (ch === "\\") {
1511
+ out += next ?? "";
1512
+ i++;
1513
+ } else if (ch === '"') {
1514
+ inString = false;
1515
+ }
1516
+ continue;
1517
+ }
1518
+ if (ch === '"') {
1519
+ inString = true;
1520
+ out += ch;
1521
+ continue;
1522
+ }
1523
+ if (ch === "/" && next === "/") {
1524
+ inLine = true;
1525
+ i++;
1526
+ continue;
1527
+ }
1528
+ if (ch === "/" && next === "*") {
1529
+ inBlock = true;
1530
+ i++;
1531
+ continue;
1532
+ }
1533
+ out += ch;
1534
+ }
1535
+ return out.replace(/,\s*([}\]])/g, "$1");
1536
+ }
1537
+ function readTsconfig(configPath) {
1538
+ try {
1539
+ const raw = fs3.readFileSync(configPath, "utf8");
1540
+ return JSON.parse(stripJsonComments(raw));
1541
+ } catch {
1542
+ return null;
1543
+ }
1544
+ }
1545
+ function resolvePathsFromConfig(configPath, seen) {
1546
+ const abs = path4.resolve(configPath);
1547
+ if (seen.has(abs)) return null;
1548
+ seen.add(abs);
1549
+ const config = readTsconfig(abs);
1550
+ if (!config) return null;
1551
+ const dir = path4.dirname(abs);
1552
+ const own = config.compilerOptions?.paths;
1553
+ if (own) {
1554
+ const baseUrl = config.compilerOptions?.baseUrl;
1555
+ return { paths: own, baseDir: baseUrl ? path4.resolve(dir, baseUrl) : dir };
1556
+ }
1557
+ const parents = config.extends == null ? [] : [].concat(config.extends);
1558
+ for (const ref of parents) {
1559
+ if (!ref.startsWith(".") && !path4.isAbsolute(ref)) continue;
1560
+ let target = path4.resolve(dir, ref);
1561
+ if (!target.endsWith(".json")) target += ".json";
1562
+ const found = resolvePathsFromConfig(target, seen);
1563
+ if (found) {
1564
+ const childBase = config.compilerOptions?.baseUrl;
1565
+ return childBase ? { paths: found.paths, baseDir: path4.resolve(dir, childBase) } : found;
1566
+ }
1567
+ }
1568
+ return null;
1569
+ }
1570
+ function compileAliases(paths, baseDir) {
1571
+ const entries = [];
1572
+ for (const [pattern, targets] of Object.entries(paths)) {
1573
+ const starIdx = pattern.indexOf("*");
1574
+ const star = starIdx !== -1;
1575
+ const prefix = star ? pattern.slice(0, starIdx) : pattern;
1576
+ const suffix = star ? pattern.slice(starIdx + 1) : "";
1577
+ const compiled = targets.map((t) => {
1578
+ const tStar = t.indexOf("*");
1579
+ const tPrefix = path4.resolve(baseDir, tStar === -1 ? t : t.slice(0, tStar));
1580
+ const sep = tStar !== -1 && t.slice(0, tStar).endsWith("/") ? path4.sep : "";
1581
+ return {
1582
+ prefix: tPrefix + sep,
1583
+ suffix: tStar === -1 ? "" : t.slice(tStar + 1)
1584
+ };
1585
+ });
1586
+ entries.push({ prefix, suffix, star, targets: compiled });
1587
+ }
1588
+ return entries;
1589
+ }
1590
+ function loadTsconfigAliases(convexDir2) {
1591
+ const entries = [];
1592
+ const seenPatterns = /* @__PURE__ */ new Set();
1593
+ let dir = path4.resolve(convexDir2);
1594
+ for (let depth = 0; depth < 10; depth++) {
1595
+ const configPath = path4.join(dir, "tsconfig.json");
1596
+ if (fs3.existsSync(configPath)) {
1597
+ const found = resolvePathsFromConfig(configPath, /* @__PURE__ */ new Set());
1598
+ if (found) {
1599
+ for (const entry of compileAliases(found.paths, found.baseDir)) {
1600
+ const key = `${entry.prefix}*${entry.suffix}`;
1601
+ if (!seenPatterns.has(key)) {
1602
+ seenPatterns.add(key);
1603
+ entries.push(entry);
1604
+ }
1605
+ }
1606
+ }
1607
+ }
1608
+ const parent = path4.dirname(dir);
1609
+ if (parent === dir) break;
1610
+ dir = parent;
1611
+ }
1612
+ return entries;
1613
+ }
1435
1614
 
1436
1615
  // src/public/codegen/discover.ts
1437
1616
  function walkSchemaRecursive(schema, accessPath, visited, seenCodecs, results) {
@@ -1575,7 +1754,7 @@ async function discoverModules(convexDir2) {
1575
1754
  const models = [];
1576
1755
  const functions = [];
1577
1756
  const codecs = [];
1578
- registerDiscoveryHooks();
1757
+ registerDiscoveryHooks(loadTsconfigAliases(convexDir2));
1579
1758
  const cleanupStubs = writeGeneratedStubs(convexDir2);
1580
1759
  const files = globSync(["**/*.{ts,js}"], {
1581
1760
  cwd: convexDir2,
@@ -1595,15 +1774,15 @@ async function discoverModules(convexDir2) {
1595
1774
  "crons.js"
1596
1775
  ]
1597
1776
  }).sort();
1598
- let importFailures = 0;
1777
+ const failedImports = [];
1599
1778
  try {
1600
1779
  for (const file of files) {
1601
- const absPath = path3.resolve(convexDir2, file);
1780
+ const absPath = path4.resolve(convexDir2, file);
1602
1781
  let moduleExports;
1603
1782
  try {
1604
1783
  moduleExports = await import(absPath);
1605
1784
  } catch (err) {
1606
- importFailures++;
1785
+ failedImports.push({ file, message: err.message });
1607
1786
  console.warn(`[zodvex] Warning: Failed to import ${file}:`, err.message);
1608
1787
  continue;
1609
1788
  }
@@ -1647,8 +1826,7 @@ async function discoverModules(convexDir2) {
1647
1826
  }
1648
1827
  }
1649
1828
  if (value instanceof $ZodCodec) {
1650
- const isZxDate = value._zod.def.in instanceof $ZodNumber && value._zod.def.out instanceof $ZodCustom;
1651
- if (!isZxDate) {
1829
+ if (!isZxDateCodec(value)) {
1652
1830
  if (!codecs.some((c) => c.schema === value)) {
1653
1831
  codecs.push({
1654
1832
  exportName,
@@ -1671,9 +1849,14 @@ async function discoverModules(convexDir2) {
1671
1849
  modelCodecs.push(...found);
1672
1850
  }
1673
1851
  const functionCodecs = walkFunctionCodecs(functions);
1674
- if (importFailures > 0 && models.length === 0 && functions.length === 0) {
1852
+ if (failedImports.length > 0 && !process.env.ZODVEX_ALLOW_IMPORT_FAILURES) {
1853
+ const shown = failedImports.slice(0, 10).map((f) => ` - ${f.file}: ${f.message}`).join("\n");
1854
+ const more = failedImports.length > 10 ? `
1855
+ \u2026 and ${failedImports.length - 10} more` : "";
1675
1856
  throw new Error(
1676
- `[zodvex] Discovery imported 0 modules (${importFailures} file(s) failed to load). Importing TypeScript at runtime requires Bun or Node >= 22.18 (native type stripping). Re-run with Bun (\`bunx zodvex generate\`) or upgrade Node.`
1857
+ `[zodvex] ${failedImports.length} module(s) failed to import during discovery \u2014 the generated registry would be incomplete:
1858
+ ${shown}${more}
1859
+ Common causes: Node < 22.18 (no native TypeScript type stripping \u2014 use Bun or upgrade Node), or an import style the discovery resolver does not handle. tsconfig path aliases and extensionless relative imports are supported. Set ZODVEX_ALLOW_IMPORT_FAILURES=1 to generate anyway (skipping the failed modules).`
1677
1860
  );
1678
1861
  }
1679
1862
  return { models, functions, codecs, modelCodecs, functionCodecs };
@@ -1698,7 +1881,7 @@ function zodToSource(schema, ctx) {
1698
1881
  return `zx.id("${tableName}")`;
1699
1882
  }
1700
1883
  }
1701
- if (schema instanceof $ZodCodec && schema._zod.def.in instanceof $ZodNumber && schema._zod.def.out instanceof $ZodCustom) {
1884
+ if (schema instanceof $ZodCodec && isZxDateCodec(schema)) {
1702
1885
  return "zx.date()";
1703
1886
  }
1704
1887
  if (schema instanceof $ZodCodec) {
@@ -2221,7 +2404,7 @@ ${dtsDeclarations.join("\n")}
2221
2404
  // src/public/cli/commands.ts
2222
2405
  async function generate(convexDir2, options) {
2223
2406
  const resolved = resolveConvexDir(convexDir2);
2224
- const zodvexDir = path3.join(resolved, "_zodvex");
2407
+ const zodvexDir = path4.join(resolved, "_zodvex");
2225
2408
  writeStubApi(zodvexDir);
2226
2409
  const result = await discoverModules(resolved);
2227
2410
  const schemaContent = generateSchemaFile(result.models);
@@ -2235,15 +2418,15 @@ async function generate(convexDir2, options) {
2235
2418
  );
2236
2419
  const clientContent = generateClientFile({ mini: options?.mini });
2237
2420
  const serverContent = generateServerFile();
2238
- fs2.mkdirSync(zodvexDir, { recursive: true });
2239
- writeIfChanged(path3.join(zodvexDir, "schema.js"), schemaContent.js);
2240
- writeIfChanged(path3.join(zodvexDir, "schema.d.ts"), schemaContent.dts);
2241
- writeIfChanged(path3.join(zodvexDir, "api.js"), apiContent.js);
2242
- writeIfChanged(path3.join(zodvexDir, "api.d.ts"), apiContent.dts);
2243
- writeIfChanged(path3.join(zodvexDir, "client.js"), clientContent.js);
2244
- writeIfChanged(path3.join(zodvexDir, "client.d.ts"), clientContent.dts);
2245
- writeIfChanged(path3.join(zodvexDir, "server.js"), serverContent.js);
2246
- writeIfChanged(path3.join(zodvexDir, "server.d.ts"), serverContent.dts);
2421
+ fs3.mkdirSync(zodvexDir, { recursive: true });
2422
+ writeIfChanged(path4.join(zodvexDir, "schema.js"), schemaContent.js);
2423
+ writeIfChanged(path4.join(zodvexDir, "schema.d.ts"), schemaContent.dts);
2424
+ writeIfChanged(path4.join(zodvexDir, "api.js"), apiContent.js);
2425
+ writeIfChanged(path4.join(zodvexDir, "api.d.ts"), apiContent.dts);
2426
+ writeIfChanged(path4.join(zodvexDir, "client.js"), clientContent.js);
2427
+ writeIfChanged(path4.join(zodvexDir, "client.d.ts"), clientContent.dts);
2428
+ writeIfChanged(path4.join(zodvexDir, "server.js"), serverContent.js);
2429
+ writeIfChanged(path4.join(zodvexDir, "server.d.ts"), serverContent.dts);
2247
2430
  const totalCodecs = result.codecs.length + result.modelCodecs.length + result.functionCodecs.length;
2248
2431
  console.log(
2249
2432
  `[zodvex] Generated ${result.models.length} model(s), ${result.functions.length} function(s), ${totalCodecs} codec(s)`
@@ -2254,7 +2437,7 @@ async function dev(convexDir2, options) {
2254
2437
  console.log("[zodvex] Starting watch mode...");
2255
2438
  await generate(resolved, options);
2256
2439
  let debounceTimer = null;
2257
- const watcher = fs2.watch(resolved, { recursive: true }, (_event, filename) => {
2440
+ const watcher = fs3.watch(resolved, { recursive: true }, (_event, filename) => {
2258
2441
  if (!filename) return;
2259
2442
  if (filename.startsWith("_zodvex") || filename.startsWith("_generated") || !filename.endsWith(".ts") && !filename.endsWith(".js")) {
2260
2443
  return;
@@ -2288,34 +2471,34 @@ function regenerate(resolved, options) {
2288
2471
  });
2289
2472
  }
2290
2473
  function writeStubApi(zodvexDir) {
2291
- fs2.mkdirSync(zodvexDir, { recursive: true });
2292
- fs2.writeFileSync(
2293
- path3.join(zodvexDir, "api.js"),
2474
+ fs3.mkdirSync(zodvexDir, { recursive: true });
2475
+ fs3.writeFileSync(
2476
+ path4.join(zodvexDir, "api.js"),
2294
2477
  "// AUTO-GENERATED by zodvex \u2014 do not edit\n// Stub created for codegen bootstrap\n\nexport const zodvexRegistry = {}\n"
2295
2478
  );
2296
- fs2.writeFileSync(
2297
- path3.join(zodvexDir, "api.d.ts"),
2479
+ fs3.writeFileSync(
2480
+ path4.join(zodvexDir, "api.d.ts"),
2298
2481
  "// AUTO-GENERATED by zodvex \u2014 do not edit\n// Stub created for codegen bootstrap\n\nexport declare const zodvexRegistry: Record<string, any>\n"
2299
2482
  );
2300
2483
  }
2301
2484
  function writeIfChanged(filePath, content) {
2302
2485
  try {
2303
- const existing = fs2.readFileSync(filePath, "utf-8");
2486
+ const existing = fs3.readFileSync(filePath, "utf-8");
2304
2487
  if (existing === content) return;
2305
2488
  } catch {
2306
2489
  }
2307
- fs2.writeFileSync(filePath, content);
2490
+ fs3.writeFileSync(filePath, content);
2308
2491
  }
2309
2492
  function resolveConvexDir(dir) {
2310
2493
  if (dir) {
2311
- const resolved = path3.resolve(dir);
2312
- if (!fs2.existsSync(resolved)) {
2494
+ const resolved = path4.resolve(dir);
2495
+ if (!fs3.existsSync(resolved)) {
2313
2496
  throw new Error(`Convex directory not found: ${resolved}`);
2314
2497
  }
2315
2498
  return resolved;
2316
2499
  }
2317
- const defaultDir = path3.resolve("convex");
2318
- if (!fs2.existsSync(defaultDir)) {
2500
+ const defaultDir = path4.resolve("convex");
2501
+ if (!fs3.existsSync(defaultDir)) {
2319
2502
  throw new Error("No convex/ directory found. Specify the path: zodvex generate <path>");
2320
2503
  }
2321
2504
  return defaultDir;