zodvex 0.7.1 → 0.7.2-beta.1
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/cli/index.js +186 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/codegen/index.js +137 -14
- package/dist/codegen/index.js.map +1 -1
- package/dist/core/index.js +56 -10
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +56 -10
- package/dist/index.js.map +1 -1
- package/dist/internal/db.d.ts +14 -11
- package/dist/internal/db.d.ts.map +1 -1
- package/dist/internal/meta.d.ts +11 -0
- package/dist/internal/meta.d.ts.map +1 -1
- package/dist/internal/model.d.ts +21 -0
- package/dist/internal/model.d.ts.map +1 -1
- package/dist/internal/zx.d.ts +14 -0
- package/dist/internal/zx.d.ts.map +1 -1
- package/dist/labs/index.js +29 -4
- package/dist/labs/index.js.map +1 -1
- package/dist/legacy/index.js +13 -2
- package/dist/legacy/index.js.map +1 -1
- package/dist/mini/index.js +58 -12
- package/dist/mini/index.js.map +1 -1
- package/dist/mini/server/index.js +37 -27
- package/dist/mini/server/index.js.map +1 -1
- package/dist/public/cli/commands.d.ts +12 -0
- package/dist/public/cli/commands.d.ts.map +1 -1
- package/dist/public/codegen/discover.d.ts +8 -0
- package/dist/public/codegen/discover.d.ts.map +1 -1
- package/dist/public/codegen/generate.d.ts.map +1 -1
- package/dist/public/mini/model.d.ts +6 -0
- package/dist/public/mini/model.d.ts.map +1 -1
- package/dist/public/mini/zx.d.ts +2 -0
- package/dist/public/mini/zx.d.ts.map +1 -1
- package/dist/public/model.d.ts +6 -0
- package/dist/public/model.d.ts.map +1 -1
- package/dist/server/index.js +37 -27
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
- package/src/internal/db.ts +33 -52
- package/src/internal/meta.ts +26 -0
- package/src/internal/model.ts +76 -9
- package/src/internal/zx.ts +18 -2
- package/src/public/cli/commands.ts +35 -6
- package/src/public/codegen/discover.ts +9 -1
- package/src/public/codegen/generate.ts +203 -15
- package/src/public/mini/model.ts +6 -0
- package/src/public/mini/zx.ts +3 -2
- package/src/public/model.ts +6 -0
package/dist/cli/index.js
CHANGED
|
@@ -3,6 +3,8 @@ import fs2, { readFileSync, writeFileSync, existsSync } from 'fs';
|
|
|
3
3
|
import path3, { resolve, relative, join } from 'path';
|
|
4
4
|
import { Project, SyntaxKind } from 'ts-morph';
|
|
5
5
|
import { globSync } from 'tinyglobby';
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
6
8
|
import { z } from 'zod';
|
|
7
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';
|
|
8
10
|
import 'convex/values';
|
|
@@ -318,7 +320,7 @@ function getMethodName(call) {
|
|
|
318
320
|
if (expr.getKind() !== SyntaxKind.PropertyAccessExpression) return null;
|
|
319
321
|
return expr.getName();
|
|
320
322
|
}
|
|
321
|
-
function transformWrappers(file) {
|
|
323
|
+
function transformWrappers(file, typeChecker) {
|
|
322
324
|
let count = 0;
|
|
323
325
|
const calls = file.getDescendantsOfKind(SyntaxKind.CallExpression).reverse();
|
|
324
326
|
for (const call of calls) {
|
|
@@ -328,6 +330,18 @@ function transformWrappers(file) {
|
|
|
328
330
|
if (call.getArguments().length > 0) continue;
|
|
329
331
|
const obj = getCallObject(call);
|
|
330
332
|
if (!obj) continue;
|
|
333
|
+
if (isNamespaceCall(obj)) continue;
|
|
334
|
+
let isSchema;
|
|
335
|
+
if (typeChecker) {
|
|
336
|
+
const typeResult = isZodSchemaByType(call, typeChecker);
|
|
337
|
+
isSchema = typeResult === true || typeResult === null && isLikelySchemaExpr(obj);
|
|
338
|
+
} else {
|
|
339
|
+
isSchema = isLikelySchemaExpr(obj);
|
|
340
|
+
}
|
|
341
|
+
if (!isSchema && isSchemaVariable(call, obj.trim())) {
|
|
342
|
+
isSchema = true;
|
|
343
|
+
}
|
|
344
|
+
if (!isSchema) continue;
|
|
331
345
|
call.replaceWithText(`z.${method}(${obj})`);
|
|
332
346
|
count++;
|
|
333
347
|
}
|
|
@@ -337,8 +351,9 @@ function isNamespaceCall(obj) {
|
|
|
337
351
|
return NAMESPACE_IDENTIFIERS.has(obj.trim());
|
|
338
352
|
}
|
|
339
353
|
function isLikelySchemaExpr(obj) {
|
|
340
|
-
|
|
341
|
-
if (
|
|
354
|
+
const normalized = obj.trim().replace(/^\(+/, "").replace(/\s+as\s+[\w$<>,\s|&[\]]+\)*\s*$/, "").trim();
|
|
355
|
+
if (normalized.match(/^z\.\w+\(/)) return true;
|
|
356
|
+
if (normalized.match(/^zx\.\w+\(/)) return true;
|
|
342
357
|
return false;
|
|
343
358
|
}
|
|
344
359
|
function isSchemaVariable(call, varName) {
|
|
@@ -561,6 +576,17 @@ function findObjectOnlyMethods(file) {
|
|
|
561
576
|
}
|
|
562
577
|
return results;
|
|
563
578
|
}
|
|
579
|
+
function ensureZImport(file) {
|
|
580
|
+
const text = file.getFullText();
|
|
581
|
+
if (!/\bz\./.test(text)) return;
|
|
582
|
+
const hasZImport = file.getImportDeclarations().some((imp) => imp.getNamedImports().some((n) => n.getName() === "z"));
|
|
583
|
+
if (hasZImport) return;
|
|
584
|
+
if (/^\s*(?:const|let|var)\s+z\s*[=:]/m.test(text)) return;
|
|
585
|
+
file.addImportDeclaration({
|
|
586
|
+
moduleSpecifier: "zod/mini",
|
|
587
|
+
namedImports: [{ name: "z" }]
|
|
588
|
+
});
|
|
589
|
+
}
|
|
564
590
|
function transformImports(file) {
|
|
565
591
|
let count = 0;
|
|
566
592
|
const imports = file.getImportDeclarations();
|
|
@@ -708,7 +734,7 @@ function transformFile(file, typeChecker) {
|
|
|
708
734
|
let propertyAccessors = 0;
|
|
709
735
|
for (let i = 0; i < 10; i++) {
|
|
710
736
|
const cr = transformConstructorReplacements(file);
|
|
711
|
-
const w = transformWrappers(file);
|
|
737
|
+
const w = transformWrappers(file, typeChecker);
|
|
712
738
|
const c = transformChecks(file);
|
|
713
739
|
const m = transformMethods(file, typeChecker);
|
|
714
740
|
const pa = transformPropertyAccessors(file, typeChecker);
|
|
@@ -722,6 +748,7 @@ function transformFile(file, typeChecker) {
|
|
|
722
748
|
const classRefs = transformClassRefs(file);
|
|
723
749
|
const objectOnlyWarnings = findObjectOnlyMethods(file);
|
|
724
750
|
const propertyAccessWarnings = findInternalPropertyAccess(file, typeChecker);
|
|
751
|
+
ensureZImport(file);
|
|
725
752
|
const imports = 0;
|
|
726
753
|
return {
|
|
727
754
|
filePath,
|
|
@@ -1002,6 +1029,20 @@ function readMeta(target) {
|
|
|
1002
1029
|
}
|
|
1003
1030
|
return target[META_KEY];
|
|
1004
1031
|
}
|
|
1032
|
+
var CODEC_BRAND_KEY = "__zodvexCodecBrand";
|
|
1033
|
+
function attachCodecBrand(target, brand) {
|
|
1034
|
+
Object.defineProperty(target, CODEC_BRAND_KEY, {
|
|
1035
|
+
value: brand,
|
|
1036
|
+
enumerable: false,
|
|
1037
|
+
writable: false,
|
|
1038
|
+
configurable: false
|
|
1039
|
+
});
|
|
1040
|
+
}
|
|
1041
|
+
function readCodecBrand(target) {
|
|
1042
|
+
if (target == null || typeof target !== "object") return void 0;
|
|
1043
|
+
const value = target[CODEC_BRAND_KEY];
|
|
1044
|
+
return typeof value === "string" ? value : void 0;
|
|
1045
|
+
}
|
|
1005
1046
|
var metadata = /* @__PURE__ */ new WeakMap();
|
|
1006
1047
|
var registryHelpers = {
|
|
1007
1048
|
getMetadata: (type) => metadata.get(type),
|
|
@@ -1042,8 +1083,10 @@ function id(tableName) {
|
|
|
1042
1083
|
branded._tableName = tableName;
|
|
1043
1084
|
return branded;
|
|
1044
1085
|
}
|
|
1045
|
-
function codec(wire, runtime, transforms) {
|
|
1046
|
-
|
|
1086
|
+
function codec(wire, runtime, transforms, opts) {
|
|
1087
|
+
const built = zodvexCodec(wire, runtime, transforms);
|
|
1088
|
+
if (opts?.brand) attachCodecBrand(built, opts.brand);
|
|
1089
|
+
return built;
|
|
1047
1090
|
}
|
|
1048
1091
|
function sharedWeakMap(name) {
|
|
1049
1092
|
const key = /* @__PURE__ */ Symbol.for(`zodvex.zx.cache.${name}`);
|
|
@@ -1528,7 +1571,7 @@ async function discoverModules(convexDir2) {
|
|
|
1528
1571
|
"crons.ts",
|
|
1529
1572
|
"crons.js"
|
|
1530
1573
|
]
|
|
1531
|
-
});
|
|
1574
|
+
}).sort();
|
|
1532
1575
|
try {
|
|
1533
1576
|
for (const file of files) {
|
|
1534
1577
|
const absPath = path3.resolve(convexDir2, file);
|
|
@@ -1689,7 +1732,35 @@ var HEADER = `// AUTO-GENERATED by zodvex \u2014 do not edit
|
|
|
1689
1732
|
`;
|
|
1690
1733
|
function fingerprintCodec(schema) {
|
|
1691
1734
|
if (!(schema instanceof $ZodCodec)) return "";
|
|
1692
|
-
|
|
1735
|
+
const def = schema._zod.def;
|
|
1736
|
+
const transform = typeof def.transform === "function" ? def.transform.toString() : "";
|
|
1737
|
+
const reverse = typeof def.reverseTransform === "function" ? def.reverseTransform.toString() : "";
|
|
1738
|
+
return `${fingerprintLeaf(def.in)}|${fingerprintLeaf(def.out)}|${transform}|${reverse}`;
|
|
1739
|
+
}
|
|
1740
|
+
function fingerprintLeaf(schema) {
|
|
1741
|
+
return `${zodToSource(schema)}#${fingerprintChecks(schema)}`;
|
|
1742
|
+
}
|
|
1743
|
+
function fingerprintChecks(schema) {
|
|
1744
|
+
const checks = schema?._zod?.def?.checks;
|
|
1745
|
+
if (!Array.isArray(checks) || checks.length === 0) return "";
|
|
1746
|
+
const parts = [];
|
|
1747
|
+
for (const check of checks) {
|
|
1748
|
+
const def = check?._zod?.def;
|
|
1749
|
+
if (!def) continue;
|
|
1750
|
+
const checkType = def.check ?? def.type ?? "check";
|
|
1751
|
+
const data = {};
|
|
1752
|
+
for (const [k, v7] of Object.entries(def)) {
|
|
1753
|
+
if (k === "check" || k === "type" || k === "error" || k === "message") continue;
|
|
1754
|
+
const t = typeof v7;
|
|
1755
|
+
if (t === "string" || t === "number" || t === "boolean" || v7 === null) {
|
|
1756
|
+
data[k] = v7;
|
|
1757
|
+
} else if (v7 instanceof RegExp) {
|
|
1758
|
+
data[k] = v7.source;
|
|
1759
|
+
}
|
|
1760
|
+
}
|
|
1761
|
+
parts.push(`${checkType}(${JSON.stringify(data)})`);
|
|
1762
|
+
}
|
|
1763
|
+
return parts.sort().join("&");
|
|
1693
1764
|
}
|
|
1694
1765
|
function generateSchemaFile(models) {
|
|
1695
1766
|
const exports$1 = models.map((m) => {
|
|
@@ -1776,6 +1847,30 @@ function deriveCodecVarName(modelExportName, accessPath) {
|
|
|
1776
1847
|
return `_${prefix}${fieldPart[0].toUpperCase() + fieldPart.slice(1)}`;
|
|
1777
1848
|
}
|
|
1778
1849
|
function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs, options) {
|
|
1850
|
+
const sortedModels = [...models].sort(
|
|
1851
|
+
(a, b) => `${a.sourceFile}|${a.exportName}`.localeCompare(`${b.sourceFile}|${b.exportName}`)
|
|
1852
|
+
);
|
|
1853
|
+
const sortedFunctions = [...functions].sort(
|
|
1854
|
+
(a, b) => a.functionPath.localeCompare(b.functionPath)
|
|
1855
|
+
);
|
|
1856
|
+
const sortedCodecs = codecs ? [...codecs].sort(
|
|
1857
|
+
(a, b) => `${a.sourceFile}|${a.exportName}`.localeCompare(`${b.sourceFile}|${b.exportName}`)
|
|
1858
|
+
) : void 0;
|
|
1859
|
+
const sortedModelCodecs = modelCodecs ? [...modelCodecs].sort(
|
|
1860
|
+
(a, b) => `${a.modelSourceFile}|${a.modelExportName}|${a.schemaKey}|${a.accessPath}`.localeCompare(
|
|
1861
|
+
`${b.modelSourceFile}|${b.modelExportName}|${b.schemaKey}|${b.accessPath}`
|
|
1862
|
+
)
|
|
1863
|
+
) : void 0;
|
|
1864
|
+
const sortedFunctionCodecs = functionCodecs ? [...functionCodecs].sort(
|
|
1865
|
+
(a, b) => `${a.functionSourceFile}|${a.functionExportName}|${a.schemaSource}|${a.accessPath}`.localeCompare(
|
|
1866
|
+
`${b.functionSourceFile}|${b.functionExportName}|${b.schemaSource}|${b.accessPath}`
|
|
1867
|
+
)
|
|
1868
|
+
) : void 0;
|
|
1869
|
+
models = sortedModels;
|
|
1870
|
+
functions = sortedFunctions;
|
|
1871
|
+
codecs = sortedCodecs;
|
|
1872
|
+
modelCodecs = sortedModelCodecs;
|
|
1873
|
+
functionCodecs = sortedFunctionCodecs;
|
|
1779
1874
|
const identityMap = /* @__PURE__ */ new Map();
|
|
1780
1875
|
const neededModelImports = /* @__PURE__ */ new Set();
|
|
1781
1876
|
for (const model of models) {
|
|
@@ -1859,21 +1954,74 @@ function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs,
|
|
|
1859
1954
|
}
|
|
1860
1955
|
if (functionCodecs) {
|
|
1861
1956
|
const fingerprintMap = /* @__PURE__ */ new Map();
|
|
1957
|
+
const brandMap = /* @__PURE__ */ new Map();
|
|
1958
|
+
const codecSchemaToSourceFile = /* @__PURE__ */ new Map();
|
|
1959
|
+
for (const c of codecs ?? []) {
|
|
1960
|
+
codecSchemaToSourceFile.set(c.schema, c.sourceFile);
|
|
1961
|
+
}
|
|
1962
|
+
for (const mc of modelCodecs ?? []) {
|
|
1963
|
+
codecSchemaToSourceFile.set(mc.codec, mc.modelSourceFile);
|
|
1964
|
+
}
|
|
1862
1965
|
for (const [codecSchema, ref] of codecMap) {
|
|
1966
|
+
const sourceFile = codecSchemaToSourceFile.get(codecSchema);
|
|
1967
|
+
const brand = readCodecBrand(codecSchema);
|
|
1968
|
+
const candidate = { ref, sourceFile, brand };
|
|
1863
1969
|
const fp = fingerprintCodec(codecSchema);
|
|
1864
|
-
if (fp)
|
|
1970
|
+
if (fp) {
|
|
1971
|
+
const existing = fingerprintMap.get(fp);
|
|
1972
|
+
if (existing) existing.push(candidate);
|
|
1973
|
+
else fingerprintMap.set(fp, [candidate]);
|
|
1974
|
+
}
|
|
1975
|
+
if (brand) {
|
|
1976
|
+
const existing = brandMap.get(brand);
|
|
1977
|
+
if (existing) existing.push(candidate);
|
|
1978
|
+
else brandMap.set(brand, [candidate]);
|
|
1979
|
+
}
|
|
1865
1980
|
}
|
|
1981
|
+
const undiscoverable = [];
|
|
1866
1982
|
for (const fc of functionCodecs) {
|
|
1867
1983
|
if (codecMap.has(fc.codec)) continue;
|
|
1868
|
-
const
|
|
1869
|
-
|
|
1870
|
-
if (
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
`[zodvex] Warning: Codec in ${fc.functionExportName}() (${fc.accessPath}) has no matching model or exported codec. Export it standalone for full client-side codec support.`
|
|
1984
|
+
const brand = readCodecBrand(fc.codec);
|
|
1985
|
+
let candidates = brand ? brandMap.get(brand) : void 0;
|
|
1986
|
+
if (!candidates || candidates.length === 0) {
|
|
1987
|
+
const fp = fingerprintCodec(fc.codec);
|
|
1988
|
+
candidates = (fp ? fingerprintMap.get(fp) : void 0)?.filter(
|
|
1989
|
+
(c) => c.brand === void 0 || c.brand === brand
|
|
1875
1990
|
);
|
|
1876
1991
|
}
|
|
1992
|
+
if (!candidates || candidates.length === 0) {
|
|
1993
|
+
undiscoverable.push({ fn: fc.functionExportName, path: fc.accessPath });
|
|
1994
|
+
continue;
|
|
1995
|
+
}
|
|
1996
|
+
let chosen;
|
|
1997
|
+
if (candidates.length === 1) {
|
|
1998
|
+
chosen = candidates[0].ref;
|
|
1999
|
+
} else {
|
|
2000
|
+
const sameFile = candidates.filter((c) => c.sourceFile === fc.functionSourceFile);
|
|
2001
|
+
if (sameFile.length === 1) {
|
|
2002
|
+
chosen = sameFile[0].ref;
|
|
2003
|
+
} else {
|
|
2004
|
+
const sorted = [...candidates].sort(
|
|
2005
|
+
(a, b) => `${a.sourceFile ?? ""}|${a.ref.exportName}`.localeCompare(
|
|
2006
|
+
`${b.sourceFile ?? ""}|${b.ref.exportName}`
|
|
2007
|
+
)
|
|
2008
|
+
);
|
|
2009
|
+
chosen = sorted[0].ref;
|
|
2010
|
+
if (!brand) {
|
|
2011
|
+
console.warn(
|
|
2012
|
+
`[zodvex] Note: Codec in ${fc.functionExportName}() (${fc.accessPath}) matches ${candidates.length} fingerprint-equivalent codecs (${candidates.map((c) => c.ref.exportName).join(", ")}). Referencing '${chosen.exportName}'. Export the codec standalone or give it a brand if you want the reference to be explicit.`
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
2015
|
+
}
|
|
2016
|
+
}
|
|
2017
|
+
codecMap.set(fc.codec, chosen);
|
|
2018
|
+
}
|
|
2019
|
+
if (undiscoverable.length > 0) {
|
|
2020
|
+
const list = undiscoverable.map((u) => ` - ${u.fn}() at ${u.path}`).join("\n");
|
|
2021
|
+
throw new Error(
|
|
2022
|
+
`[zodvex] ${undiscoverable.length} codec(s) in function args/returns have no importable reference (not exported standalone, not embedded in a model). The generated client cannot encode or decode them, which silently breaks the codec boundary. Export each codec standalone (or add it to a model) so codegen can import it:
|
|
2023
|
+
${list}`
|
|
2024
|
+
);
|
|
1877
2025
|
}
|
|
1878
2026
|
}
|
|
1879
2027
|
const zodToSourceCtx = {
|
|
@@ -1932,15 +2080,17 @@ function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs,
|
|
|
1932
2080
|
if (coreImports.length > 0) {
|
|
1933
2081
|
imports.push(`import { ${coreImports.join(", ")} } from '${zodvexImport}'`);
|
|
1934
2082
|
}
|
|
1935
|
-
for (const exportName of neededModelImports) {
|
|
2083
|
+
for (const exportName of [...neededModelImports].sort()) {
|
|
1936
2084
|
const model = models.find((m) => m.exportName === exportName);
|
|
1937
2085
|
if (model) {
|
|
1938
2086
|
const importPath = `../${model.sourceFile.replace(/\.ts$/, ".js")}`;
|
|
1939
2087
|
imports.push(`import { ${exportName} } from '${importPath}'`);
|
|
1940
2088
|
}
|
|
1941
2089
|
}
|
|
1942
|
-
|
|
2090
|
+
const sortedCodecImportPaths = [...zodToSourceCtx.neededCodecImports.keys()].sort();
|
|
2091
|
+
for (const importPath of sortedCodecImportPaths) {
|
|
1943
2092
|
if (importPath === MODEL_CODEC_SENTINEL) continue;
|
|
2093
|
+
const exportNames = zodToSourceCtx.neededCodecImports.get(importPath) ?? /* @__PURE__ */ new Set();
|
|
1944
2094
|
const names = Array.from(exportNames).sort().join(", ");
|
|
1945
2095
|
imports.push(`import { ${names} } from '${importPath}'`);
|
|
1946
2096
|
}
|
|
@@ -2080,13 +2230,9 @@ async function dev(convexDir2, options) {
|
|
|
2080
2230
|
return;
|
|
2081
2231
|
}
|
|
2082
2232
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
2083
|
-
debounceTimer = setTimeout(
|
|
2233
|
+
debounceTimer = setTimeout(() => {
|
|
2084
2234
|
console.log("[zodvex] Regenerating...");
|
|
2085
|
-
|
|
2086
|
-
await generate(resolved, options);
|
|
2087
|
-
} catch (err) {
|
|
2088
|
-
console.error("[zodvex] Generation failed:", err.message);
|
|
2089
|
-
}
|
|
2235
|
+
void regenerate(resolved, options);
|
|
2090
2236
|
}, 300);
|
|
2091
2237
|
});
|
|
2092
2238
|
process.on("SIGINT", () => {
|
|
@@ -2095,6 +2241,22 @@ async function dev(convexDir2, options) {
|
|
|
2095
2241
|
process.exit(0);
|
|
2096
2242
|
});
|
|
2097
2243
|
}
|
|
2244
|
+
function regenerate(resolved, options) {
|
|
2245
|
+
const cliEntry = fileURLToPath(new URL("./index.js", import.meta.url));
|
|
2246
|
+
const args = [cliEntry, "generate", resolved];
|
|
2247
|
+
if (options?.mini) args.push("--mini");
|
|
2248
|
+
return new Promise((resolve2) => {
|
|
2249
|
+
const child = spawn(process.execPath, args, { stdio: "inherit" });
|
|
2250
|
+
child.on("exit", (code) => {
|
|
2251
|
+
if (code !== 0) console.error(`[zodvex] Regeneration exited with code ${code}`);
|
|
2252
|
+
resolve2();
|
|
2253
|
+
});
|
|
2254
|
+
child.on("error", (err) => {
|
|
2255
|
+
console.error("[zodvex] Failed to spawn regeneration:", err.message);
|
|
2256
|
+
resolve2();
|
|
2257
|
+
});
|
|
2258
|
+
});
|
|
2259
|
+
}
|
|
2098
2260
|
function writeStubApi(zodvexDir) {
|
|
2099
2261
|
fs2.mkdirSync(zodvexDir, { recursive: true });
|
|
2100
2262
|
fs2.writeFileSync(
|