zodvex 0.7.2-beta.0 → 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 +85 -36
- package/dist/cli/index.js.map +1 -1
- package/dist/codegen/index.js +64 -29
- package/dist/codegen/index.js.map +1 -1
- package/dist/core/index.js +13 -2
- package/dist/core/index.js.map +1 -1
- package/dist/index.js +13 -2
- package/dist/index.js.map +1 -1
- package/dist/internal/meta.d.ts +11 -0
- package/dist/internal/meta.d.ts.map +1 -1
- package/dist/internal/zx.d.ts +14 -0
- package/dist/internal/zx.d.ts.map +1 -1
- package/dist/legacy/index.js +13 -2
- package/dist/legacy/index.js.map +1 -1
- package/dist/mini/index.js +15 -4
- package/dist/mini/index.js.map +1 -1
- package/dist/mini/server/index.js +13 -2
- package/dist/mini/server/index.js.map +1 -1
- package/dist/public/cli/commands.d.ts +12 -1
- package/dist/public/cli/commands.d.ts.map +1 -1
- package/dist/public/codegen/discover.d.ts +7 -9
- package/dist/public/codegen/discover.d.ts.map +1 -1
- package/dist/public/codegen/generate.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/server/index.js +13 -2
- package/dist/server/index.js.map +1 -1
- package/package.json +1 -1
- package/src/internal/meta.ts +26 -0
- package/src/internal/zx.ts +18 -2
- package/src/public/cli/commands.ts +37 -15
- package/src/public/codegen/discover.ts +8 -26
- package/src/public/codegen/generate.ts +93 -36
- package/src/public/mini/zx.ts +3 -2
package/dist/cli/index.js
CHANGED
|
@@ -3,7 +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 {
|
|
6
|
+
import { spawn } from 'child_process';
|
|
7
|
+
import { fileURLToPath } from 'url';
|
|
7
8
|
import { z } from 'zod';
|
|
8
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
10
|
import 'convex/values';
|
|
@@ -1028,6 +1029,20 @@ function readMeta(target) {
|
|
|
1028
1029
|
}
|
|
1029
1030
|
return target[META_KEY];
|
|
1030
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
|
+
}
|
|
1031
1046
|
var metadata = /* @__PURE__ */ new WeakMap();
|
|
1032
1047
|
var registryHelpers = {
|
|
1033
1048
|
getMetadata: (type) => metadata.get(type),
|
|
@@ -1068,8 +1083,10 @@ function id(tableName) {
|
|
|
1068
1083
|
branded._tableName = tableName;
|
|
1069
1084
|
return branded;
|
|
1070
1085
|
}
|
|
1071
|
-
function codec(wire, runtime, transforms) {
|
|
1072
|
-
|
|
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;
|
|
1073
1090
|
}
|
|
1074
1091
|
function sharedWeakMap(name) {
|
|
1075
1092
|
const key = /* @__PURE__ */ Symbol.for(`zodvex.zx.cache.${name}`);
|
|
@@ -1394,7 +1411,6 @@ function findCodec(schema) {
|
|
|
1394
1411
|
}
|
|
1395
1412
|
|
|
1396
1413
|
// src/public/codegen/discover.ts
|
|
1397
|
-
var discoveryRunCounter = 0;
|
|
1398
1414
|
function walkSchemaRecursive(schema, accessPath, visited, seenCodecs, results) {
|
|
1399
1415
|
if (visited.has(schema)) return;
|
|
1400
1416
|
visited.add(schema);
|
|
@@ -1532,7 +1548,7 @@ function walkFunctionCodecs(functions) {
|
|
|
1532
1548
|
}
|
|
1533
1549
|
return found;
|
|
1534
1550
|
}
|
|
1535
|
-
async function discoverModules(convexDir2
|
|
1551
|
+
async function discoverModules(convexDir2) {
|
|
1536
1552
|
const models = [];
|
|
1537
1553
|
const functions = [];
|
|
1538
1554
|
const codecs = [];
|
|
@@ -1556,18 +1572,12 @@ async function discoverModules(convexDir2, options) {
|
|
|
1556
1572
|
"crons.js"
|
|
1557
1573
|
]
|
|
1558
1574
|
}).sort();
|
|
1559
|
-
let cacheKey = null;
|
|
1560
|
-
if (options?.freshImports) {
|
|
1561
|
-
discoveryRunCounter += 1;
|
|
1562
|
-
cacheKey = `${process.pid}-${discoveryRunCounter}`;
|
|
1563
|
-
}
|
|
1564
1575
|
try {
|
|
1565
1576
|
for (const file of files) {
|
|
1566
1577
|
const absPath = path3.resolve(convexDir2, file);
|
|
1567
|
-
const importUrl = cacheKey ? `${pathToFileURL(absPath).href}?t=${cacheKey}` : absPath;
|
|
1568
1578
|
let moduleExports;
|
|
1569
1579
|
try {
|
|
1570
|
-
moduleExports = await import(
|
|
1580
|
+
moduleExports = await import(absPath);
|
|
1571
1581
|
} catch (err) {
|
|
1572
1582
|
console.warn(`[zodvex] Warning: Failed to import ${file}:`, err.message);
|
|
1573
1583
|
continue;
|
|
@@ -1722,7 +1732,10 @@ var HEADER = `// AUTO-GENERATED by zodvex \u2014 do not edit
|
|
|
1722
1732
|
`;
|
|
1723
1733
|
function fingerprintCodec(schema) {
|
|
1724
1734
|
if (!(schema instanceof $ZodCodec)) return "";
|
|
1725
|
-
|
|
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}`;
|
|
1726
1739
|
}
|
|
1727
1740
|
function fingerprintLeaf(schema) {
|
|
1728
1741
|
return `${zodToSource(schema)}#${fingerprintChecks(schema)}`;
|
|
@@ -1941,6 +1954,7 @@ function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs,
|
|
|
1941
1954
|
}
|
|
1942
1955
|
if (functionCodecs) {
|
|
1943
1956
|
const fingerprintMap = /* @__PURE__ */ new Map();
|
|
1957
|
+
const brandMap = /* @__PURE__ */ new Map();
|
|
1944
1958
|
const codecSchemaToSourceFile = /* @__PURE__ */ new Map();
|
|
1945
1959
|
for (const c of codecs ?? []) {
|
|
1946
1960
|
codecSchemaToSourceFile.set(c.schema, c.sourceFile);
|
|
@@ -1949,24 +1963,34 @@ function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs,
|
|
|
1949
1963
|
codecSchemaToSourceFile.set(mc.codec, mc.modelSourceFile);
|
|
1950
1964
|
}
|
|
1951
1965
|
for (const [codecSchema, ref] of codecMap) {
|
|
1952
|
-
const fp = fingerprintCodec(codecSchema);
|
|
1953
|
-
if (!fp) continue;
|
|
1954
1966
|
const sourceFile = codecSchemaToSourceFile.get(codecSchema);
|
|
1955
|
-
const
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
fingerprintMap.
|
|
1967
|
+
const brand = readCodecBrand(codecSchema);
|
|
1968
|
+
const candidate = { ref, sourceFile, brand };
|
|
1969
|
+
const fp = fingerprintCodec(codecSchema);
|
|
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]);
|
|
1960
1979
|
}
|
|
1961
1980
|
}
|
|
1981
|
+
const undiscoverable = [];
|
|
1962
1982
|
for (const fc of functionCodecs) {
|
|
1963
1983
|
if (codecMap.has(fc.codec)) continue;
|
|
1964
|
-
const
|
|
1965
|
-
|
|
1984
|
+
const brand = readCodecBrand(fc.codec);
|
|
1985
|
+
let candidates = brand ? brandMap.get(brand) : void 0;
|
|
1966
1986
|
if (!candidates || candidates.length === 0) {
|
|
1967
|
-
|
|
1968
|
-
|
|
1987
|
+
const fp = fingerprintCodec(fc.codec);
|
|
1988
|
+
candidates = (fp ? fingerprintMap.get(fp) : void 0)?.filter(
|
|
1989
|
+
(c) => c.brand === void 0 || c.brand === brand
|
|
1969
1990
|
);
|
|
1991
|
+
}
|
|
1992
|
+
if (!candidates || candidates.length === 0) {
|
|
1993
|
+
undiscoverable.push({ fn: fc.functionExportName, path: fc.accessPath });
|
|
1970
1994
|
continue;
|
|
1971
1995
|
}
|
|
1972
1996
|
let chosen;
|
|
@@ -1977,14 +2001,27 @@ function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs,
|
|
|
1977
2001
|
if (sameFile.length === 1) {
|
|
1978
2002
|
chosen = sameFile[0].ref;
|
|
1979
2003
|
} else {
|
|
1980
|
-
|
|
1981
|
-
|
|
2004
|
+
const sorted = [...candidates].sort(
|
|
2005
|
+
(a, b) => `${a.sourceFile ?? ""}|${a.ref.exportName}`.localeCompare(
|
|
2006
|
+
`${b.sourceFile ?? ""}|${b.ref.exportName}`
|
|
2007
|
+
)
|
|
1982
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
|
+
}
|
|
1983
2015
|
}
|
|
1984
2016
|
}
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
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
|
+
);
|
|
1988
2025
|
}
|
|
1989
2026
|
}
|
|
1990
2027
|
const zodToSourceCtx = {
|
|
@@ -2156,7 +2193,7 @@ async function generate(convexDir2, options) {
|
|
|
2156
2193
|
const resolved = resolveConvexDir(convexDir2);
|
|
2157
2194
|
const zodvexDir = path3.join(resolved, "_zodvex");
|
|
2158
2195
|
writeStubApi(zodvexDir);
|
|
2159
|
-
const result = await discoverModules(resolved
|
|
2196
|
+
const result = await discoverModules(resolved);
|
|
2160
2197
|
const schemaContent = generateSchemaFile(result.models);
|
|
2161
2198
|
const apiContent = generateApiFile(
|
|
2162
2199
|
result.functions,
|
|
@@ -2193,13 +2230,9 @@ async function dev(convexDir2, options) {
|
|
|
2193
2230
|
return;
|
|
2194
2231
|
}
|
|
2195
2232
|
if (debounceTimer) clearTimeout(debounceTimer);
|
|
2196
|
-
debounceTimer = setTimeout(
|
|
2233
|
+
debounceTimer = setTimeout(() => {
|
|
2197
2234
|
console.log("[zodvex] Regenerating...");
|
|
2198
|
-
|
|
2199
|
-
await generate(resolved, { ...options, freshImports: true });
|
|
2200
|
-
} catch (err) {
|
|
2201
|
-
console.error("[zodvex] Generation failed:", err.message);
|
|
2202
|
-
}
|
|
2235
|
+
void regenerate(resolved, options);
|
|
2203
2236
|
}, 300);
|
|
2204
2237
|
});
|
|
2205
2238
|
process.on("SIGINT", () => {
|
|
@@ -2208,6 +2241,22 @@ async function dev(convexDir2, options) {
|
|
|
2208
2241
|
process.exit(0);
|
|
2209
2242
|
});
|
|
2210
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
|
+
}
|
|
2211
2260
|
function writeStubApi(zodvexDir) {
|
|
2212
2261
|
fs2.mkdirSync(zodvexDir, { recursive: true });
|
|
2213
2262
|
fs2.writeFileSync(
|