agent-relay 6.0.3 → 6.0.5

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 (157) hide show
  1. package/dist/index.cjs +1395 -674
  2. package/node_modules/@relaycast/sdk/node_modules/zod/README.md +1 -1
  3. package/node_modules/@relaycast/sdk/node_modules/zod/locales/package.json +2 -1
  4. package/node_modules/@relaycast/sdk/node_modules/zod/mini/package.json +2 -1
  5. package/node_modules/@relaycast/sdk/node_modules/zod/package.json +1 -1
  6. package/node_modules/@relaycast/sdk/node_modules/zod/src/v3/tests/all-errors.test.ts +3 -3
  7. package/node_modules/@relaycast/sdk/node_modules/zod/src/v3/tests/object.test.ts +5 -5
  8. package/node_modules/@relaycast/sdk/node_modules/zod/src/v3/tests/partials.test.ts +3 -3
  9. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/errors.ts +2 -2
  10. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/external.ts +1 -0
  11. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/from-json-schema.ts +39 -23
  12. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/parse.ts +6 -6
  13. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/schemas.ts +389 -148
  14. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/catch.test.ts +4 -2
  15. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/codec.test.ts +142 -1
  16. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/continuability.test.ts +1 -1
  17. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/datetime.test.ts +1 -1
  18. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/default.test.ts +44 -0
  19. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/detached-methods.test.ts +197 -0
  20. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/discriminated-unions.test.ts +31 -1
  21. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/error-utils.test.ts +214 -2
  22. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/from-json-schema.test.ts +161 -0
  23. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/function.test.ts +6 -6
  24. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/global-config.test.ts +39 -0
  25. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/index.test.ts +2 -2
  26. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/jitless-allows-eval.test.ts +46 -0
  27. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/locales_ka.test.ts +29 -0
  28. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/locales_ro.test.ts +24 -0
  29. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/number.test.ts +55 -0
  30. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/object.test.ts +83 -6
  31. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/optional.test.ts +114 -4
  32. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/partial.test.ts +28 -2
  33. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/prefault.test.ts +1 -1
  34. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/record.test.ts +85 -0
  35. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/recursive-types.test.ts +49 -0
  36. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/refine.test.ts +63 -0
  37. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/string.test.ts +50 -1
  38. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/template-literal.test.ts +4 -4
  39. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/to-json-schema.test.ts +128 -14
  40. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/transform.test.ts +17 -0
  41. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/tuple.test.ts +315 -2
  42. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/classic/tests/union.test.ts +54 -0
  43. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/api.ts +25 -2
  44. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/checks.ts +1 -1
  45. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/core.ts +17 -2
  46. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/errors.ts +31 -24
  47. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/json-schema-processors.ts +15 -17
  48. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/parse.ts +7 -7
  49. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/regexes.ts +8 -1
  50. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/schemas.ts +218 -66
  51. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/tests/locales/el.test.ts +215 -0
  52. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/tests/locales/fr.test.ts +72 -0
  53. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/tests/locales/hr.test.ts +163 -0
  54. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/tests/locales/uz.test.ts +22 -0
  55. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/tests/record-constructor.test.ts +58 -0
  56. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/to-json-schema.ts +9 -1
  57. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/util.ts +52 -35
  58. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/core/versions.ts +2 -2
  59. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/el.ts +121 -0
  60. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/en.ts +4 -0
  61. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/fr.ts +24 -8
  62. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/hr.ts +131 -0
  63. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/index.ts +3 -0
  64. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/it.ts +1 -1
  65. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/ka.ts +8 -8
  66. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/ro.ts +129 -0
  67. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/locales/uz.ts +1 -0
  68. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/mini/external.ts +1 -0
  69. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/mini/schemas.ts +55 -24
  70. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/mini/tests/codec.test.ts +19 -0
  71. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/mini/tests/index.test.ts +27 -2
  72. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/mini/tests/object.test.ts +9 -9
  73. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/mini/tests/recursive-types.test.ts +51 -1
  74. package/node_modules/@relaycast/sdk/node_modules/zod/src/v4/mini/tests/string.test.ts +5 -0
  75. package/node_modules/@relaycast/sdk/node_modules/zod/v3/package.json +2 -1
  76. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/errors.js +2 -2
  77. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/external.d.cts +1 -0
  78. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/external.d.ts +1 -0
  79. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/from-json-schema.cjs +31 -16
  80. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/from-json-schema.js +31 -16
  81. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/package.json +2 -1
  82. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/schemas.cjs +346 -117
  83. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/schemas.d.cts +34 -12
  84. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/schemas.d.ts +34 -12
  85. package/node_modules/@relaycast/sdk/node_modules/zod/v4/classic/schemas.js +345 -117
  86. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/api.cjs +7 -2
  87. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/api.d.cts +20 -1
  88. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/api.d.ts +20 -1
  89. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/api.js +7 -2
  90. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/checks.d.cts +1 -1
  91. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/checks.d.ts +1 -1
  92. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/core.cjs +3 -1
  93. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/core.js +4 -2
  94. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/errors.cjs +26 -23
  95. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/errors.d.cts +1 -0
  96. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/errors.d.ts +1 -0
  97. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/errors.js +26 -23
  98. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/json-schema-processors.cjs +14 -19
  99. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/json-schema-processors.js +14 -19
  100. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/package.json +2 -1
  101. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/parse.cjs +7 -7
  102. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/parse.js +7 -7
  103. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/regexes.cjs +9 -3
  104. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/regexes.d.cts +6 -0
  105. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/regexes.d.ts +6 -0
  106. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/regexes.js +7 -1
  107. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/schemas.cjs +196 -59
  108. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/schemas.d.cts +21 -1
  109. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/schemas.d.ts +21 -1
  110. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/schemas.js +196 -59
  111. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/to-json-schema.cjs +10 -1
  112. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/to-json-schema.js +10 -1
  113. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/util.cjs +54 -30
  114. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/util.d.cts +1 -0
  115. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/util.d.ts +1 -0
  116. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/util.js +55 -32
  117. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/versions.cjs +2 -2
  118. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/versions.d.cts +1 -1
  119. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/versions.d.ts +1 -1
  120. package/node_modules/@relaycast/sdk/node_modules/zod/v4/core/versions.js +2 -2
  121. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/el.cjs +136 -0
  122. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/el.d.cts +5 -0
  123. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/el.d.ts +4 -0
  124. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/el.js +109 -0
  125. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/en.cjs +4 -0
  126. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/en.js +4 -0
  127. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/fr.cjs +24 -7
  128. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/fr.js +24 -7
  129. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/hr.cjs +149 -0
  130. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/hr.d.cts +5 -0
  131. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/hr.d.ts +4 -0
  132. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/hr.js +122 -0
  133. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/index.cjs +8 -1
  134. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/index.d.cts +3 -0
  135. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/index.d.ts +3 -0
  136. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/index.js +3 -0
  137. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/it.cjs +1 -1
  138. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/it.js +1 -1
  139. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/ka.cjs +8 -8
  140. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/ka.js +8 -8
  141. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/package.json +2 -1
  142. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/ro.cjs +146 -0
  143. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/ro.d.cts +5 -0
  144. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/ro.d.ts +4 -0
  145. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/ro.js +119 -0
  146. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/uz.cjs +1 -0
  147. package/node_modules/@relaycast/sdk/node_modules/zod/v4/locales/uz.js +1 -0
  148. package/node_modules/@relaycast/sdk/node_modules/zod/v4/mini/external.d.cts +1 -0
  149. package/node_modules/@relaycast/sdk/node_modules/zod/v4/mini/external.d.ts +1 -0
  150. package/node_modules/@relaycast/sdk/node_modules/zod/v4/mini/package.json +2 -1
  151. package/node_modules/@relaycast/sdk/node_modules/zod/v4/mini/schemas.cjs +41 -4
  152. package/node_modules/@relaycast/sdk/node_modules/zod/v4/mini/schemas.d.cts +27 -9
  153. package/node_modules/@relaycast/sdk/node_modules/zod/v4/mini/schemas.d.ts +27 -9
  154. package/node_modules/@relaycast/sdk/node_modules/zod/v4/mini/schemas.js +40 -4
  155. package/node_modules/@relaycast/sdk/node_modules/zod/v4/package.json +2 -1
  156. package/node_modules/@relaycast/sdk/node_modules/zod/v4-mini/package.json +2 -1
  157. package/package.json +9 -9
@@ -212,7 +212,7 @@ describe("toJSONSchema", () => {
212
212
  {
213
213
  "$schema": "https://json-schema.org/draft/2020-12/schema",
214
214
  "format": "cuid",
215
- "pattern": "^[cC][^\\s-]{8,}$",
215
+ "pattern": "^[cC][0-9a-z]{6,}$",
216
216
  "type": "string",
217
217
  }
218
218
  `);
@@ -647,6 +647,47 @@ describe("toJSONSchema", () => {
647
647
  `);
648
648
  });
649
649
 
650
+ test("number constraints intersection draft-04", () => {
651
+ // When both minimum (from .int()) and exclusiveMinimum (from .positive()) exist,
652
+ // the more restrictive constraint should be used
653
+ expect(z.toJSONSchema(z.number().int().positive().lte(65535), { target: "draft-04" })).toMatchInlineSnapshot(`
654
+ {
655
+ "$schema": "http://json-schema.org/draft-04/schema#",
656
+ "exclusiveMinimum": true,
657
+ "maximum": 65535,
658
+ "minimum": 0,
659
+ "type": "integer",
660
+ }
661
+ `);
662
+ // Same for openapi-3.0
663
+ expect(z.toJSONSchema(z.number().int().positive().lte(65535), { target: "openapi-3.0" })).toMatchInlineSnapshot(`
664
+ {
665
+ "exclusiveMinimum": true,
666
+ "maximum": 65535,
667
+ "minimum": 0,
668
+ "type": "integer",
669
+ }
670
+ `);
671
+ // When inclusive minimum is more restrictive than exclusive minimum
672
+ expect(z.toJSONSchema(z.number().gt(3).gte(10), { target: "draft-04" })).toMatchInlineSnapshot(`
673
+ {
674
+ "$schema": "http://json-schema.org/draft-04/schema#",
675
+ "minimum": 10,
676
+ "type": "number",
677
+ }
678
+ `);
679
+ // Same logic for maximum constraints
680
+ expect(z.toJSONSchema(z.number().int().negative(), { target: "draft-04" })).toMatchInlineSnapshot(`
681
+ {
682
+ "$schema": "http://json-schema.org/draft-04/schema#",
683
+ "exclusiveMaximum": true,
684
+ "maximum": 0,
685
+ "minimum": -9007199254740991,
686
+ "type": "integer",
687
+ }
688
+ `);
689
+ });
690
+
650
691
  test("target normalization draft-04 and draft-07", () => {
651
692
  // Test that both old (draft-4, draft-7) and new (draft-04, draft-07) target formats work
652
693
  // Test draft-04 / draft-4
@@ -1219,11 +1260,9 @@ describe("toJSONSchema", () => {
1219
1260
  },
1220
1261
  "definitions": {
1221
1262
  "primary": {
1222
- "id": "primary",
1223
1263
  "type": "string",
1224
1264
  },
1225
1265
  "rest": {
1226
- "id": "rest",
1227
1266
  "type": "number",
1228
1267
  },
1229
1268
  },
@@ -2014,11 +2053,9 @@ test("extract schemas with id", () => {
2014
2053
  {
2015
2054
  "$defs": {
2016
2055
  "age": {
2017
- "id": "age",
2018
2056
  "type": "number",
2019
2057
  },
2020
2058
  "name": {
2021
- "id": "name",
2022
2059
  "type": "string",
2023
2060
  },
2024
2061
  },
@@ -2106,7 +2143,6 @@ test("describe with id", () => {
2106
2143
  {
2107
2144
  "$defs": {
2108
2145
  "jobId": {
2109
- "id": "jobId",
2110
2146
  "type": "string",
2111
2147
  },
2112
2148
  },
@@ -2131,6 +2167,45 @@ test("describe with id", () => {
2131
2167
  `);
2132
2168
  });
2133
2169
 
2170
+ test("id is stripped from $defs entries (draft-2020-12)", () => {
2171
+ // The `id` in `.meta()` is a registration tag — it determines the $defs key
2172
+ // but should not leak into the definition body, where it is redundant.
2173
+ const inner = z.string().meta({ id: "Inner" });
2174
+ const result = z.toJSONSchema(z.object({ a: inner, b: inner }));
2175
+ expect(result.$defs?.Inner).toEqual({ type: "string" });
2176
+ expect((result.$defs?.Inner as any).id).toBeUndefined();
2177
+ });
2178
+
2179
+ test("id is stripped from definitions entries (draft-04)", () => {
2180
+ // In draft-04, `id` is a reserved keyword that sets a base URI for the
2181
+ // subschema. Leaking Zod's registration tag here is semantically wrong, so
2182
+ // ensure it is stripped.
2183
+ const inner = z.string().meta({ id: "Inner" });
2184
+ const result = z.toJSONSchema(z.object({ a: inner, b: inner }), { target: "draft-04" }) as any;
2185
+ expect(result.definitions?.Inner).toEqual({ type: "string" });
2186
+ expect(result.definitions?.Inner?.id).toBeUndefined();
2187
+ });
2188
+
2189
+ test("id is stripped from root schema", () => {
2190
+ // The registration tag should not appear on the root either.
2191
+ const A = z.object({ name: z.string() }).meta({ id: "A" });
2192
+ const result = z.toJSONSchema(A);
2193
+ expect((result as any).id).toBeUndefined();
2194
+ });
2195
+
2196
+ test("id is observable in override callback", () => {
2197
+ // The strip happens after override callbacks run, so userland override code
2198
+ // can still read `jsonSchema.id` if it wants to.
2199
+ const inner = z.string().meta({ id: "Inner" });
2200
+ const seenIds: Array<string | undefined> = [];
2201
+ z.toJSONSchema(z.object({ a: inner }), {
2202
+ override: ({ jsonSchema }) => {
2203
+ if (jsonSchema.id !== undefined) seenIds.push(jsonSchema.id as string);
2204
+ },
2205
+ });
2206
+ expect(seenIds).toContain("Inner");
2207
+ });
2208
+
2134
2209
  test("describe with id on wrapper", () => {
2135
2210
  // Test that $ref propagation works when processor sets a different ref (readonly -> innerType)
2136
2211
  // but parent was extracted due to having an id
@@ -2146,7 +2221,6 @@ test("describe with id on wrapper", () => {
2146
2221
  {
2147
2222
  "$defs": {
2148
2223
  "roJobId": {
2149
- "id": "roJobId",
2150
2224
  "readOnly": true,
2151
2225
  "type": "string",
2152
2226
  },
@@ -2185,12 +2259,10 @@ test("overwrite id", () => {
2185
2259
  {
2186
2260
  "$defs": {
2187
2261
  "aaa": {
2188
- "id": "aaa",
2189
2262
  "type": "string",
2190
2263
  },
2191
2264
  "bbb": {
2192
2265
  "$ref": "#/$defs/aaa",
2193
- "id": "bbb",
2194
2266
  },
2195
2267
  },
2196
2268
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -2224,12 +2296,10 @@ test("overwrite id", () => {
2224
2296
  {
2225
2297
  "$defs": {
2226
2298
  "aaa": {
2227
- "id": "aaa",
2228
2299
  "type": "string",
2229
2300
  },
2230
2301
  "ccc": {
2231
2302
  "$ref": "#/$defs/aaa",
2232
- "id": "ccc",
2233
2303
  },
2234
2304
  },
2235
2305
  "$schema": "https://json-schema.org/draft/2020-12/schema",
@@ -2351,7 +2421,6 @@ test("top-level readonly", () => {
2351
2421
  "$defs": {
2352
2422
  "B": {
2353
2423
  "additionalProperties": false,
2354
- "id": "B",
2355
2424
  "properties": {
2356
2425
  "a": {
2357
2426
  "$ref": "#",
@@ -2370,7 +2439,6 @@ test("top-level readonly", () => {
2370
2439
  },
2371
2440
  "$schema": "https://json-schema.org/draft/2020-12/schema",
2372
2441
  "additionalProperties": false,
2373
- "id": "A",
2374
2442
  "properties": {
2375
2443
  "b": {
2376
2444
  "$ref": "#/$defs/B",
@@ -2497,7 +2565,6 @@ test("_ref", () => {
2497
2565
  {
2498
2566
  "$defs": {
2499
2567
  "foo": {
2500
- "id": "foo",
2501
2568
  "type": "string",
2502
2569
  },
2503
2570
  },
@@ -2560,6 +2627,38 @@ test("defaults/prefaults", () => {
2560
2627
  `);
2561
2628
  });
2562
2629
 
2630
+ test("falsy prefaults (false, 0, empty string)", () => {
2631
+ // boolean prefault false
2632
+ const a = z.boolean().prefault(false);
2633
+ expect(z.toJSONSchema(a, { io: "input" })).toMatchInlineSnapshot(`
2634
+ {
2635
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
2636
+ "default": false,
2637
+ "type": "boolean",
2638
+ }
2639
+ `);
2640
+
2641
+ // number prefault 0
2642
+ const b = z.number().prefault(0);
2643
+ expect(z.toJSONSchema(b, { io: "input" })).toMatchInlineSnapshot(`
2644
+ {
2645
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
2646
+ "default": 0,
2647
+ "type": "number",
2648
+ }
2649
+ `);
2650
+
2651
+ // string prefault empty string
2652
+ const c = z.string().prefault("");
2653
+ expect(z.toJSONSchema(c, { io: "input" })).toMatchInlineSnapshot(`
2654
+ {
2655
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
2656
+ "default": "",
2657
+ "type": "string",
2658
+ }
2659
+ `);
2660
+ });
2661
+
2563
2662
  test("input type", () => {
2564
2663
  const schema = z.object({
2565
2664
  a: z.string(),
@@ -2988,3 +3087,18 @@ test("cycle detection - mutual recursion", () => {
2988
3087
  Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.]
2989
3088
  `);
2990
3089
  });
3090
+
3091
+ test("recursive lazy with describe does not stack overflow", () => {
3092
+ const NodeSchema: z.ZodType = z.lazy(() =>
3093
+ z
3094
+ .object({
3095
+ value: z.string().describe("node value"),
3096
+ children: z.array(NodeSchema.describe("child node")).optional().describe("child list"),
3097
+ })
3098
+ .describe("tree node")
3099
+ );
3100
+
3101
+ const result = z.toJSONSchema(NodeSchema, { cycles: "ref", reused: "ref" });
3102
+ expect(result).toBeDefined();
3103
+ expect(result.$defs).toBeDefined();
3104
+ });
@@ -359,3 +359,20 @@ test("encode error", () => {
359
359
  `[ZodEncodeError: Encountered unidirectional transform during encode: ZodTransform]`
360
360
  );
361
361
  });
362
+
363
+ test("transform context should have addIssue", () => {
364
+ const schema = z.transform((val, ctx) => {
365
+ ctx.addIssue({
366
+ code: "custom",
367
+ message: "Not valid",
368
+ });
369
+ return val;
370
+ });
371
+
372
+ const result = schema.safeParse("test");
373
+
374
+ expect(result.success).toBe(false);
375
+ if (!result.success) {
376
+ expect(result.error.issues[0].message).toBe("Not valid");
377
+ }
378
+ });
@@ -107,7 +107,9 @@ test("async validation", async () => {
107
107
 
108
108
  test("tuple with optional elements", () => {
109
109
  const myTuple = z.tuple([z.string(), z.number().optional(), z.string().optional()]).rest(z.boolean());
110
- expectTypeOf<typeof myTuple._output>().toEqualTypeOf<[string, number?, string?, ...boolean[]]>();
110
+ expectTypeOf<typeof myTuple._output>().toEqualTypeOf<
111
+ [string, (number | undefined)?, (string | undefined)?, ...boolean[]]
112
+ >();
111
113
 
112
114
  const goodData = [["asdf"], ["asdf", 1234], ["asdf", 1234, "asdf"], ["asdf", 1234, "asdf", true, false, true]];
113
115
  for (const data of goodData) {
@@ -149,7 +151,9 @@ test("tuple with optional elements followed by required", () => {
149
151
 
150
152
  test("tuple with all optional elements", () => {
151
153
  const allOptionalTuple = z.tuple([z.string().optional(), z.number().optional(), z.boolean().optional()]);
152
- expectTypeOf<typeof allOptionalTuple._output>().toEqualTypeOf<[string?, number?, boolean?]>();
154
+ expectTypeOf<typeof allOptionalTuple._output>().toEqualTypeOf<
155
+ [(string | undefined)?, (number | undefined)?, (boolean | undefined)?]
156
+ >();
153
157
 
154
158
  // Empty array should be valid (all items optional)
155
159
  expect(allOptionalTuple.parse([])).toEqual([]);
@@ -165,6 +169,227 @@ test("tuple with all optional elements", () => {
165
169
  expect(() => allOptionalTuple.parse(["hello", 42, true, "extra"])).toThrow();
166
170
  });
167
171
 
172
+ test("tuple fills defaults for missing trailing elements", () => {
173
+ // Issue #5229: trailing `.default()`/`.prefault()` elements should be
174
+ // filled in when the input array is shorter than the tuple.
175
+ const t = z.tuple([z.string(), z.string().default("bravo")]);
176
+ expectTypeOf<typeof t._output>().toEqualTypeOf<[string, string]>();
177
+ expectTypeOf<typeof t._input>().toEqualTypeOf<[string, (string | undefined)?]>();
178
+
179
+ expect(t.parse(["alpha", "charlie"])).toEqual(["alpha", "charlie"]);
180
+ expect(t.parse(["alpha"])).toEqual(["alpha", "bravo"]);
181
+
182
+ // Multiple trailing defaults
183
+ const multi = z.tuple([z.string(), z.number().default(42), z.boolean().default(true)]);
184
+ expect(multi.parse(["hello"])).toEqual(["hello", 42, true]);
185
+ expect(multi.parse(["hello", 100])).toEqual(["hello", 100, true]);
186
+ expect(multi.parse(["hello", 100, false])).toEqual(["hello", 100, false]);
187
+
188
+ // Prefault parity
189
+ expect(z.tuple([z.string(), z.string().prefault("delta")]).parse(["alpha"])).toEqual(["alpha", "delta"]);
190
+
191
+ // Defaults wrapped in modifiers: `optout` propagates through these, so the
192
+ // fix is not type-name specific.
193
+ expect(z.tuple([z.string(), z.string().default("x").nullable()]).parse(["alpha"])).toEqual(["alpha", "x"]);
194
+ expect(z.tuple([z.string(), z.string().default("x").readonly()]).parse(["alpha"])).toEqual(["alpha", "x"]);
195
+ expect(z.tuple([z.string(), z.string().default("x").catch("y")]).parse(["alpha"])).toEqual(["alpha", "x"]);
196
+ expect(z.tuple([z.string(), z.string().default("x").pipe(z.string())]).parse(["alpha"])).toEqual(["alpha", "x"]);
197
+ });
198
+
199
+ test("tuple fills defaults under async parse", async () => {
200
+ const t = z.tuple([z.string(), z.string().default("zulu")]);
201
+ await expect(t.parseAsync(["alpha"])).resolves.toEqual(["alpha", "zulu"]);
202
+ });
203
+
204
+ test("tuple keeps length-1 array for missing `.optional()` elements", () => {
205
+ // Backwards compat: a trailing `.optional()` element that is omitted from
206
+ // the input must NOT be filled with `undefined` — the result stays length-1.
207
+ // Only schemas that produce a defined value get materialized.
208
+ const t = z.tuple([z.string(), z.string().optional()]);
209
+ const out = t.parse(["alpha"]);
210
+ expect(out).toEqual(["alpha"]);
211
+ expect(out.length).toEqual(1);
212
+
213
+ // `z.undefined()` is NOT a synonym for `.optional()` — its value type is
214
+ // *must be undefined*, so the slot is required input. Omitting it triggers
215
+ // a single `too_small` (no element-level errors, matching v3's abort
216
+ // semantics); passing explicit `undefined` succeeds and is preserved.
217
+ expect(z.tuple([z.string(), z.undefined()]).safeParse(["alpha"]).error!.issues).toMatchInlineSnapshot(`
218
+ [
219
+ {
220
+ "code": "too_small",
221
+ "inclusive": true,
222
+ "message": "Too small: expected array to have >=2 items",
223
+ "minimum": 2,
224
+ "origin": "array",
225
+ "path": [],
226
+ },
227
+ ]
228
+ `);
229
+ expect(z.tuple([z.string(), z.undefined()]).parse(["alpha", undefined])).toHaveLength(2);
230
+
231
+ // `.optional().nullable()` still trims — `.optional()` propagates the
232
+ // optin/optout flags through the nullable wrapper.
233
+ expect(z.tuple([z.string(), z.string().optional().nullable()]).parse(["alpha"])).toHaveLength(1);
234
+
235
+ // Multiple trailing optionals trim the same way — we don't fill the tail
236
+ // with literal `undefined`s.
237
+ const many = z.tuple([z.string(), z.string().optional(), z.string().optional(), z.string().optional()]);
238
+ expect(many.parse(["alpha"])).toEqual(["alpha"]);
239
+ expect(many.parse(["alpha", "beta"])).toEqual(["alpha", "beta"]);
240
+
241
+ // Explicit `undefined` inside `input.length` IS preserved — only slots
242
+ // past the input get trimmed.
243
+ const r = many.parse(["alpha", undefined]);
244
+ expect(r.length).toEqual(2);
245
+ expect(1 in r).toEqual(true);
246
+
247
+ // Trailing optionals after a default that fires are still trimmed.
248
+ expect(
249
+ z.tuple([z.string(), z.string().default("d"), z.string().optional(), z.string().optional()]).parse(["alpha"])
250
+ ).toEqual(["alpha", "d"]);
251
+ });
252
+
253
+ test("tuple result is dense when optional precedes a default", () => {
254
+ // `.optional()` before a `.default()` must produce an explicit `undefined`
255
+ // (not a sparse hole), otherwise `1 in r`, `JSON.stringify`, `Object.keys`,
256
+ // and iteration all behave wrong.
257
+ const t = z.tuple([z.string(), z.string().optional(), z.string().default("z")]);
258
+ const r = t.parse(["alpha"]);
259
+ expect(r).toEqual(["alpha", undefined, "z"]);
260
+ expect(r.length).toEqual(3);
261
+ expect(1 in r).toEqual(true);
262
+ expect(JSON.stringify(r)).toEqual('["alpha",null,"z"]');
263
+
264
+ // Trailing optional after a default is still dropped (no later default
265
+ // forces it to materialize).
266
+ expect(z.tuple([z.string(), z.string().default("d"), z.string().optional()]).parse(["alpha"])).toEqual([
267
+ "alpha",
268
+ "d",
269
+ ]);
270
+
271
+ // Multiple interleaved optional/default — every slot up to the last
272
+ // default must be present and dense.
273
+ const interleaved = z.tuple([
274
+ z.string(),
275
+ z.string().optional(),
276
+ z.string().default("d"),
277
+ z.string().optional(),
278
+ z.string().default("e"),
279
+ ]);
280
+ const out = interleaved.parse(["alpha"]);
281
+ expect(out).toEqual(["alpha", undefined, "d", undefined, "e"]);
282
+ expect(1 in out && 3 in out).toEqual(true);
283
+ });
284
+
285
+ test("tuple truncates absent optional rejections only when the output tail is optional", () => {
286
+ // An absent optional-output slot can only be swallowed when every later
287
+ // output slot is optional too. If a later default would make the output tail
288
+ // required, truncating would violate the tuple's output type.
289
+ const refusesUndefined = z
290
+ .string()
291
+ .optional()
292
+ .refine((s) => s !== undefined, "must not be undefined");
293
+
294
+ const trailingDefault = z.tuple([z.string(), refusesUndefined, z.string().default("d")]);
295
+ const r1 = trailingDefault.safeParse(["alpha"]);
296
+ expect(r1.success).toBe(false);
297
+ expect(r1.error!.issues[0].path).toEqual([1]);
298
+
299
+ // Optional slots BEFORE the rejected one still cannot hide a later required
300
+ // output slot.
301
+ const beforeReject = z.tuple([z.string(), z.string().optional(), refusesUndefined, z.string().default("d")]);
302
+ const r2 = beforeReject.safeParse(["alpha"]);
303
+ expect(r2.success).toBe(false);
304
+ expect(r2.error!.issues[0].path).toEqual([2]);
305
+
306
+ // No default after — truncate still applies, no spurious issue surfaces.
307
+ const noTrailingDefault = z.tuple([z.string(), refusesUndefined]);
308
+ const r3 = noTrailingDefault.safeParse(["alpha"]);
309
+ expect(r3.success).toBe(true);
310
+ expect(r3.data).toEqual(["alpha"]);
311
+ });
312
+
313
+ test("tuple rejects absent optional before required output under async parse", async () => {
314
+ const refusesUndefined = z
315
+ .string()
316
+ .optional()
317
+ .refine(async (s) => s !== undefined, "must not be undefined");
318
+
319
+ const schema = z.tuple([z.string(), refusesUndefined, z.string().default("d")]);
320
+ const r = await schema.safeParseAsync(["alpha"]);
321
+ expect(r.success).toBe(false);
322
+ expect(r.error!.issues[0].path).toEqual([1]);
323
+ });
324
+
325
+ test("tuple rejects absent exact optional before defaulted output", () => {
326
+ const schema = z.tuple([z.string(), z.string().exactOptional(), z.string().default("fallback")]);
327
+ expectTypeOf<typeof schema._output>().toEqualTypeOf<[string, string, string]>();
328
+
329
+ const missingExact = schema.safeParse(["alpha"]);
330
+ expect(missingExact.success).toBe(false);
331
+ expect(missingExact.error!.issues[0].path).toEqual([1]);
332
+
333
+ expect(schema.parse(["alpha", "bravo"])).toEqual(["alpha", "bravo", "fallback"]);
334
+ expect(schema.safeParse(["alpha", undefined]).success).toBe(false);
335
+
336
+ // With no later required output slot, exact optional still behaves like an
337
+ // omitted tuple tail and truncates cleanly.
338
+ expect(z.tuple([z.string(), z.string().exactOptional(), z.string().optional()]).parse(["alpha"])).toEqual(["alpha"]);
339
+ });
340
+
341
+ test("tuple preserves explicit undefined inside input even for optional-out schemas", () => {
342
+ // The trim only runs for slots PAST `input.length`. An explicit `undefined`
343
+ // value supplied by the caller at index < input.length must survive, even
344
+ // when the schema produces undefined as a valid output (e.g.
345
+ // `z.string().or(z.undefined())`, `z.string().optional()`, `z.undefined()`).
346
+ const orUndefined = z.tuple([z.string(), z.string().or(z.undefined())]);
347
+ const r1 = orUndefined.parse(["alpha", undefined]);
348
+ expect(r1.length).toEqual(2);
349
+ expect(r1[1]).toBeUndefined();
350
+ expect(1 in r1).toEqual(true);
351
+ expect(JSON.stringify(r1)).toEqual('["alpha",null]');
352
+
353
+ // Same for `.optional()`.
354
+ const opt = z.tuple([z.string(), z.string().optional()]);
355
+ const r2 = opt.parse(["alpha", undefined]);
356
+ expect(r2.length).toEqual(2);
357
+ expect(1 in r2).toEqual(true);
358
+
359
+ // Same for `z.undefined()` literal.
360
+ const lit = z.tuple([z.string(), z.undefined()]);
361
+ const r3 = lit.parse(["alpha", undefined]);
362
+ expect(r3.length).toEqual(2);
363
+ expect(1 in r3).toEqual(true);
364
+
365
+ // Mid-tuple explicit undefined surrounded by defined values is also kept.
366
+ const mid = z.tuple([z.string(), z.string().or(z.undefined()), z.string()]);
367
+ const r4 = mid.parse(["alpha", undefined, "gamma"]);
368
+ expect(r4).toEqual(["alpha", undefined, "gamma"]);
369
+ expect(r4.length).toEqual(3);
370
+ expect(1 in r4).toEqual(true);
371
+ });
372
+
373
+ test("tuple does NOT break when a required slot fails past input length", () => {
374
+ // A required slot (no `.optional()` chain, so optout !== "optional") past
375
+ // input length must still surface an issue rather than silently swallowing
376
+ // it. Otherwise we'd accept arbitrarily short tuples for required-tail
377
+ // schemas. The precheck collapses this into a single `too_small`.
378
+ const schema = z.tuple([z.string(), z.string()]);
379
+ expect(schema.safeParse(["alpha"]).error!.issues).toMatchInlineSnapshot(`
380
+ [
381
+ {
382
+ "code": "too_small",
383
+ "inclusive": true,
384
+ "message": "Too small: expected array to have >=2 items",
385
+ "minimum": 2,
386
+ "origin": "array",
387
+ "path": [],
388
+ },
389
+ ]
390
+ `);
391
+ });
392
+
168
393
  test("tuple with rest schema", () => {
169
394
  const myTuple = z.tuple([z.string(), z.number()]).rest(z.boolean());
170
395
  expect(myTuple.parse(["asdf", 1234, true, false, true])).toEqual(["asdf", 1234, true, false, true]);
@@ -181,3 +406,91 @@ test("sparse array input", () => {
181
406
  const schema = z.tuple([z.string(), z.number()]);
182
407
  expect(() => schema.parse(new Array(2))).toThrow();
183
408
  });
409
+
410
+ test("under-length tuple emits a single too_small with optStart minimum", () => {
411
+ const allRequired = z.tuple([z.string(), z.string()]);
412
+ expect(allRequired.safeParse(["a"]).error!.issues).toMatchInlineSnapshot(`
413
+ [
414
+ {
415
+ "code": "too_small",
416
+ "inclusive": true,
417
+ "message": "Too small: expected array to have >=2 items",
418
+ "minimum": 2,
419
+ "origin": "array",
420
+ "path": [],
421
+ },
422
+ ]
423
+ `);
424
+ expect(allRequired.safeParse([]).error!.issues).toMatchInlineSnapshot(`
425
+ [
426
+ {
427
+ "code": "too_small",
428
+ "inclusive": true,
429
+ "message": "Too small: expected array to have >=2 items",
430
+ "minimum": 2,
431
+ "origin": "array",
432
+ "path": [],
433
+ },
434
+ ]
435
+ `);
436
+
437
+ const trailingOptional = z.tuple([z.string(), z.number().optional()]);
438
+ expect(trailingOptional.safeParse([]).error!.issues).toMatchInlineSnapshot(`
439
+ [
440
+ {
441
+ "code": "too_small",
442
+ "inclusive": true,
443
+ "message": "Too small: expected array to have >=1 items",
444
+ "minimum": 1,
445
+ "origin": "array",
446
+ "path": [],
447
+ },
448
+ ]
449
+ `);
450
+
451
+ const interiorOptional = z.tuple([z.string(), z.number().optional(), z.string()]);
452
+ expect(interiorOptional.safeParse(["a", 1]).error!.issues).toMatchInlineSnapshot(`
453
+ [
454
+ {
455
+ "code": "too_small",
456
+ "inclusive": true,
457
+ "message": "Too small: expected array to have >=3 items",
458
+ "minimum": 3,
459
+ "origin": "array",
460
+ "path": [],
461
+ },
462
+ ]
463
+ `);
464
+ });
465
+
466
+ test("too_big tuple still surfaces element-wise type errors for present indices", () => {
467
+ const schema = z.tuple([z.string(), z.number()]);
468
+ expect(schema.safeParse([1, "x", "extra"]).error!.issues).toMatchInlineSnapshot(`
469
+ [
470
+ {
471
+ "code": "too_big",
472
+ "inclusive": true,
473
+ "maximum": 2,
474
+ "message": "Too big: expected array to have <=2 items",
475
+ "origin": "array",
476
+ "path": [],
477
+ },
478
+ {
479
+ "code": "invalid_type",
480
+ "expected": "string",
481
+ "message": "Invalid input: expected string, received number",
482
+ "path": [
483
+ 0,
484
+ ],
485
+ },
486
+ {
487
+ "code": "invalid_type",
488
+ "expected": "number",
489
+ "message": "Invalid input: expected number, received string",
490
+ "path": [
491
+ 1,
492
+ ],
493
+ },
494
+ ]
495
+ `);
496
+ });
@@ -217,3 +217,57 @@ test("z.xor() type inference", () => {
217
217
  type Result = z.infer<typeof schema>;
218
218
  expectTypeOf<Result>().toEqualTypeOf<string | number | boolean>();
219
219
  });
220
+
221
+ test("z.union([]) constructs and rejects all input", () => {
222
+ const schema = z.union([]);
223
+ expectTypeOf<z.infer<typeof schema>>().toEqualTypeOf<never>();
224
+ const result = schema.safeParse("anything");
225
+ expect(result.success).toEqual(false);
226
+ if (!result.success) {
227
+ expect(result.error.issues).toMatchInlineSnapshot(`
228
+ [
229
+ {
230
+ "code": "invalid_union",
231
+ "errors": [],
232
+ "message": "Invalid input",
233
+ "path": [],
234
+ },
235
+ ]
236
+ `);
237
+ }
238
+ });
239
+
240
+ test("z.xor([]) constructs and rejects all input", () => {
241
+ const schema = z.xor([]);
242
+ expectTypeOf<z.infer<typeof schema>>().toEqualTypeOf<never>();
243
+ const result = schema.safeParse("anything");
244
+ expect(result.success).toEqual(false);
245
+ if (!result.success) {
246
+ expect(result.error.issues).toMatchInlineSnapshot(`
247
+ [
248
+ {
249
+ "code": "invalid_union",
250
+ "errors": [],
251
+ "message": "Invalid input",
252
+ "path": [],
253
+ },
254
+ ]
255
+ `);
256
+ }
257
+ });
258
+
259
+ test("z.discriminatedUnion with empty options constructs and rejects", () => {
260
+ const schema = z.discriminatedUnion("type", [] as any);
261
+ const nonObject = schema.safeParse("nope");
262
+ expect(nonObject.success).toEqual(false);
263
+ if (!nonObject.success) {
264
+ expect(nonObject.error.issues[0].code).toBe("invalid_type");
265
+ }
266
+ const obj = schema.safeParse({ type: "x" });
267
+ expect(obj.success).toEqual(false);
268
+ if (!obj.success) {
269
+ expect(obj.error.issues[0].code).toBe("invalid_union");
270
+ expect((obj.error.issues[0] as any).errors).toEqual([]);
271
+ expect((obj.error.issues[0] as any).options).toEqual([]);
272
+ }
273
+ });