@oxog/vld 2.0.2 → 2.0.3

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 (48) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/LICENSE +20 -20
  3. package/README.md +2 -2
  4. package/dist/chunks/{bigint-DgsCr2dC.js → bigint-CRS0QVsy.js} +147 -2
  5. package/dist/chunks/bigint-CRS0QVsy.js.map +1 -0
  6. package/dist/chunks/{date-ODue_rtq.js → date-50JV_Mfj.js} +2 -2
  7. package/dist/chunks/{date-ODue_rtq.js.map → date-50JV_Mfj.js.map} +1 -1
  8. package/dist/chunks/{index-CETyGkrv.js → index-DO8CFMxD.js} +4 -4
  9. package/dist/chunks/index-DO8CFMxD.js.map +1 -0
  10. package/dist/chunks/{json-o20GFhTh.js → json-Cp4WO0M9.js} +4 -4
  11. package/dist/chunks/json-Cp4WO0M9.js.map +1 -0
  12. package/dist/chunks/{unknown-SLIH1VCf.js → unknown-Dhzri_T-.js} +2 -2
  13. package/dist/chunks/unknown-Dhzri_T-.js.map +1 -0
  14. package/dist/cjs/index.cjs +777 -1
  15. package/dist/cjs/index.cjs.map +1 -1
  16. package/dist/cjs/locales/index.cjs.map +1 -1
  17. package/dist/cjs/mini.cjs +145 -0
  18. package/dist/cjs/mini.cjs.map +1 -1
  19. package/dist/cli/commands/validate.d.ts.map +1 -1
  20. package/dist/codecs/index.js +3 -3
  21. package/dist/coercion/index.js +2 -2
  22. package/dist/coercion/index.js.map +1 -1
  23. package/dist/index.d.ts +244 -0
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js +550 -11
  26. package/dist/index.js.map +1 -1
  27. package/dist/mini.js +5 -5
  28. package/dist/utils/json-schema.d.ts +67 -0
  29. package/dist/utils/json-schema.d.ts.map +1 -0
  30. package/dist/validators/base.d.ts +79 -0
  31. package/dist/validators/base.d.ts.map +1 -1
  32. package/dist/validators/index.d.ts +3 -2
  33. package/dist/validators/index.d.ts.map +1 -1
  34. package/dist/validators/index.js +514 -4
  35. package/dist/validators/index.js.map +1 -1
  36. package/dist/validators/number.d.ts +30 -0
  37. package/dist/validators/number.d.ts.map +1 -1
  38. package/dist/validators/promise.d.ts +53 -0
  39. package/dist/validators/promise.d.ts.map +1 -0
  40. package/dist/validators/string-formats.d.ts +6 -0
  41. package/dist/validators/string-formats.d.ts.map +1 -1
  42. package/package.json +6 -5
  43. package/dist/chunks/bigint-DgsCr2dC.js.map +0 -1
  44. package/dist/chunks/index-BZqWZvVe.js +0 -426
  45. package/dist/chunks/index-BZqWZvVe.js.map +0 -1
  46. package/dist/chunks/index-CETyGkrv.js.map +0 -1
  47. package/dist/chunks/json-o20GFhTh.js.map +0 -1
  48. package/dist/chunks/unknown-SLIH1VCf.js.map +0 -1
@@ -90,6 +90,16 @@ class VldBase {
90
90
  nullish() {
91
91
  return new VldNullish(this);
92
92
  }
93
+ /**
94
+ * Make this validator exactly optional - allows undefined but not missing
95
+ * Unlike .optional() which treats missing as undefined, exactOptional()
96
+ * requires the key to be present but allows undefined as a value
97
+ * Zod 4 API parity
98
+ * @returns A new exact optional validator
99
+ */
100
+ exactOptional() {
101
+ return new VldExactOptional(this);
102
+ }
93
103
  /**
94
104
  * Pipe the output of this validator into another validator
95
105
  * @param next The next validator to pipe into
@@ -134,6 +144,49 @@ class VldBase {
134
144
  apply(fn) {
135
145
  return fn(this);
136
146
  }
147
+ check(predicate, message) {
148
+ return new VldRefine(this, predicate, message);
149
+ }
150
+ /**
151
+ * Get or set metadata for this schema
152
+ */
153
+ meta(data) {
154
+ if (data === undefined) {
155
+ return undefined;
156
+ }
157
+ return new VldMeta(this, data);
158
+ }
159
+ /**
160
+ * Add a description to this schema
161
+ * Zod 4 API parity - convenience method for .meta({ description: ... })
162
+ * @param description The description to add
163
+ * @returns A new validator with the description
164
+ */
165
+ describe(description) {
166
+ return new VldMeta(this, { description });
167
+ }
168
+ }
169
+ /**
170
+ * Metadata validator - wraps a schema with metadata
171
+ */
172
+ class VldMeta extends VldBase {
173
+ constructor(baseValidator, metadata) {
174
+ super();
175
+ this.baseValidator = baseValidator;
176
+ this.metadata = metadata;
177
+ }
178
+ parse(value) {
179
+ return this.baseValidator.parse(value);
180
+ }
181
+ safeParse(value) {
182
+ return this.baseValidator.safeParse(value);
183
+ }
184
+ /**
185
+ * Get the metadata
186
+ */
187
+ getMeta() {
188
+ return this.metadata;
189
+ }
137
190
  }
138
191
  /**
139
192
  * Readonly validator - marks output as readonly
@@ -349,6 +402,38 @@ class VldOptional extends VldBase {
349
402
  return this.baseValidator;
350
403
  }
351
404
  }
405
+ /**
406
+ * Exact optional validator - allows undefined but requires key presence
407
+ * Unlike Optional which treats missing as undefined, ExactOptional
408
+ * requires the key to be present (not missing from object) but allows undefined
409
+ * Zod 4 API parity
410
+ */
411
+ class VldExactOptional extends VldBase {
412
+ constructor(baseValidator) {
413
+ super();
414
+ this.baseValidator = baseValidator;
415
+ }
416
+ static create(baseValidator) {
417
+ return new VldExactOptional(baseValidator);
418
+ }
419
+ parse(value) {
420
+ if (value === undefined) {
421
+ return undefined;
422
+ }
423
+ return this.baseValidator.parse(value);
424
+ }
425
+ safeParse(value) {
426
+ // Unlike regular optional, undefined is explicitly valid
427
+ // but we still validate through the base validator
428
+ if (value === undefined) {
429
+ return { success: true, data: undefined };
430
+ }
431
+ return this.baseValidator.safeParse(value);
432
+ }
433
+ unwrap() {
434
+ return this.baseValidator;
435
+ }
436
+ }
352
437
  /**
353
438
  * Nullable validator - allows null
354
439
  */
@@ -4012,6 +4097,66 @@ class VldNumber extends VldBase {
4012
4097
  lte(value, message) {
4013
4098
  return this.max(value, message);
4014
4099
  }
4100
+ /**
4101
+ * Create a validator for unsigned 32-bit integers
4102
+ * Range: 0 to 4,294,967,295
4103
+ */
4104
+ uint32(message) {
4105
+ return new VldNumber({
4106
+ checks: [...this.config.checks, (v) => Number.isSafeInteger(v) && v >= 0 && v <= 4294967295],
4107
+ errorMessage: message || 'Expected an unsigned 32-bit integer'
4108
+ });
4109
+ }
4110
+ /**
4111
+ * Create a validator for unsigned 64-bit integers
4112
+ * Range: 0 to 2^53-1 (safe integer limit)
4113
+ */
4114
+ uint64(message) {
4115
+ return new VldNumber({
4116
+ checks: [...this.config.checks, (v) => Number.isSafeInteger(v) && v >= 0],
4117
+ errorMessage: message || 'Expected an unsigned 64-bit integer'
4118
+ });
4119
+ }
4120
+ /**
4121
+ * Create a validator for signed 32-bit integers
4122
+ * Range: -2,147,483,648 to 2,147,483,647
4123
+ */
4124
+ int32(message) {
4125
+ return new VldNumber({
4126
+ checks: [...this.config.checks, (v) => Number.isSafeInteger(v) && v >= -2147483648 && v <= 2147483647],
4127
+ errorMessage: message || 'Expected a signed 32-bit integer'
4128
+ });
4129
+ }
4130
+ /**
4131
+ * Create a validator for signed 64-bit integers
4132
+ * Range: -(2^53-1) to 2^53-1 (safe integer limit)
4133
+ */
4134
+ int64(message) {
4135
+ return new VldNumber({
4136
+ checks: [...this.config.checks, (v) => Number.isSafeInteger(v)],
4137
+ errorMessage: message || 'Expected a signed 64-bit integer'
4138
+ });
4139
+ }
4140
+ /**
4141
+ * Create a validator for 32-bit floats (IEEE 754 single precision)
4142
+ * Range: -3.4e38 to 3.4e38, precision ~7 decimal digits
4143
+ */
4144
+ float32(message) {
4145
+ return new VldNumber({
4146
+ checks: [...this.config.checks, (v) => Number.isFinite(v) && Math.abs(v) <= 3.4e38],
4147
+ errorMessage: message || 'Expected a 32-bit float'
4148
+ });
4149
+ }
4150
+ /**
4151
+ * Create a validator for 64-bit floats (IEEE 754 double precision)
4152
+ * Alias for standard number validation
4153
+ */
4154
+ float64(message) {
4155
+ return new VldNumber({
4156
+ checks: [...this.config.checks, (v) => Number.isFinite(v)],
4157
+ errorMessage: message || 'Expected a 64-bit float'
4158
+ });
4159
+ }
4015
4160
  }
4016
4161
 
4017
4162
  /**
@@ -8125,6 +8270,87 @@ class VldUint8Array extends VldBase {
8125
8270
  }
8126
8271
  }
8127
8272
 
8273
+ /**
8274
+ * Promise validator - validates Promise values
8275
+ * Validates that the resolved value matches the inner schema
8276
+ */
8277
+ /**
8278
+ * Promise validator - validates Promise<T> where T matches inner schema
8279
+ * Zod 4 API parity - allows async validation with proper type inference
8280
+ *
8281
+ * Validates that the input is a Promise, and validates the resolved value
8282
+ * against the inner schema when parsed.
8283
+ *
8284
+ * Use parseAsync() or safeParseAsync() for proper async handling.
8285
+ */
8286
+ class VldPromise {
8287
+ constructor(inner) {
8288
+ this.inner = inner;
8289
+ }
8290
+ /**
8291
+ * Check if value is thenable (Promise-like)
8292
+ * Must be called BEFORE wrapping in Promise.resolve
8293
+ */
8294
+ _isThenable(value) {
8295
+ return value !== null && typeof value.then === 'function';
8296
+ }
8297
+ /**
8298
+ * Parse and validate a Promise value asynchronously
8299
+ * @param value The Promise to validate
8300
+ * @returns The validated value
8301
+ * @throws {Error} If validation fails when Promise resolves
8302
+ */
8303
+ async parse(value) {
8304
+ // Check if value is thenable BEFORE wrapping in Promise.resolve
8305
+ if (!this._isThenable(value)) {
8306
+ throw new Error('Expected a Promise value');
8307
+ }
8308
+ // Now we can safely await it
8309
+ const resolved = await Promise.resolve(value);
8310
+ return this.inner.parse(resolved);
8311
+ }
8312
+ /**
8313
+ * Safely parse and validate a Promise value asynchronously
8314
+ * @param value The Promise to validate
8315
+ * @returns A Promise resolving to ParseResult containing the validated value
8316
+ */
8317
+ async safeParse(value) {
8318
+ // Check if value is thenable BEFORE wrapping in Promise.resolve
8319
+ if (!this._isThenable(value)) {
8320
+ return {
8321
+ success: false,
8322
+ error: new Error('Expected a Promise value')
8323
+ };
8324
+ }
8325
+ try {
8326
+ const resolved = await Promise.resolve(value);
8327
+ const validated = this.inner.parse(resolved);
8328
+ return {
8329
+ success: true,
8330
+ data: validated
8331
+ };
8332
+ }
8333
+ catch (err) {
8334
+ return {
8335
+ success: false,
8336
+ error: err instanceof Error ? err : new Error(String(err))
8337
+ };
8338
+ }
8339
+ }
8340
+ }
8341
+ /**
8342
+ * Create a Promise validator
8343
+ * @param inner The schema to validate the resolved value against
8344
+ * @returns A new Promise validator
8345
+ * @example
8346
+ * const promiseSchema = v.promise(v.string());
8347
+ * const result = await promiseSchema.parse(Promise.resolve("hello"));
8348
+ * // result is string
8349
+ */
8350
+ function promise(inner) {
8351
+ return new VldPromise(inner);
8352
+ }
8353
+
8128
8354
  /**
8129
8355
  * BigInt coercion validator that attempts to convert values to bigint
8130
8356
  */
@@ -8269,6 +8495,10 @@ const REGEXES = {
8269
8495
  sha256: /^[a-f0-9]{64}$/i,
8270
8496
  sha384: /^[a-f0-9]{96}$/i,
8271
8497
  sha512: /^[a-f0-9]{128}$/i,
8498
+ // Additional formats (Zod v4 parity)
8499
+ xid: /^[A-HJKMNP-TV-Z0-9]{20}$/, // ksort's XID format
8500
+ guid: /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/i, // Alias for UUID
8501
+ httpUrl: /^https?:\/\/[^\s/$.?#].[^\s]*$/, // HTTP/HTTPS URL
8272
8502
  };
8273
8503
  /**
8274
8504
  * Generic string format validator
@@ -8329,6 +8559,9 @@ const mac = () => VldStringFormat.create('mac', (val) => REGEXES.mac.test(val));
8329
8559
  const cidrv4 = () => VldStringFormat.create('cidrv4', (val) => REGEXES.cidrv4.test(val));
8330
8560
  const cidrv6 = () => VldStringFormat.create('cidrv6', (val) => REGEXES.cidrv6.test(val));
8331
8561
  const e164 = () => VldStringFormat.create('e164', (val) => REGEXES.e164.test(val));
8562
+ const xid = () => VldStringFormat.create('xid', (val) => REGEXES.xid.test(val));
8563
+ const guid = () => VldStringFormat.create('guid', (val) => REGEXES.guid.test(val));
8564
+ const httpUrl = () => VldStringFormat.create('httpUrl', (val) => REGEXES.httpUrl.test(val));
8332
8565
  const hash = (algorithm) => VldStringFormat.create('hash', (val) => REGEXES[algorithm]?.test(val) ?? false, `Invalid ${algorithm} hash`);
8333
8566
  /**
8334
8567
  * ISO date/time validators
@@ -9767,6 +10000,534 @@ function createNoOpLogger() {
9767
10000
  return createLogger({ level: 'silent' });
9768
10001
  }
9769
10002
 
10003
+ /**
10004
+ * JSON Schema support for VLD validators
10005
+ * Provides conversion between VLD schemas and JSON Schema
10006
+ */
10007
+ /**
10008
+ * Convert a VLD schema to JSON Schema
10009
+ * @param schema The VLD schema to convert
10010
+ * @param options Conversion options
10011
+ * @returns JSON Schema definition
10012
+ */
10013
+ function toJSONSchema(schema, options = {}) {
10014
+ return schemaToJSONSchema(schema, options);
10015
+ }
10016
+ /**
10017
+ * Convert a JSON Schema to a VLD schema
10018
+ * @param json The JSON Schema definition
10019
+ * @returns A VLD schema
10020
+ */
10021
+ function fromJSONSchema(json) {
10022
+ return jsonSchemaToVLD(json);
10023
+ }
10024
+ /**
10025
+ * Internal function to convert VLD schema to JSON Schema
10026
+ */
10027
+ function schemaToJSONSchema(schema, options) {
10028
+ options.target || 'draft-07';
10029
+ // Handle primitives
10030
+ if (schema.constructor.name === 'VldString') {
10031
+ return buildStringSchema();
10032
+ }
10033
+ if (schema.constructor.name === 'VldNumber') {
10034
+ return buildNumberSchema(schema);
10035
+ }
10036
+ if (schema.constructor.name === 'VldBoolean') {
10037
+ return { type: 'boolean' };
10038
+ }
10039
+ if (schema.constructor.name === 'VldBigInt') {
10040
+ return { type: 'integer' };
10041
+ }
10042
+ if (schema.constructor.name === 'VldDate') {
10043
+ return { type: 'string', format: 'date-time' };
10044
+ }
10045
+ if (schema.constructor.name === 'VldArray') {
10046
+ return buildArraySchema(schema, options);
10047
+ }
10048
+ if (schema.constructor.name === 'VldObject') {
10049
+ return buildObjectSchema(schema, options);
10050
+ }
10051
+ // Handle union types
10052
+ if (schema.constructor.name === 'VldUnion') {
10053
+ return buildUnionSchema(schema, options);
10054
+ }
10055
+ // Handle literal types
10056
+ if (schema.constructor.name === 'VldLiteral') {
10057
+ return buildLiteralSchema(schema);
10058
+ }
10059
+ if (schema.constructor.name === 'VldEnum') {
10060
+ return buildEnumSchema(schema);
10061
+ }
10062
+ if (schema.constructor.name === 'VldRecord') {
10063
+ return buildRecordSchema(schema, options);
10064
+ }
10065
+ if (schema.constructor.name === 'VldTuple') {
10066
+ return buildTupleSchema(schema, options);
10067
+ }
10068
+ if (schema.constructor.name === 'VldIntersection') {
10069
+ return buildIntersectionSchema(schema, options);
10070
+ }
10071
+ if (schema.constructor.name === 'VldOptional') {
10072
+ return buildOptionalSchema(schema, options);
10073
+ }
10074
+ if (schema.constructor.name === 'VldNullable') {
10075
+ return buildNullableSchema(schema, options);
10076
+ }
10077
+ if (schema.constructor.name === 'VldNullish') {
10078
+ return buildNullishSchema(schema, options);
10079
+ }
10080
+ if (schema.constructor.name === 'VldExactOptional') {
10081
+ return buildExactOptionalSchema(schema, options);
10082
+ }
10083
+ if (schema.constructor.name === 'VldLazy') {
10084
+ return { type: 'object' }; // Placeholder for recursive schemas
10085
+ }
10086
+ if (schema.constructor.name === 'VldJson') {
10087
+ return {}; // Any JSON
10088
+ }
10089
+ if (schema.constructor.name === 'VldAny') {
10090
+ return {}; // JSON Schema true
10091
+ }
10092
+ if (schema.constructor.name === 'VldUnknown') {
10093
+ return {}; // JSON Schema true
10094
+ }
10095
+ if (schema.constructor.name === 'VldNever') {
10096
+ return { not: {} }; // JSON Schema false
10097
+ }
10098
+ if (schema.constructor.name === 'VldNull') {
10099
+ return { type: 'null' };
10100
+ }
10101
+ if (schema.constructor.name === 'VldUndefined') {
10102
+ return { not: {} }; // Undefined can't be represented in JSON Schema
10103
+ }
10104
+ if (schema.constructor.name === 'VldNan') {
10105
+ return { type: 'number', not: {} }; // NaN is a number type constraint
10106
+ }
10107
+ if (schema.constructor.name === 'VldVoid') {
10108
+ return { not: {} }; // Void/undefined can't be represented
10109
+ }
10110
+ // Handle branded types - unwrap and continue
10111
+ if (schema.constructor.name === 'VldBrand') {
10112
+ return schemaToJSONSchema(schema.baseValidator, options);
10113
+ }
10114
+ // Handle readonly types
10115
+ if (schema.constructor.name === 'VldReadonly') {
10116
+ return schemaToJSONSchema(schema.baseValidator, options);
10117
+ }
10118
+ // Handle transform types
10119
+ if (schema.constructor.name === 'VldTransform') {
10120
+ return schemaToJSONSchema(schema._inner, options);
10121
+ }
10122
+ // Handle meta types - unwrap metadata
10123
+ if (schema.constructor.name === 'VldMeta') {
10124
+ const metaSchema = schema;
10125
+ const result = schemaToJSONSchema(metaSchema.baseValidator, options);
10126
+ if (options.includeMetadata !== false && metaSchema.metadata) {
10127
+ const meta = metaSchema.metadata;
10128
+ if (meta.title)
10129
+ result.title = meta.title;
10130
+ if (meta.description)
10131
+ result.description = meta.description;
10132
+ if (meta.examples && options.includeExamples)
10133
+ result.examples = meta.examples;
10134
+ if (meta.default !== undefined)
10135
+ result.default = meta.default;
10136
+ if (meta.deprecated)
10137
+ result.deprecated = true;
10138
+ if (meta.readOnly)
10139
+ result.readOnly = true;
10140
+ if (meta.writeOnly)
10141
+ result.writeOnly = true;
10142
+ }
10143
+ return result;
10144
+ }
10145
+ // Handle refine/superRefine types
10146
+ if (schema.constructor.name === 'VldRefine' || schema.constructor.name === 'VldSuperRefine') {
10147
+ return schemaToJSONSchema(schema._inner || schema._baseValidator, options);
10148
+ }
10149
+ // Handle pipe types
10150
+ if (schema.constructor.name === 'VldPipe') {
10151
+ return schemaToJSONSchema(schema._next || schema.second, options);
10152
+ }
10153
+ // Handle default/catch types
10154
+ if (schema.constructor.name === 'VldDefault' || schema.constructor.name === 'VldCatch') {
10155
+ return schemaToJSONSchema(schema._inner || schema._baseValidator, options);
10156
+ }
10157
+ // Handle preprocess types
10158
+ if (schema.constructor.name === 'VldPreprocess') {
10159
+ return schemaToJSONSchema(schema._schema, options);
10160
+ }
10161
+ // Handle string format validators
10162
+ if (schema.constructor.name === 'VldStringFormat') {
10163
+ const formatSchema = schema;
10164
+ return { type: 'string', format: formatSchema._format };
10165
+ }
10166
+ // Fallback for unknown types
10167
+ return {};
10168
+ }
10169
+ /**
10170
+ * Build string JSON Schema
10171
+ */
10172
+ function buildStringSchema(_target) {
10173
+ return { type: 'string' };
10174
+ }
10175
+ /**
10176
+ * Build number JSON Schema from VLD number schema
10177
+ */
10178
+ function buildNumberSchema(schema, _target) {
10179
+ const config = schema.config || {};
10180
+ const checks = config.checks || [];
10181
+ const result = { type: 'number' };
10182
+ for (const check of checks) {
10183
+ // Try to extract constraints from closures
10184
+ const checkStr = check.toString();
10185
+ if (checkStr.includes('>=') || checkStr.includes('min')) {
10186
+ result.minimum = 0; // Default, actual value is in closure
10187
+ }
10188
+ if (checkStr.includes('<=') || checkStr.includes('max')) {
10189
+ result.maximum = 0; // Default, actual value is in closure
10190
+ }
10191
+ if (checkStr.includes('isInteger') || checkStr.includes('int')) {
10192
+ result.type = 'integer';
10193
+ }
10194
+ if (checkStr.includes('isSafeInteger')) {
10195
+ result.type = 'integer';
10196
+ }
10197
+ if (checkStr.includes('Number.isFinite')) ;
10198
+ }
10199
+ return result;
10200
+ }
10201
+ /**
10202
+ * Build array JSON Schema
10203
+ */
10204
+ function buildArraySchema(schema, options) {
10205
+ const inner = schema._item || schema._inner;
10206
+ if (inner) {
10207
+ return {
10208
+ type: 'array',
10209
+ items: toJSONSchema(inner, options)
10210
+ };
10211
+ }
10212
+ return { type: 'array' };
10213
+ }
10214
+ /**
10215
+ * Build object JSON Schema
10216
+ */
10217
+ function buildObjectSchema(schema, options) {
10218
+ const shape = schema._shape || schema.shape;
10219
+ if (!shape)
10220
+ return { type: 'object' };
10221
+ const properties = {};
10222
+ const required = [];
10223
+ for (const [key, value] of Object.entries(shape)) {
10224
+ properties[key] = toJSONSchema(value, options);
10225
+ // VLD objects require all keys by default
10226
+ if (schema._strict !== false) {
10227
+ required.push(key);
10228
+ }
10229
+ }
10230
+ const result = {
10231
+ type: 'object',
10232
+ properties
10233
+ };
10234
+ if (required.length > 0) {
10235
+ result.required = required;
10236
+ }
10237
+ // Handle passthrough mode
10238
+ if (schema._passthrough || schema._loose) {
10239
+ result.additionalProperties = true;
10240
+ }
10241
+ else if (schema._strict) {
10242
+ result.additionalProperties = false;
10243
+ }
10244
+ return result;
10245
+ }
10246
+ /**
10247
+ * Build union JSON Schema
10248
+ */
10249
+ function buildUnionSchema(schema, options) {
10250
+ const validators = schema._validators || schema._options || [];
10251
+ return {
10252
+ anyOf: validators.map((v) => toJSONSchema(v, options))
10253
+ };
10254
+ }
10255
+ /**
10256
+ * Build literal JSON Schema
10257
+ */
10258
+ function buildLiteralSchema(schema) {
10259
+ const value = schema._value || schema.value;
10260
+ if (value === null)
10261
+ return { type: 'null' };
10262
+ if (typeof value === 'string')
10263
+ return { type: 'string', const: value };
10264
+ if (typeof value === 'number')
10265
+ return { type: 'number', const: value };
10266
+ if (typeof value === 'boolean')
10267
+ return { type: 'boolean', const: value };
10268
+ return { const: value };
10269
+ }
10270
+ /**
10271
+ * Build enum JSON Schema
10272
+ */
10273
+ function buildEnumSchema(schema) {
10274
+ const values = schema._values || schema.values;
10275
+ if (Array.isArray(values)) {
10276
+ return { enum: [...values] };
10277
+ }
10278
+ return {};
10279
+ }
10280
+ /**
10281
+ * Build record JSON Schema
10282
+ */
10283
+ function buildRecordSchema(schema, options) {
10284
+ const valueValidator = schema._value || schema._inner;
10285
+ if (valueValidator) {
10286
+ return {
10287
+ type: 'object',
10288
+ additionalProperties: toJSONSchema(valueValidator, options)
10289
+ };
10290
+ }
10291
+ return { type: 'object' };
10292
+ }
10293
+ /**
10294
+ * Build tuple JSON Schema
10295
+ */
10296
+ function buildTupleSchema(schema, options) {
10297
+ const items = schema._items || schema.items;
10298
+ if (!items || !Array.isArray(items)) {
10299
+ return { type: 'array' };
10300
+ }
10301
+ return {
10302
+ type: 'array',
10303
+ items: items.map((item) => toJSONSchema(item, options)),
10304
+ minItems: items.length,
10305
+ maxItems: items.length
10306
+ };
10307
+ }
10308
+ /**
10309
+ * Build intersection JSON Schema
10310
+ */
10311
+ function buildIntersectionSchema(schema, options) {
10312
+ const first = schema._first || schema.first;
10313
+ const second = schema._second || schema.second;
10314
+ const schemas = [];
10315
+ if (first)
10316
+ schemas.push(toJSONSchema(first, options));
10317
+ if (second)
10318
+ schemas.push(toJSONSchema(second, options));
10319
+ if (schemas.length === 0)
10320
+ return {};
10321
+ if (schemas.length === 1)
10322
+ return schemas[0];
10323
+ return { allOf: schemas };
10324
+ }
10325
+ /**
10326
+ * Build optional JSON Schema
10327
+ */
10328
+ function buildOptionalSchema(schema, options) {
10329
+ const inner = schema._inner || schema._baseValidator;
10330
+ if (!inner)
10331
+ return {};
10332
+ const result = toJSONSchema(inner, options);
10333
+ // Remove from required array - but we don't track required here
10334
+ return result;
10335
+ }
10336
+ /**
10337
+ * Build nullable JSON Schema
10338
+ */
10339
+ function buildNullableSchema(schema, options) {
10340
+ const inner = schema._inner || schema._baseValidator;
10341
+ if (!inner)
10342
+ return { type: 'null' };
10343
+ const result = toJSONSchema(inner, options);
10344
+ if (typeof result.type === 'string') {
10345
+ return { type: [result.type, 'null'] };
10346
+ }
10347
+ else if (Array.isArray(result.type)) {
10348
+ result.type.push('null');
10349
+ return result;
10350
+ }
10351
+ return {
10352
+ anyOf: [result, { type: 'null' }]
10353
+ };
10354
+ }
10355
+ /**
10356
+ * Build nullish JSON Schema
10357
+ */
10358
+ function buildNullishSchema(schema, options) {
10359
+ const inner = schema._inner || schema._baseValidator;
10360
+ if (!inner)
10361
+ return {};
10362
+ return toJSONSchema(inner, options);
10363
+ }
10364
+ /**
10365
+ * Build exactOptional JSON Schema
10366
+ */
10367
+ function buildExactOptionalSchema(schema, options) {
10368
+ const inner = schema._inner || schema._baseValidator;
10369
+ if (!inner)
10370
+ return {};
10371
+ return toJSONSchema(inner, options);
10372
+ }
10373
+ /**
10374
+ * Internal function to convert JSON Schema to VLD schema
10375
+ */
10376
+ function jsonSchemaToVLD(json) {
10377
+ // This is a simplified implementation
10378
+ // Full implementation would recursively handle all JSON Schema types
10379
+ const VldString = require('../validators/string').VldString;
10380
+ const VldNumber = require('../validators/number').VldNumber;
10381
+ const VldBoolean = require('../validators/boolean').VldBoolean;
10382
+ const VldObject = require('../validators/object').VldObject;
10383
+ const VldArray = require('../validators/array').VldArray;
10384
+ const VldUnion = require('../validators/union').VldUnion;
10385
+ const VldLiteral = require('../validators/literal').VldLiteral;
10386
+ const VldEnum = require('../validators/enum').VldEnum;
10387
+ const VldNull = require('../validators/null').VldNull;
10388
+ const VldAny = require('../validators/any').VldAny;
10389
+ const VldRecord = require('../validators/record').VldRecord;
10390
+ // Handle $ref
10391
+ if (json.$ref) {
10392
+ // For now, return any - full $ref handling requires registry
10393
+ return VldAny.create();
10394
+ }
10395
+ // Handle anyOf/oneOf (union)
10396
+ if (json.anyOf || json.oneOf) {
10397
+ const options = (json.anyOf || json.oneOf)
10398
+ .map((s) => jsonSchemaToVLD(s))
10399
+ .filter(Boolean);
10400
+ if (options.length > 0) {
10401
+ return VldUnion.create(...options);
10402
+ }
10403
+ }
10404
+ // Handle allOf (intersection)
10405
+ if (json.allOf) {
10406
+ // For intersection, we'd need VldIntersection
10407
+ const first = jsonSchemaToVLD(json.allOf[0]);
10408
+ if (json.allOf.length > 1) {
10409
+ const second = jsonSchemaToVLD({ allOf: json.allOf.slice(1) });
10410
+ const VldIntersection = require('../validators/intersection').VldIntersection;
10411
+ return VldIntersection.create(first, second);
10412
+ }
10413
+ return first;
10414
+ }
10415
+ // Handle not
10416
+ if (json.not) {
10417
+ // For negation, we need special handling
10418
+ return VldAny.create();
10419
+ }
10420
+ // Handle const
10421
+ if (json.const !== undefined) {
10422
+ return VldLiteral.create(json.const);
10423
+ }
10424
+ // Handle enum
10425
+ if (json.enum) {
10426
+ return VldEnum.create(json.enum);
10427
+ }
10428
+ // Handle type
10429
+ const type = json.type;
10430
+ if (type === 'string' || type === undefined) {
10431
+ const s = VldString.create();
10432
+ if (json.minLength)
10433
+ s.minLength = json.minLength;
10434
+ if (json.maxLength)
10435
+ s.maxLength = json.maxLength;
10436
+ if (json.pattern)
10437
+ s.pattern = json.pattern;
10438
+ if (json.format) {
10439
+ // Map JSON Schema formats to VLD validators
10440
+ switch (json.format) {
10441
+ case 'date-time':
10442
+ case 'date':
10443
+ case 'time':
10444
+ // Would need DateTime validator
10445
+ break;
10446
+ case 'email':
10447
+ const email = require('../validators/string-formats').email;
10448
+ return email();
10449
+ case 'uri':
10450
+ case 'uri-reference':
10451
+ const httpUrl = require('../validators/string-formats').httpUrl;
10452
+ return httpUrl();
10453
+ case 'uuid':
10454
+ const uuid = require('../validators/string-formats').uuid;
10455
+ return uuid();
10456
+ }
10457
+ }
10458
+ return s;
10459
+ }
10460
+ if (type === 'number' || type === 'integer') {
10461
+ const n = VldNumber.create();
10462
+ if (type === 'integer')
10463
+ n.int();
10464
+ if (json.minimum !== undefined)
10465
+ n.min(json.minimum);
10466
+ if (json.maximum !== undefined)
10467
+ n.max(json.maximum);
10468
+ if (json.exclusiveMinimum !== undefined)
10469
+ n.gt(json.exclusiveMinimum);
10470
+ if (json.exclusiveMaximum !== undefined)
10471
+ n.lt(json.exclusiveMaximum);
10472
+ if (json.multipleOf !== undefined)
10473
+ n.multipleOf(json.multipleOf);
10474
+ return n;
10475
+ }
10476
+ if (type === 'boolean') {
10477
+ return VldBoolean.create();
10478
+ }
10479
+ if (type === 'array') {
10480
+ if (json.items && !Array.isArray(json.items)) {
10481
+ return VldArray.create(jsonSchemaToVLD(json.items));
10482
+ }
10483
+ return VldArray.create(VldAny.create());
10484
+ }
10485
+ if (type === 'object') {
10486
+ if (json.properties) {
10487
+ const shape = {};
10488
+ const required = json.required || [];
10489
+ for (const [key, propSchema] of Object.entries(json.properties)) {
10490
+ shape[key] = jsonSchemaToVLD(propSchema);
10491
+ }
10492
+ let obj = VldObject.create(shape);
10493
+ if (!required.length) {
10494
+ // If no required fields, make all optional
10495
+ for (const key of Object.keys(shape)) {
10496
+ if (!required.includes(key)) ;
10497
+ }
10498
+ }
10499
+ if (json.additionalProperties === false) {
10500
+ obj = obj.strict();
10501
+ }
10502
+ else if (json.additionalProperties === true) {
10503
+ obj = obj.passthrough();
10504
+ }
10505
+ else if (json.additionalProperties) {
10506
+ // additionalProperties is a schema
10507
+ const valueSchema = jsonSchemaToVLD(json.additionalProperties);
10508
+ obj = VldRecord.create(valueSchema);
10509
+ }
10510
+ return obj;
10511
+ }
10512
+ // Empty object schema
10513
+ return VldObject.create({});
10514
+ }
10515
+ if (type === 'null') {
10516
+ return VldNull.create();
10517
+ }
10518
+ if (Array.isArray(type)) {
10519
+ // Union of types
10520
+ const options = type.map((t) => {
10521
+ return jsonSchemaToVLD({ ...json, type: t });
10522
+ });
10523
+ if (options.length > 0) {
10524
+ return VldUnion.create(...options);
10525
+ }
10526
+ }
10527
+ // Fallback to any
10528
+ return VldAny.create();
10529
+ }
10530
+
9770
10531
  /**
9771
10532
  * VLD - Fast, Type-Safe Validation Library
9772
10533
  * Zero dependencies, blazing fast performance
@@ -9792,6 +10553,11 @@ const v = {
9792
10553
  number: () => VldNumber.create(),
9793
10554
  int: () => VldNumber.create().int(),
9794
10555
  int32: () => VldNumber.create().int().min(-2147483648).max(2147483647),
10556
+ uint32: () => VldNumber.create().uint32(),
10557
+ uint64: () => VldNumber.create().uint64(),
10558
+ int64: () => VldNumber.create().int64(),
10559
+ float32: () => VldNumber.create().float32(),
10560
+ float64: () => VldNumber.create().float64(),
9795
10561
  boolean: () => VldBoolean.create(),
9796
10562
  date: () => VldDate.create(),
9797
10563
  bigint: () => VldBigInt.create(),
@@ -9830,6 +10596,7 @@ const v = {
9830
10596
  optional: (validator) => VldOptional.create(validator),
9831
10597
  nullable: (validator) => VldNullable.create(validator),
9832
10598
  nullish: (validator) => VldNullish.create(validator),
10599
+ exactOptional: (validator) => VldExactOptional.create(validator),
9833
10600
  // Recursive schemas
9834
10601
  lazy: (schemaGetter) => VldLazy.create(schemaGetter),
9835
10602
  // JSON validator
@@ -9878,6 +10645,10 @@ const v = {
9878
10645
  duration: () => iso.duration(),
9879
10646
  },
9880
10647
  stringFormat: (name, validator) => stringFormat(name, validator),
10648
+ // Zod v4 parity string formats
10649
+ xid: () => xid(),
10650
+ guid: () => guid(),
10651
+ httpUrl: () => httpUrl(),
9881
10652
  // Template literal validator
9882
10653
  templateLiteral: (...components) => templateLiteral(...components),
9883
10654
  // Codec validators (binary data validators)
@@ -9885,7 +10656,9 @@ const v = {
9885
10656
  hexBytes: () => VldHex.create(),
9886
10657
  uint8Array: () => VldUint8Array.create(),
9887
10658
  // Codec factory
9888
- codec: (inputValidator, outputValidator, transform) => VldCodec.create(inputValidator, outputValidator, transform)
10659
+ codec: (inputValidator, outputValidator, transform) => VldCodec.create(inputValidator, outputValidator, transform),
10660
+ // Promise validator (Zod v4 parity)
10661
+ promise: (inner) => promise(inner)
9889
10662
  };
9890
10663
 
9891
10664
  exports.Err = Err;
@@ -9894,6 +10667,7 @@ exports.ResultUtils = ResultUtils;
9894
10667
  exports.VldBase = VldBase;
9895
10668
  exports.VldError = VldError;
9896
10669
  exports.VldIntersection = VldIntersection;
10670
+ exports.VldMeta = VldMeta;
9897
10671
  exports.all = all;
9898
10672
  exports.base64Json = base64Json;
9899
10673
  exports.base64ToBytes = base64ToBytes;
@@ -9920,6 +10694,7 @@ exports.epochSecondsToDate = epochSecondsToDate;
9920
10694
  exports.failure = failure;
9921
10695
  exports.flatMap = flatMap;
9922
10696
  exports.flattenError = flattenError;
10697
+ exports.fromJSONSchema = fromJSONSchema;
9923
10698
  exports.fromNullable = fromNullable;
9924
10699
  exports.getLocale = getLocale;
9925
10700
  exports.getLogger = getLogger;
@@ -9962,6 +10737,7 @@ exports.stringToUint8Array = stringToUint8Array;
9962
10737
  exports.strip = strip;
9963
10738
  exports.success = success;
9964
10739
  exports.supportsColor = supportsColor;
10740
+ exports.toJSONSchema = toJSONSchema;
9965
10741
  exports.treeifyError = treeifyError;
9966
10742
  exports.tryCatch = tryCatch;
9967
10743
  exports.tryCatchAsync = tryCatchAsync;