zodvex 0.7.2-beta.0 → 0.7.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.
- 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/codegen/index.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from 'path';
|
|
2
|
-
import { pathToFileURL } from 'url';
|
|
3
2
|
import { globSync } from 'tinyglobby';
|
|
4
3
|
import { z } from 'zod';
|
|
5
4
|
import { $ZodCodec, $ZodNumber, $ZodCustom, $ZodOptional, $ZodNullable, $ZodString, $ZodBoolean, $ZodNull, $ZodUndefined, $ZodAny, $ZodObject, $ZodArray, $ZodEnum, $ZodLiteral, $ZodUnion, $ZodTuple, $ZodRecord, $ZodType, clone, $ZodDiscriminatedUnion } from 'zod/v4/core';
|
|
@@ -21,6 +20,20 @@ function readMeta(target) {
|
|
|
21
20
|
}
|
|
22
21
|
return target[META_KEY];
|
|
23
22
|
}
|
|
23
|
+
var CODEC_BRAND_KEY = "__zodvexCodecBrand";
|
|
24
|
+
function attachCodecBrand(target, brand) {
|
|
25
|
+
Object.defineProperty(target, CODEC_BRAND_KEY, {
|
|
26
|
+
value: brand,
|
|
27
|
+
enumerable: false,
|
|
28
|
+
writable: false,
|
|
29
|
+
configurable: false
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
function readCodecBrand(target) {
|
|
33
|
+
if (target == null || typeof target !== "object") return void 0;
|
|
34
|
+
const value = target[CODEC_BRAND_KEY];
|
|
35
|
+
return typeof value === "string" ? value : void 0;
|
|
36
|
+
}
|
|
24
37
|
var metadata = /* @__PURE__ */ new WeakMap();
|
|
25
38
|
var registryHelpers = {
|
|
26
39
|
getMetadata: (type) => metadata.get(type),
|
|
@@ -61,8 +74,10 @@ function id(tableName) {
|
|
|
61
74
|
branded._tableName = tableName;
|
|
62
75
|
return branded;
|
|
63
76
|
}
|
|
64
|
-
function codec(wire, runtime, transforms) {
|
|
65
|
-
|
|
77
|
+
function codec(wire, runtime, transforms, opts) {
|
|
78
|
+
const built = zodvexCodec(wire, runtime, transforms);
|
|
79
|
+
if (opts?.brand) attachCodecBrand(built, opts.brand);
|
|
80
|
+
return built;
|
|
66
81
|
}
|
|
67
82
|
function sharedWeakMap(name) {
|
|
68
83
|
const key = /* @__PURE__ */ Symbol.for(`zodvex.zx.cache.${name}`);
|
|
@@ -408,7 +423,6 @@ function readFnReturns(fn) {
|
|
|
408
423
|
}
|
|
409
424
|
|
|
410
425
|
// src/public/codegen/discover.ts
|
|
411
|
-
var discoveryRunCounter = 0;
|
|
412
426
|
function walkSchemaRecursive(schema, accessPath, visited, seenCodecs, results) {
|
|
413
427
|
if (visited.has(schema)) return;
|
|
414
428
|
visited.add(schema);
|
|
@@ -546,7 +560,7 @@ function walkFunctionCodecs(functions) {
|
|
|
546
560
|
}
|
|
547
561
|
return found;
|
|
548
562
|
}
|
|
549
|
-
async function discoverModules(convexDir
|
|
563
|
+
async function discoverModules(convexDir) {
|
|
550
564
|
const models = [];
|
|
551
565
|
const functions = [];
|
|
552
566
|
const codecs = [];
|
|
@@ -570,18 +584,12 @@ async function discoverModules(convexDir, options) {
|
|
|
570
584
|
"crons.js"
|
|
571
585
|
]
|
|
572
586
|
}).sort();
|
|
573
|
-
let cacheKey = null;
|
|
574
|
-
if (options?.freshImports) {
|
|
575
|
-
discoveryRunCounter += 1;
|
|
576
|
-
cacheKey = `${process.pid}-${discoveryRunCounter}`;
|
|
577
|
-
}
|
|
578
587
|
try {
|
|
579
588
|
for (const file of files) {
|
|
580
589
|
const absPath = path.resolve(convexDir, file);
|
|
581
|
-
const importUrl = cacheKey ? `${pathToFileURL(absPath).href}?t=${cacheKey}` : absPath;
|
|
582
590
|
let moduleExports;
|
|
583
591
|
try {
|
|
584
|
-
moduleExports = await import(
|
|
592
|
+
moduleExports = await import(absPath);
|
|
585
593
|
} catch (err) {
|
|
586
594
|
console.warn(`[zodvex] Warning: Failed to import ${file}:`, err.message);
|
|
587
595
|
continue;
|
|
@@ -736,7 +744,10 @@ var HEADER = `// AUTO-GENERATED by zodvex \u2014 do not edit
|
|
|
736
744
|
`;
|
|
737
745
|
function fingerprintCodec(schema) {
|
|
738
746
|
if (!(schema instanceof $ZodCodec)) return "";
|
|
739
|
-
|
|
747
|
+
const def = schema._zod.def;
|
|
748
|
+
const transform = typeof def.transform === "function" ? def.transform.toString() : "";
|
|
749
|
+
const reverse = typeof def.reverseTransform === "function" ? def.reverseTransform.toString() : "";
|
|
750
|
+
return `${fingerprintLeaf(def.in)}|${fingerprintLeaf(def.out)}|${transform}|${reverse}`;
|
|
740
751
|
}
|
|
741
752
|
function fingerprintLeaf(schema) {
|
|
742
753
|
return `${zodToSource(schema)}#${fingerprintChecks(schema)}`;
|
|
@@ -955,6 +966,7 @@ function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs,
|
|
|
955
966
|
}
|
|
956
967
|
if (functionCodecs) {
|
|
957
968
|
const fingerprintMap = /* @__PURE__ */ new Map();
|
|
969
|
+
const brandMap = /* @__PURE__ */ new Map();
|
|
958
970
|
const codecSchemaToSourceFile = /* @__PURE__ */ new Map();
|
|
959
971
|
for (const c of codecs ?? []) {
|
|
960
972
|
codecSchemaToSourceFile.set(c.schema, c.sourceFile);
|
|
@@ -963,24 +975,34 @@ function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs,
|
|
|
963
975
|
codecSchemaToSourceFile.set(mc.codec, mc.modelSourceFile);
|
|
964
976
|
}
|
|
965
977
|
for (const [codecSchema, ref] of codecMap) {
|
|
966
|
-
const fp = fingerprintCodec(codecSchema);
|
|
967
|
-
if (!fp) continue;
|
|
968
978
|
const sourceFile = codecSchemaToSourceFile.get(codecSchema);
|
|
969
|
-
const
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
fingerprintMap.
|
|
979
|
+
const brand = readCodecBrand(codecSchema);
|
|
980
|
+
const candidate = { ref, sourceFile, brand };
|
|
981
|
+
const fp = fingerprintCodec(codecSchema);
|
|
982
|
+
if (fp) {
|
|
983
|
+
const existing = fingerprintMap.get(fp);
|
|
984
|
+
if (existing) existing.push(candidate);
|
|
985
|
+
else fingerprintMap.set(fp, [candidate]);
|
|
986
|
+
}
|
|
987
|
+
if (brand) {
|
|
988
|
+
const existing = brandMap.get(brand);
|
|
989
|
+
if (existing) existing.push(candidate);
|
|
990
|
+
else brandMap.set(brand, [candidate]);
|
|
974
991
|
}
|
|
975
992
|
}
|
|
993
|
+
const undiscoverable = [];
|
|
976
994
|
for (const fc of functionCodecs) {
|
|
977
995
|
if (codecMap.has(fc.codec)) continue;
|
|
978
|
-
const
|
|
979
|
-
|
|
996
|
+
const brand = readCodecBrand(fc.codec);
|
|
997
|
+
let candidates = brand ? brandMap.get(brand) : void 0;
|
|
980
998
|
if (!candidates || candidates.length === 0) {
|
|
981
|
-
|
|
982
|
-
|
|
999
|
+
const fp = fingerprintCodec(fc.codec);
|
|
1000
|
+
candidates = (fp ? fingerprintMap.get(fp) : void 0)?.filter(
|
|
1001
|
+
(c) => c.brand === void 0 || c.brand === brand
|
|
983
1002
|
);
|
|
1003
|
+
}
|
|
1004
|
+
if (!candidates || candidates.length === 0) {
|
|
1005
|
+
undiscoverable.push({ fn: fc.functionExportName, path: fc.accessPath });
|
|
984
1006
|
continue;
|
|
985
1007
|
}
|
|
986
1008
|
let chosen;
|
|
@@ -991,14 +1013,27 @@ function generateApiFile(functions, models, codecs, modelCodecs, functionCodecs,
|
|
|
991
1013
|
if (sameFile.length === 1) {
|
|
992
1014
|
chosen = sameFile[0].ref;
|
|
993
1015
|
} else {
|
|
994
|
-
|
|
995
|
-
|
|
1016
|
+
const sorted = [...candidates].sort(
|
|
1017
|
+
(a, b) => `${a.sourceFile ?? ""}|${a.ref.exportName}`.localeCompare(
|
|
1018
|
+
`${b.sourceFile ?? ""}|${b.ref.exportName}`
|
|
1019
|
+
)
|
|
996
1020
|
);
|
|
1021
|
+
chosen = sorted[0].ref;
|
|
1022
|
+
if (!brand) {
|
|
1023
|
+
console.warn(
|
|
1024
|
+
`[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.`
|
|
1025
|
+
);
|
|
1026
|
+
}
|
|
997
1027
|
}
|
|
998
1028
|
}
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1029
|
+
codecMap.set(fc.codec, chosen);
|
|
1030
|
+
}
|
|
1031
|
+
if (undiscoverable.length > 0) {
|
|
1032
|
+
const list = undiscoverable.map((u) => ` - ${u.fn}() at ${u.path}`).join("\n");
|
|
1033
|
+
throw new Error(
|
|
1034
|
+
`[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:
|
|
1035
|
+
${list}`
|
|
1036
|
+
);
|
|
1002
1037
|
}
|
|
1003
1038
|
}
|
|
1004
1039
|
const zodToSourceCtx = {
|