@orpc/zod 0.0.0-next.de766b3 → 0.0.0-next.de7ca70
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 +1 -1
- package/dist/index.d.mts +15 -6
- package/dist/index.d.ts +15 -6
- package/dist/index.mjs +75 -38
- package/dist/zod4/index.d.mts +14 -2
- package/dist/zod4/index.d.ts +14 -2
- package/dist/zod4/index.mjs +57 -32
- package/package.json +8 -7
package/README.md
CHANGED
@@ -30,7 +30,7 @@
|
|
30
30
|
- **🔗 End-to-End Type Safety**: Ensure type-safe inputs, outputs, and errors from client to server.
|
31
31
|
- **📘 First-Class OpenAPI**: Built-in support that fully adheres to the OpenAPI standard.
|
32
32
|
- **📝 Contract-First Development**: Optionally define your API contract before implementation.
|
33
|
-
- **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte), Pinia Colada, and more.
|
33
|
+
- **⚙️ Framework Integrations**: Seamlessly integrate with TanStack Query (React, Vue, Solid, Svelte, Angular), Pinia Colada, and more.
|
34
34
|
- **🚀 Server Actions**: Fully compatible with React Server Actions on Next.js, TanStack Start, and other platforms.
|
35
35
|
- **🔠 Standard Schema Support**: Works out of the box with Zod, Valibot, ArkType, and other schema validators.
|
36
36
|
- **🗃️ Native Types**: Supports native types like Date, File, Blob, BigInt, URL, and more.
|
package/dist/index.d.mts
CHANGED
@@ -40,34 +40,43 @@ declare class ZodSmartCoercionPlugin<TContext extends Context> implements Standa
|
|
40
40
|
|
41
41
|
interface ZodToJsonSchemaOptions {
|
42
42
|
/**
|
43
|
-
* Max depth of lazy type
|
43
|
+
* Max depth of lazy type
|
44
44
|
*
|
45
|
-
* Used `{}` when
|
45
|
+
* Used `{}` when exceed max depth
|
46
46
|
*
|
47
47
|
* @default 3
|
48
48
|
*/
|
49
49
|
maxLazyDepth?: number;
|
50
50
|
/**
|
51
|
-
*
|
51
|
+
* Max depth of nested types
|
52
52
|
*
|
53
|
-
*
|
53
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
54
|
+
*
|
55
|
+
* @default 10
|
54
56
|
*/
|
55
|
-
|
57
|
+
maxStructureDepth?: number;
|
56
58
|
/**
|
57
59
|
* The schema to be used to represent the any | unknown type.
|
58
60
|
*
|
59
61
|
* @default { }
|
60
62
|
*/
|
61
63
|
anyJsonSchema?: Exclude<JSONSchema, boolean>;
|
64
|
+
/**
|
65
|
+
* The schema to be used when the Zod schema is unsupported.
|
66
|
+
*
|
67
|
+
* @default { not: {} }
|
68
|
+
*/
|
69
|
+
unsupportedJsonSchema?: Exclude<JSONSchema, boolean>;
|
62
70
|
}
|
63
71
|
declare class ZodToJsonSchemaConverter implements ConditionalSchemaConverter {
|
64
72
|
#private;
|
65
73
|
private readonly maxLazyDepth;
|
74
|
+
private readonly maxStructureDepth;
|
66
75
|
private readonly unsupportedJsonSchema;
|
67
76
|
private readonly anyJsonSchema;
|
68
77
|
constructor(options?: ZodToJsonSchemaOptions);
|
69
78
|
condition(schema: AnySchema | undefined): boolean;
|
70
|
-
convert(schema: AnySchema | undefined, options: SchemaConvertOptions, lazyDepth?: number, isHandledCustomJSONSchema?: boolean, isHandledZodDescription?: boolean): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
79
|
+
convert(schema: AnySchema | undefined, options: SchemaConvertOptions, lazyDepth?: number, isHandledCustomJSONSchema?: boolean, isHandledZodDescription?: boolean, structureDepth?: number): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
71
80
|
}
|
72
81
|
|
73
82
|
declare const oz: {
|
package/dist/index.d.ts
CHANGED
@@ -40,34 +40,43 @@ declare class ZodSmartCoercionPlugin<TContext extends Context> implements Standa
|
|
40
40
|
|
41
41
|
interface ZodToJsonSchemaOptions {
|
42
42
|
/**
|
43
|
-
* Max depth of lazy type
|
43
|
+
* Max depth of lazy type
|
44
44
|
*
|
45
|
-
* Used `{}` when
|
45
|
+
* Used `{}` when exceed max depth
|
46
46
|
*
|
47
47
|
* @default 3
|
48
48
|
*/
|
49
49
|
maxLazyDepth?: number;
|
50
50
|
/**
|
51
|
-
*
|
51
|
+
* Max depth of nested types
|
52
52
|
*
|
53
|
-
*
|
53
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
54
|
+
*
|
55
|
+
* @default 10
|
54
56
|
*/
|
55
|
-
|
57
|
+
maxStructureDepth?: number;
|
56
58
|
/**
|
57
59
|
* The schema to be used to represent the any | unknown type.
|
58
60
|
*
|
59
61
|
* @default { }
|
60
62
|
*/
|
61
63
|
anyJsonSchema?: Exclude<JSONSchema, boolean>;
|
64
|
+
/**
|
65
|
+
* The schema to be used when the Zod schema is unsupported.
|
66
|
+
*
|
67
|
+
* @default { not: {} }
|
68
|
+
*/
|
69
|
+
unsupportedJsonSchema?: Exclude<JSONSchema, boolean>;
|
62
70
|
}
|
63
71
|
declare class ZodToJsonSchemaConverter implements ConditionalSchemaConverter {
|
64
72
|
#private;
|
65
73
|
private readonly maxLazyDepth;
|
74
|
+
private readonly maxStructureDepth;
|
66
75
|
private readonly unsupportedJsonSchema;
|
67
76
|
private readonly anyJsonSchema;
|
68
77
|
constructor(options?: ZodToJsonSchemaOptions);
|
69
78
|
condition(schema: AnySchema | undefined): boolean;
|
70
|
-
convert(schema: AnySchema | undefined, options: SchemaConvertOptions, lazyDepth?: number, isHandledCustomJSONSchema?: boolean, isHandledZodDescription?: boolean): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
79
|
+
convert(schema: AnySchema | undefined, options: SchemaConvertOptions, lazyDepth?: number, isHandledCustomJSONSchema?: boolean, isHandledZodDescription?: boolean, structureDepth?: number): [required: boolean, jsonSchema: Exclude<JSONSchema, boolean>];
|
71
80
|
}
|
72
81
|
|
73
82
|
declare const oz: {
|
package/dist/index.mjs
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
import { custom, ZodFirstPartyTypeKind } from 'zod';
|
2
2
|
import wcmatch from 'wildcard-match';
|
3
|
-
import { isObject, guard } from '@orpc/shared';
|
3
|
+
import { isObject, guard, toArray } from '@orpc/shared';
|
4
|
+
import { JsonSchemaXNativeType } from '@orpc/json-schema';
|
4
5
|
import { JSONSchemaFormat } from '@orpc/openapi';
|
5
6
|
import escapeStringRegexp from 'escape-string-regexp';
|
6
7
|
|
@@ -390,25 +391,39 @@ function safeToDate(value) {
|
|
390
391
|
|
391
392
|
class ZodToJsonSchemaConverter {
|
392
393
|
maxLazyDepth;
|
394
|
+
maxStructureDepth;
|
393
395
|
unsupportedJsonSchema;
|
394
396
|
anyJsonSchema;
|
395
397
|
constructor(options = {}) {
|
396
398
|
this.maxLazyDepth = options.maxLazyDepth ?? 3;
|
399
|
+
this.maxStructureDepth = options.maxStructureDepth ?? 10;
|
397
400
|
this.unsupportedJsonSchema = options.unsupportedJsonSchema ?? { not: {} };
|
398
401
|
this.anyJsonSchema = options.anyJsonSchema ?? {};
|
399
402
|
}
|
400
403
|
condition(schema) {
|
401
404
|
return schema !== void 0 && schema["~standard"].vendor === "zod";
|
402
405
|
}
|
403
|
-
convert(schema, options, lazyDepth = 0, isHandledCustomJSONSchema = false, isHandledZodDescription = false) {
|
406
|
+
convert(schema, options, lazyDepth = 0, isHandledCustomJSONSchema = false, isHandledZodDescription = false, structureDepth = 0) {
|
404
407
|
const def = schema._def;
|
408
|
+
if (structureDepth > this.maxStructureDepth) {
|
409
|
+
return [false, this.anyJsonSchema];
|
410
|
+
}
|
411
|
+
if (!options.minStructureDepthForRef || options.minStructureDepthForRef <= structureDepth) {
|
412
|
+
const components = toArray(options.components);
|
413
|
+
for (const component of components) {
|
414
|
+
if (component.schema === schema && component.allowedStrategies.includes(options.strategy)) {
|
415
|
+
return [component.required, { $ref: component.ref }];
|
416
|
+
}
|
417
|
+
}
|
418
|
+
}
|
405
419
|
if (!isHandledZodDescription && "description" in def && typeof def.description === "string") {
|
406
420
|
const [required, json] = this.convert(
|
407
421
|
schema,
|
408
422
|
options,
|
409
423
|
lazyDepth,
|
410
424
|
isHandledCustomJSONSchema,
|
411
|
-
true
|
425
|
+
true,
|
426
|
+
structureDepth
|
412
427
|
);
|
413
428
|
return [required, { ...json, description: def.description }];
|
414
429
|
}
|
@@ -420,7 +435,8 @@ class ZodToJsonSchemaConverter {
|
|
420
435
|
options,
|
421
436
|
lazyDepth,
|
422
437
|
true,
|
423
|
-
isHandledZodDescription
|
438
|
+
isHandledZodDescription,
|
439
|
+
structureDepth
|
424
440
|
);
|
425
441
|
return [required, { ...json, ...customJSONSchema }];
|
426
442
|
}
|
@@ -548,7 +564,11 @@ class ZodToJsonSchemaConverter {
|
|
548
564
|
return [true, json];
|
549
565
|
}
|
550
566
|
case ZodFirstPartyTypeKind.ZodBigInt: {
|
551
|
-
const json = {
|
567
|
+
const json = {
|
568
|
+
"type": "string",
|
569
|
+
"pattern": "^-?[0-9]+$",
|
570
|
+
"x-native-type": JsonSchemaXNativeType.BigInt
|
571
|
+
};
|
552
572
|
return [true, json];
|
553
573
|
}
|
554
574
|
case ZodFirstPartyTypeKind.ZodNaN: {
|
@@ -558,7 +578,11 @@ class ZodToJsonSchemaConverter {
|
|
558
578
|
return [true, { type: "boolean" }];
|
559
579
|
}
|
560
580
|
case ZodFirstPartyTypeKind.ZodDate: {
|
561
|
-
const schema2 = {
|
581
|
+
const schema2 = {
|
582
|
+
"type": "string",
|
583
|
+
"format": JSONSchemaFormat.DateTime,
|
584
|
+
"x-native-type": JsonSchemaXNativeType.Date
|
585
|
+
};
|
562
586
|
return [true, schema2];
|
563
587
|
}
|
564
588
|
case ZodFirstPartyTypeKind.ZodNull: {
|
@@ -591,7 +615,7 @@ class ZodToJsonSchemaConverter {
|
|
591
615
|
const schema_ = schema;
|
592
616
|
const def2 = schema_._def;
|
593
617
|
const json = { type: "array" };
|
594
|
-
const [itemRequired, itemJson] = this.convert(def2.type, options, lazyDepth, false, false);
|
618
|
+
const [itemRequired, itemJson] = this.convert(def2.type, options, lazyDepth, false, false, structureDepth + 1);
|
595
619
|
json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
|
596
620
|
if (def2.exactLength) {
|
597
621
|
json.maxItems = def2.exactLength.value;
|
@@ -610,7 +634,7 @@ class ZodToJsonSchemaConverter {
|
|
610
634
|
const prefixItems = [];
|
611
635
|
const json = { type: "array" };
|
612
636
|
for (const item of schema_._def.items) {
|
613
|
-
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
|
637
|
+
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false, structureDepth + 1);
|
614
638
|
prefixItems.push(
|
615
639
|
this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy)
|
616
640
|
);
|
@@ -619,7 +643,7 @@ class ZodToJsonSchemaConverter {
|
|
619
643
|
json.prefixItems = prefixItems;
|
620
644
|
}
|
621
645
|
if (schema_._def.rest) {
|
622
|
-
const [itemRequired, itemJson] = this.convert(schema_._def.rest, options, lazyDepth, false, false);
|
646
|
+
const [itemRequired, itemJson] = this.convert(schema_._def.rest, options, lazyDepth, false, false, structureDepth + 1);
|
623
647
|
json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
|
624
648
|
}
|
625
649
|
return [true, json];
|
@@ -630,7 +654,7 @@ class ZodToJsonSchemaConverter {
|
|
630
654
|
const properties = {};
|
631
655
|
const required = [];
|
632
656
|
for (const [key, value] of Object.entries(schema_.shape)) {
|
633
|
-
const [itemRequired, itemJson] = this.convert(value, options, lazyDepth, false, false);
|
657
|
+
const [itemRequired, itemJson] = this.convert(value, options, lazyDepth, false, false, structureDepth + 1);
|
634
658
|
properties[key] = itemJson;
|
635
659
|
if (itemRequired) {
|
636
660
|
required.push(key);
|
@@ -648,7 +672,7 @@ class ZodToJsonSchemaConverter {
|
|
648
672
|
json.additionalProperties = false;
|
649
673
|
}
|
650
674
|
} else {
|
651
|
-
const [_, addJson] = this.convert(schema_._def.catchall, options, lazyDepth, false, false);
|
675
|
+
const [_, addJson] = this.convert(schema_._def.catchall, options, lazyDepth, false, false, structureDepth + 1);
|
652
676
|
json.additionalProperties = addJson;
|
653
677
|
}
|
654
678
|
return [true, json];
|
@@ -656,28 +680,32 @@ class ZodToJsonSchemaConverter {
|
|
656
680
|
case ZodFirstPartyTypeKind.ZodRecord: {
|
657
681
|
const schema_ = schema;
|
658
682
|
const json = { type: "object" };
|
659
|
-
const [__, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false);
|
683
|
+
const [__, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false, structureDepth + 1);
|
660
684
|
if (Object.entries(keyJson).some(([k, v]) => k !== "type" || v !== "string")) {
|
661
685
|
json.propertyNames = keyJson;
|
662
686
|
}
|
663
|
-
const [_, itemJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false);
|
687
|
+
const [_, itemJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false, structureDepth + 1);
|
664
688
|
json.additionalProperties = itemJson;
|
665
689
|
return [true, json];
|
666
690
|
}
|
667
691
|
case ZodFirstPartyTypeKind.ZodSet: {
|
668
692
|
const schema_ = schema;
|
669
|
-
const json = {
|
670
|
-
|
693
|
+
const json = {
|
694
|
+
"type": "array",
|
695
|
+
"uniqueItems": true,
|
696
|
+
"x-native-type": JsonSchemaXNativeType.Set
|
697
|
+
};
|
698
|
+
const [itemRequired, itemJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false, structureDepth + 1);
|
671
699
|
json.items = this.#toArrayItemJsonSchema(itemRequired, itemJson, options.strategy);
|
672
700
|
return [true, json];
|
673
701
|
}
|
674
702
|
case ZodFirstPartyTypeKind.ZodMap: {
|
675
703
|
const schema_ = schema;
|
676
|
-
const [keyRequired, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false);
|
677
|
-
const [valueRequired, valueJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false);
|
678
|
-
|
679
|
-
type: "array",
|
680
|
-
items: {
|
704
|
+
const [keyRequired, keyJson] = this.convert(schema_._def.keyType, options, lazyDepth, false, false, structureDepth + 1);
|
705
|
+
const [valueRequired, valueJson] = this.convert(schema_._def.valueType, options, lazyDepth, false, false, structureDepth + 1);
|
706
|
+
const json = {
|
707
|
+
"type": "array",
|
708
|
+
"items": {
|
681
709
|
type: "array",
|
682
710
|
prefixItems: [
|
683
711
|
this.#toArrayItemJsonSchema(keyRequired, keyJson, options.strategy),
|
@@ -685,8 +713,10 @@ class ZodToJsonSchemaConverter {
|
|
685
713
|
],
|
686
714
|
maxItems: 2,
|
687
715
|
minItems: 2
|
688
|
-
}
|
689
|
-
|
716
|
+
},
|
717
|
+
"x-native-type": JsonSchemaXNativeType.Map
|
718
|
+
};
|
719
|
+
return [true, json];
|
690
720
|
}
|
691
721
|
case ZodFirstPartyTypeKind.ZodUnion:
|
692
722
|
case ZodFirstPartyTypeKind.ZodDiscriminatedUnion: {
|
@@ -694,7 +724,7 @@ class ZodToJsonSchemaConverter {
|
|
694
724
|
const anyOf = [];
|
695
725
|
let required = true;
|
696
726
|
for (const item of schema_._def.options) {
|
697
|
-
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
|
727
|
+
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false, structureDepth);
|
698
728
|
if (!itemRequired) {
|
699
729
|
required = false;
|
700
730
|
if (itemJson !== this.unsupportedJsonSchema) {
|
@@ -714,7 +744,7 @@ class ZodToJsonSchemaConverter {
|
|
714
744
|
const allOf = [];
|
715
745
|
let required = false;
|
716
746
|
for (const item of [schema_._def.left, schema_._def.right]) {
|
717
|
-
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false);
|
747
|
+
const [itemRequired, itemJson] = this.convert(item, options, lazyDepth, false, false, structureDepth);
|
718
748
|
allOf.push(itemJson);
|
719
749
|
if (itemRequired) {
|
720
750
|
required = true;
|
@@ -723,25 +753,26 @@ class ZodToJsonSchemaConverter {
|
|
723
753
|
return [required, { allOf }];
|
724
754
|
}
|
725
755
|
case ZodFirstPartyTypeKind.ZodLazy: {
|
726
|
-
|
756
|
+
const currentLazyDepth = lazyDepth + 1;
|
757
|
+
if (currentLazyDepth > this.maxLazyDepth) {
|
727
758
|
return [false, this.anyJsonSchema];
|
728
759
|
}
|
729
760
|
const schema_ = schema;
|
730
|
-
return this.convert(schema_._def.getter(), options,
|
761
|
+
return this.convert(schema_._def.getter(), options, currentLazyDepth, false, false, structureDepth);
|
731
762
|
}
|
732
763
|
case ZodFirstPartyTypeKind.ZodOptional: {
|
733
764
|
const schema_ = schema;
|
734
|
-
const [_, inner] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
765
|
+
const [_, inner] = this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
735
766
|
return [false, inner];
|
736
767
|
}
|
737
768
|
case ZodFirstPartyTypeKind.ZodReadonly: {
|
738
769
|
const schema_ = schema;
|
739
|
-
const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
770
|
+
const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
740
771
|
return [required, { ...json, readOnly: true }];
|
741
772
|
}
|
742
773
|
case ZodFirstPartyTypeKind.ZodDefault: {
|
743
774
|
const schema_ = schema;
|
744
|
-
const [_, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
775
|
+
const [_, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
745
776
|
return [false, { default: schema_._def.defaultValue(), ...json }];
|
746
777
|
}
|
747
778
|
case ZodFirstPartyTypeKind.ZodEffects: {
|
@@ -749,15 +780,15 @@ class ZodToJsonSchemaConverter {
|
|
749
780
|
if (schema_._def.effect.type === "transform" && options.strategy === "output") {
|
750
781
|
return [false, this.anyJsonSchema];
|
751
782
|
}
|
752
|
-
return this.convert(schema_._def.schema, options, lazyDepth, false, false);
|
783
|
+
return this.convert(schema_._def.schema, options, lazyDepth, false, false, structureDepth);
|
753
784
|
}
|
754
785
|
case ZodFirstPartyTypeKind.ZodCatch: {
|
755
786
|
const schema_ = schema;
|
756
|
-
return this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
787
|
+
return this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
757
788
|
}
|
758
789
|
case ZodFirstPartyTypeKind.ZodBranded: {
|
759
790
|
const schema_ = schema;
|
760
|
-
return this.convert(schema_._def.type, options, lazyDepth, false, false);
|
791
|
+
return this.convert(schema_._def.type, options, lazyDepth, false, false, structureDepth);
|
761
792
|
}
|
762
793
|
case ZodFirstPartyTypeKind.ZodPipeline: {
|
763
794
|
const schema_ = schema;
|
@@ -766,13 +797,14 @@ class ZodToJsonSchemaConverter {
|
|
766
797
|
options,
|
767
798
|
lazyDepth,
|
768
799
|
false,
|
769
|
-
false
|
800
|
+
false,
|
801
|
+
structureDepth
|
770
802
|
);
|
771
803
|
}
|
772
804
|
case ZodFirstPartyTypeKind.ZodNullable: {
|
773
805
|
const schema_ = schema;
|
774
|
-
const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false);
|
775
|
-
return [required, { anyOf: [{ type: "null" }
|
806
|
+
const [required, json] = this.convert(schema_._def.innerType, options, lazyDepth, false, false, structureDepth);
|
807
|
+
return [required, { anyOf: [json, { type: "null" }] }];
|
776
808
|
}
|
777
809
|
}
|
778
810
|
return [true, this.unsupportedJsonSchema];
|
@@ -791,12 +823,17 @@ class ZodToJsonSchemaConverter {
|
|
791
823
|
}
|
792
824
|
case "regexp": {
|
793
825
|
return {
|
794
|
-
type: "string",
|
795
|
-
pattern: "^\\/(.*)\\/([a-z]*)$"
|
826
|
+
"type": "string",
|
827
|
+
"pattern": "^\\/(.*)\\/([a-z]*)$",
|
828
|
+
"x-native-type": JsonSchemaXNativeType.RegExp
|
796
829
|
};
|
797
830
|
}
|
798
831
|
case "url": {
|
799
|
-
return {
|
832
|
+
return {
|
833
|
+
"type": "string",
|
834
|
+
"format": JSONSchemaFormat.URI,
|
835
|
+
"x-native-type": JsonSchemaXNativeType.Url
|
836
|
+
};
|
800
837
|
}
|
801
838
|
}
|
802
839
|
}
|
package/dist/zod4/index.d.mts
CHANGED
@@ -6,6 +6,9 @@ import { Interceptor } from '@orpc/shared';
|
|
6
6
|
import * as zod_v4_core from 'zod/v4/core';
|
7
7
|
import { $ZodType, $input, $output } from 'zod/v4/core';
|
8
8
|
|
9
|
+
/**
|
10
|
+
* @deprecated Use [Smart Coercion Plugin](https://orpc.unnoq.com/docs/openapi/plugins/smart-coercion) instead.
|
11
|
+
*/
|
9
12
|
declare class experimental_ZodSmartCoercionPlugin<TContext extends Context> implements StandardHandlerPlugin<TContext> {
|
10
13
|
#private;
|
11
14
|
init(options: StandardHandlerOptions<TContext>): void;
|
@@ -13,13 +16,21 @@ declare class experimental_ZodSmartCoercionPlugin<TContext extends Context> impl
|
|
13
16
|
|
14
17
|
interface experimental_ZodToJsonSchemaOptions {
|
15
18
|
/**
|
16
|
-
* Max depth of lazy type
|
19
|
+
* Max depth of lazy type.
|
17
20
|
*
|
18
|
-
* Used anyJsonSchema (`{}`) when
|
21
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
19
22
|
*
|
20
23
|
* @default 2
|
21
24
|
*/
|
22
25
|
maxLazyDepth?: number;
|
26
|
+
/**
|
27
|
+
* Max depth of nested types.
|
28
|
+
*
|
29
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
30
|
+
*
|
31
|
+
* @default 10
|
32
|
+
*/
|
33
|
+
maxStructureDepth?: number;
|
23
34
|
/**
|
24
35
|
* The schema to be used to represent the any | unknown type.
|
25
36
|
*
|
@@ -51,6 +62,7 @@ interface experimental_ZodToJsonSchemaOptions {
|
|
51
62
|
declare class experimental_ZodToJsonSchemaConverter implements ConditionalSchemaConverter {
|
52
63
|
#private;
|
53
64
|
private readonly maxLazyDepth;
|
65
|
+
private readonly maxStructureDepth;
|
54
66
|
private readonly anyJsonSchema;
|
55
67
|
private readonly unsupportedJsonSchema;
|
56
68
|
private readonly undefinedJsonSchema;
|
package/dist/zod4/index.d.ts
CHANGED
@@ -6,6 +6,9 @@ import { Interceptor } from '@orpc/shared';
|
|
6
6
|
import * as zod_v4_core from 'zod/v4/core';
|
7
7
|
import { $ZodType, $input, $output } from 'zod/v4/core';
|
8
8
|
|
9
|
+
/**
|
10
|
+
* @deprecated Use [Smart Coercion Plugin](https://orpc.unnoq.com/docs/openapi/plugins/smart-coercion) instead.
|
11
|
+
*/
|
9
12
|
declare class experimental_ZodSmartCoercionPlugin<TContext extends Context> implements StandardHandlerPlugin<TContext> {
|
10
13
|
#private;
|
11
14
|
init(options: StandardHandlerOptions<TContext>): void;
|
@@ -13,13 +16,21 @@ declare class experimental_ZodSmartCoercionPlugin<TContext extends Context> impl
|
|
13
16
|
|
14
17
|
interface experimental_ZodToJsonSchemaOptions {
|
15
18
|
/**
|
16
|
-
* Max depth of lazy type
|
19
|
+
* Max depth of lazy type.
|
17
20
|
*
|
18
|
-
* Used anyJsonSchema (`{}`) when
|
21
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
19
22
|
*
|
20
23
|
* @default 2
|
21
24
|
*/
|
22
25
|
maxLazyDepth?: number;
|
26
|
+
/**
|
27
|
+
* Max depth of nested types.
|
28
|
+
*
|
29
|
+
* Used anyJsonSchema (`{}`) when exceed max depth
|
30
|
+
*
|
31
|
+
* @default 10
|
32
|
+
*/
|
33
|
+
maxStructureDepth?: number;
|
23
34
|
/**
|
24
35
|
* The schema to be used to represent the any | unknown type.
|
25
36
|
*
|
@@ -51,6 +62,7 @@ interface experimental_ZodToJsonSchemaOptions {
|
|
51
62
|
declare class experimental_ZodToJsonSchemaConverter implements ConditionalSchemaConverter {
|
52
63
|
#private;
|
53
64
|
private readonly maxLazyDepth;
|
65
|
+
private readonly maxStructureDepth;
|
54
66
|
private readonly anyJsonSchema;
|
55
67
|
private readonly unsupportedJsonSchema;
|
56
68
|
private readonly undefinedJsonSchema;
|
package/dist/zod4/index.mjs
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
import { isObject, guard, intercept } from '@orpc/shared';
|
1
|
+
import { isObject, guard, intercept, toArray } from '@orpc/shared';
|
2
|
+
import { JsonSchemaXNativeType } from '@orpc/json-schema';
|
2
3
|
import { JSONSchemaFormat, JSONSchemaContentEncoding } from '@orpc/openapi';
|
3
4
|
import { registry, globalRegistry } from 'zod/v4/core';
|
4
5
|
|
@@ -274,12 +275,14 @@ const experimental_JSON_SCHEMA_OUTPUT_REGISTRY = registry();
|
|
274
275
|
|
275
276
|
class experimental_ZodToJsonSchemaConverter {
|
276
277
|
maxLazyDepth;
|
278
|
+
maxStructureDepth;
|
277
279
|
anyJsonSchema;
|
278
280
|
unsupportedJsonSchema;
|
279
281
|
undefinedJsonSchema;
|
280
282
|
interceptors;
|
281
283
|
constructor(options = {}) {
|
282
284
|
this.maxLazyDepth = options.maxLazyDepth ?? 2;
|
285
|
+
this.maxStructureDepth = options.maxStructureDepth ?? 10;
|
283
286
|
this.anyJsonSchema = options.anyJsonSchema ?? {};
|
284
287
|
this.unsupportedJsonSchema = options.unsupportedJsonSchema ?? { not: {} };
|
285
288
|
this.undefinedJsonSchema = options.undefinedJsonSchema ?? { not: {} };
|
@@ -289,17 +292,28 @@ class experimental_ZodToJsonSchemaConverter {
|
|
289
292
|
return schema !== void 0 && schema["~standard"].vendor === "zod";
|
290
293
|
}
|
291
294
|
convert(schema, options) {
|
292
|
-
return this.#convert(schema, options, 0);
|
295
|
+
return this.#convert(schema, options, 0, 0);
|
293
296
|
}
|
294
|
-
#convert(schema, options, lazyDepth, isHandledCustomJSONSchema = false) {
|
297
|
+
#convert(schema, options, lazyDepth, structureDepth, isHandledCustomJSONSchema = false) {
|
295
298
|
return intercept(
|
296
299
|
this.interceptors,
|
297
300
|
{ schema, options, lazyDepth, isHandledCustomJSONSchema },
|
298
301
|
({ schema: schema2, options: options2, lazyDepth: lazyDepth2, isHandledCustomJSONSchema: isHandledCustomJSONSchema2 }) => {
|
302
|
+
if (structureDepth > this.maxStructureDepth) {
|
303
|
+
return [false, this.anyJsonSchema];
|
304
|
+
}
|
305
|
+
if (!options2.minStructureDepthForRef || options2.minStructureDepthForRef <= structureDepth) {
|
306
|
+
const components = toArray(options2.components);
|
307
|
+
for (const component of components) {
|
308
|
+
if (component.schema === schema2 && component.allowedStrategies.includes(options2.strategy)) {
|
309
|
+
return [component.required, { $ref: component.ref }];
|
310
|
+
}
|
311
|
+
}
|
312
|
+
}
|
299
313
|
if (!isHandledCustomJSONSchema2) {
|
300
314
|
const customJSONSchema = this.#getCustomJsonSchema(schema2, options2);
|
301
315
|
if (customJSONSchema) {
|
302
|
-
const [required, json] = this.#convert(schema2, options2, lazyDepth2, true);
|
316
|
+
const [required, json] = this.#convert(schema2, options2, lazyDepth2, structureDepth, true);
|
303
317
|
return [required, { ...json, ...customJSONSchema }];
|
304
318
|
}
|
305
319
|
}
|
@@ -363,10 +377,18 @@ class experimental_ZodToJsonSchemaConverter {
|
|
363
377
|
return [true, { type: "boolean" }];
|
364
378
|
}
|
365
379
|
case "bigint": {
|
366
|
-
return [true, {
|
380
|
+
return [true, {
|
381
|
+
"type": "string",
|
382
|
+
"pattern": "^-?[0-9]+$",
|
383
|
+
"x-native-type": JsonSchemaXNativeType.BigInt
|
384
|
+
}];
|
367
385
|
}
|
368
386
|
case "date": {
|
369
|
-
return [true, {
|
387
|
+
return [true, {
|
388
|
+
"type": "string",
|
389
|
+
"format": JSONSchemaFormat.DateTime,
|
390
|
+
"x-native-type": JsonSchemaXNativeType.Date
|
391
|
+
}];
|
370
392
|
}
|
371
393
|
case "null": {
|
372
394
|
return [true, { type: "null" }];
|
@@ -394,14 +416,14 @@ class experimental_ZodToJsonSchemaConverter {
|
|
394
416
|
if (typeof maximum === "number") {
|
395
417
|
json.maxItems = maximum;
|
396
418
|
}
|
397
|
-
json.items = this.#handleArrayItemJsonSchema(this.#convert(array._zod.def.element, options2, lazyDepth2), options2);
|
419
|
+
json.items = this.#handleArrayItemJsonSchema(this.#convert(array._zod.def.element, options2, lazyDepth2, structureDepth + 1), options2);
|
398
420
|
return [true, json];
|
399
421
|
}
|
400
422
|
case "object": {
|
401
423
|
const object = schema2;
|
402
424
|
const json = { type: "object" };
|
403
425
|
for (const [key, value] of Object.entries(object._zod.def.shape)) {
|
404
|
-
const [itemRequired, itemJson] = this.#convert(value, options2, lazyDepth2);
|
426
|
+
const [itemRequired, itemJson] = this.#convert(value, options2, lazyDepth2, structureDepth + 1);
|
405
427
|
json.properties ??= {};
|
406
428
|
json.properties[key] = itemJson;
|
407
429
|
if (itemRequired) {
|
@@ -413,7 +435,7 @@ class experimental_ZodToJsonSchemaConverter {
|
|
413
435
|
if (object._zod.def.catchall._zod.def.type === "never") {
|
414
436
|
json.additionalProperties = false;
|
415
437
|
} else {
|
416
|
-
const [_, addJson] = this.#convert(object._zod.def.catchall, options2, lazyDepth2);
|
438
|
+
const [_, addJson] = this.#convert(object._zod.def.catchall, options2, lazyDepth2, structureDepth + 1);
|
417
439
|
json.additionalProperties = addJson;
|
418
440
|
}
|
419
441
|
}
|
@@ -424,7 +446,7 @@ class experimental_ZodToJsonSchemaConverter {
|
|
424
446
|
const anyOf = [];
|
425
447
|
let required = true;
|
426
448
|
for (const item of union._zod.def.options) {
|
427
|
-
const [itemRequired, itemJson] = this.#convert(item, options2, lazyDepth2);
|
449
|
+
const [itemRequired, itemJson] = this.#convert(item, options2, lazyDepth2, structureDepth);
|
428
450
|
if (!itemRequired) {
|
429
451
|
required = false;
|
430
452
|
}
|
@@ -445,7 +467,7 @@ class experimental_ZodToJsonSchemaConverter {
|
|
445
467
|
const json = { allOf: [] };
|
446
468
|
let required = false;
|
447
469
|
for (const item of [intersection._zod.def.left, intersection._zod.def.right]) {
|
448
|
-
const [itemRequired, itemJson] = this.#convert(item, options2, lazyDepth2);
|
470
|
+
const [itemRequired, itemJson] = this.#convert(item, options2, lazyDepth2, structureDepth);
|
449
471
|
json.allOf.push(itemJson);
|
450
472
|
if (itemRequired) {
|
451
473
|
required = true;
|
@@ -457,10 +479,10 @@ class experimental_ZodToJsonSchemaConverter {
|
|
457
479
|
const tuple = schema2;
|
458
480
|
const json = { type: "array", prefixItems: [] };
|
459
481
|
for (const item of tuple._zod.def.items) {
|
460
|
-
json.prefixItems.push(this.#handleArrayItemJsonSchema(this.#convert(item, options2, lazyDepth2), options2));
|
482
|
+
json.prefixItems.push(this.#handleArrayItemJsonSchema(this.#convert(item, options2, lazyDepth2, structureDepth + 1), options2));
|
461
483
|
}
|
462
484
|
if (tuple._zod.def.rest) {
|
463
|
-
json.items = this.#handleArrayItemJsonSchema(this.#convert(tuple._zod.def.rest, options2, lazyDepth2), options2);
|
485
|
+
json.items = this.#handleArrayItemJsonSchema(this.#convert(tuple._zod.def.rest, options2, lazyDepth2, structureDepth + 1), options2);
|
464
486
|
}
|
465
487
|
const { minimum, maximum } = tuple._zod.bag;
|
466
488
|
if (typeof minimum === "number") {
|
@@ -474,31 +496,33 @@ class experimental_ZodToJsonSchemaConverter {
|
|
474
496
|
case "record": {
|
475
497
|
const record = schema2;
|
476
498
|
const json = { type: "object" };
|
477
|
-
json.propertyNames = this.#convert(record._zod.def.keyType, options2, lazyDepth2)[1];
|
478
|
-
json.additionalProperties = this.#convert(record._zod.def.valueType, options2, lazyDepth2)[1];
|
499
|
+
json.propertyNames = this.#convert(record._zod.def.keyType, options2, lazyDepth2, structureDepth + 1)[1];
|
500
|
+
json.additionalProperties = this.#convert(record._zod.def.valueType, options2, lazyDepth2, structureDepth + 1)[1];
|
479
501
|
return [true, json];
|
480
502
|
}
|
481
503
|
case "map": {
|
482
504
|
const map = schema2;
|
483
505
|
return [true, {
|
484
|
-
type: "array",
|
485
|
-
items: {
|
506
|
+
"type": "array",
|
507
|
+
"items": {
|
486
508
|
type: "array",
|
487
509
|
prefixItems: [
|
488
|
-
this.#handleArrayItemJsonSchema(this.#convert(map._zod.def.keyType, options2, lazyDepth2), options2),
|
489
|
-
this.#handleArrayItemJsonSchema(this.#convert(map._zod.def.valueType, options2, lazyDepth2), options2)
|
510
|
+
this.#handleArrayItemJsonSchema(this.#convert(map._zod.def.keyType, options2, lazyDepth2, structureDepth + 1), options2),
|
511
|
+
this.#handleArrayItemJsonSchema(this.#convert(map._zod.def.valueType, options2, lazyDepth2, structureDepth + 1), options2)
|
490
512
|
],
|
491
513
|
maxItems: 2,
|
492
514
|
minItems: 2
|
493
|
-
}
|
515
|
+
},
|
516
|
+
"x-native-type": JsonSchemaXNativeType.Map
|
494
517
|
}];
|
495
518
|
}
|
496
519
|
case "set": {
|
497
520
|
const set = schema2;
|
498
521
|
return [true, {
|
499
|
-
type: "array",
|
500
|
-
uniqueItems: true,
|
501
|
-
items: this.#handleArrayItemJsonSchema(this.#convert(set._zod.def.valueType, options2, lazyDepth2), options2)
|
522
|
+
"type": "array",
|
523
|
+
"uniqueItems": true,
|
524
|
+
"items": this.#handleArrayItemJsonSchema(this.#convert(set._zod.def.valueType, options2, lazyDepth2, structureDepth + 1), options2),
|
525
|
+
"x-native-type": JsonSchemaXNativeType.Set
|
502
526
|
}];
|
503
527
|
}
|
504
528
|
case "enum": {
|
@@ -538,12 +562,12 @@ class experimental_ZodToJsonSchemaConverter {
|
|
538
562
|
}
|
539
563
|
case "nullable": {
|
540
564
|
const nullable = schema2;
|
541
|
-
const [required, json] = this.#convert(nullable._zod.def.innerType, options2, lazyDepth2);
|
565
|
+
const [required, json] = this.#convert(nullable._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
542
566
|
return [required, { anyOf: [json, { type: "null" }] }];
|
543
567
|
}
|
544
568
|
case "nonoptional": {
|
545
569
|
const nonoptional = schema2;
|
546
|
-
const [, json] = this.#convert(nonoptional._zod.def.innerType, options2, lazyDepth2);
|
570
|
+
const [, json] = this.#convert(nonoptional._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
547
571
|
return [true, json];
|
548
572
|
}
|
549
573
|
case "success": {
|
@@ -552,7 +576,7 @@ class experimental_ZodToJsonSchemaConverter {
|
|
552
576
|
case "default":
|
553
577
|
case "prefault": {
|
554
578
|
const default_ = schema2;
|
555
|
-
const [, json] = this.#convert(default_._zod.def.innerType, options2, lazyDepth2);
|
579
|
+
const [, json] = this.#convert(default_._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
556
580
|
return [false, {
|
557
581
|
...json,
|
558
582
|
default: default_._zod.def.defaultValue
|
@@ -560,18 +584,18 @@ class experimental_ZodToJsonSchemaConverter {
|
|
560
584
|
}
|
561
585
|
case "catch": {
|
562
586
|
const catch_ = schema2;
|
563
|
-
return this.#convert(catch_._zod.def.innerType, options2, lazyDepth2);
|
587
|
+
return this.#convert(catch_._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
564
588
|
}
|
565
589
|
case "nan": {
|
566
590
|
return [true, options2.strategy === "input" ? this.unsupportedJsonSchema : { type: "null" }];
|
567
591
|
}
|
568
592
|
case "pipe": {
|
569
593
|
const pipe = schema2;
|
570
|
-
return this.#convert(options2.strategy === "input" ? pipe._zod.def.in : pipe._zod.def.out, options2, lazyDepth2);
|
594
|
+
return this.#convert(options2.strategy === "input" ? pipe._zod.def.in : pipe._zod.def.out, options2, lazyDepth2, structureDepth);
|
571
595
|
}
|
572
596
|
case "readonly": {
|
573
597
|
const readonly_ = schema2;
|
574
|
-
const [required, json] = this.#convert(readonly_._zod.def.innerType, options2, lazyDepth2);
|
598
|
+
const [required, json] = this.#convert(readonly_._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
575
599
|
return [required, { ...json, readOnly: true }];
|
576
600
|
}
|
577
601
|
case "template_literal": {
|
@@ -583,15 +607,16 @@ class experimental_ZodToJsonSchemaConverter {
|
|
583
607
|
}
|
584
608
|
case "optional": {
|
585
609
|
const optional = schema2;
|
586
|
-
const [, json] = this.#convert(optional._zod.def.innerType, options2, lazyDepth2);
|
610
|
+
const [, json] = this.#convert(optional._zod.def.innerType, options2, lazyDepth2, structureDepth);
|
587
611
|
return [false, json];
|
588
612
|
}
|
589
613
|
case "lazy": {
|
590
614
|
const lazy = schema2;
|
591
|
-
|
615
|
+
const currentLazyDepth = lazyDepth2 + 1;
|
616
|
+
if (currentLazyDepth > this.maxLazyDepth) {
|
592
617
|
return [false, this.anyJsonSchema];
|
593
618
|
}
|
594
|
-
return this.#convert(lazy._zod.def.getter(), options2,
|
619
|
+
return this.#convert(lazy._zod.def.getter(), options2, currentLazyDepth, structureDepth);
|
595
620
|
}
|
596
621
|
default: {
|
597
622
|
schema2._zod.def.type;
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@orpc/zod",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.0.0-next.
|
4
|
+
"version": "0.0.0-next.de7ca70",
|
5
5
|
"license": "MIT",
|
6
6
|
"homepage": "https://orpc.unnoq.com",
|
7
7
|
"repository": {
|
@@ -30,18 +30,19 @@
|
|
30
30
|
],
|
31
31
|
"peerDependencies": {
|
32
32
|
"zod": ">=3.24.2",
|
33
|
-
"@orpc/
|
34
|
-
"@orpc/
|
33
|
+
"@orpc/contract": "0.0.0-next.de7ca70",
|
34
|
+
"@orpc/server": "0.0.0-next.de7ca70"
|
35
35
|
},
|
36
36
|
"dependencies": {
|
37
37
|
"escape-string-regexp": "^5.0.0",
|
38
38
|
"wildcard-match": "^5.1.3",
|
39
|
-
"@orpc/
|
40
|
-
"@orpc/shared": "0.0.0-next.
|
39
|
+
"@orpc/json-schema": "0.0.0-next.de7ca70",
|
40
|
+
"@orpc/shared": "0.0.0-next.de7ca70",
|
41
|
+
"@orpc/openapi": "0.0.0-next.de7ca70"
|
41
42
|
},
|
42
43
|
"devDependencies": {
|
43
|
-
"zod": "^3.25.
|
44
|
-
"zod-to-json-schema": "^3.24.
|
44
|
+
"zod": "^3.25.76",
|
45
|
+
"zod-to-json-schema": "^3.24.6"
|
45
46
|
},
|
46
47
|
"scripts": {
|
47
48
|
"build": "unbuild",
|