@warlock.js/seal 5.16.0 → 5.17.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +22 -0
  3. package/cjs/index.cjs +953 -6977
  4. package/cjs/index.cjs.map +1 -1
  5. package/cjs/object-_2YHdBxJ.cjs +613 -0
  6. package/cjs/object-_2YHdBxJ.cjs.map +1 -0
  7. package/cjs/object.cjs +10 -0
  8. package/cjs/required-methods-GwIEE6hP.cjs +5868 -0
  9. package/cjs/required-methods-GwIEE6hP.cjs.map +1 -0
  10. package/cjs/string-6m5Y83pJ.cjs +943 -0
  11. package/cjs/string-6m5Y83pJ.cjs.map +1 -0
  12. package/cjs/string.cjs +10 -0
  13. package/esm/factory/validators.d.mts +5 -0
  14. package/esm/factory/validators.d.mts.map +1 -1
  15. package/esm/factory/validators.mjs +4 -3
  16. package/esm/factory/validators.mjs.map +1 -1
  17. package/esm/helpers/index.mjs +1 -1
  18. package/esm/helpers/validation-helpers.mjs +1 -1
  19. package/esm/helpers/validation-helpers.mjs.map +1 -1
  20. package/esm/index.mjs +1 -1
  21. package/esm/object.d.mts +15 -0
  22. package/esm/object.d.mts.map +1 -0
  23. package/esm/object.mjs +13 -0
  24. package/esm/object.mjs.map +1 -0
  25. package/esm/rules/common/equals-field-rules.mjs +1 -1
  26. package/esm/rules/conditional/forbidden-if-rules.mjs +2 -2
  27. package/esm/rules/conditional/present-if-rules.mjs +2 -2
  28. package/esm/rules/conditional/present-unless-rules.mjs +1 -1
  29. package/esm/rules/conditional/present-with-rules.mjs +1 -1
  30. package/esm/rules/conditional/present-without-rules.mjs +1 -1
  31. package/esm/rules/conditional/required-if-rules.mjs +2 -2
  32. package/esm/rules/conditional/required-unless-rules.mjs +2 -2
  33. package/esm/rules/conditional/required-when-rule.mjs +1 -1
  34. package/esm/rules/conditional/required-with-rules.mjs +2 -2
  35. package/esm/rules/conditional/required-without-rules.mjs +2 -2
  36. package/esm/rules/core/forbidden.mjs +1 -1
  37. package/esm/rules/core/required.mjs +1 -1
  38. package/esm/rules/date/date-field-comparison-rules.mjs +1 -1
  39. package/esm/rules/date/date.mjs +1 -1
  40. package/esm/rules/file/file-size.mjs +1 -1
  41. package/esm/rules/scalar/accepted-rule.mjs +2 -2
  42. package/esm/rules/scalar/declined-rule.mjs +2 -2
  43. package/esm/string.d.mts +13 -0
  44. package/esm/string.d.mts.map +1 -0
  45. package/esm/string.mjs +13 -0
  46. package/esm/string.mjs.map +1 -0
  47. package/esm/types/context-types.d.mts +2 -1
  48. package/esm/types/context-types.d.mts.map +1 -1
  49. package/esm/validators/base-validator.d.mts.map +1 -1
  50. package/esm/validators/base-validator.mjs +0 -1
  51. package/esm/validators/base-validator.mjs.map +1 -1
  52. package/esm/validators/object-validator.d.mts.map +1 -1
  53. package/esm/validators/object-validator.mjs +0 -3
  54. package/esm/validators/object-validator.mjs.map +1 -1
  55. package/esm/validators/primitive-validator.mjs +0 -1
  56. package/esm/validators/primitive-validator.mjs.map +1 -1
  57. package/esm/validators/string-validator.d.mts.map +1 -1
  58. package/esm/validators/string-validator.mjs +2 -2
  59. package/esm/validators/string-validator.mjs.map +1 -1
  60. package/llms-full.txt +22 -0
  61. package/package.json +21 -1
  62. package/skills/seal-basics/SKILL.md +22 -0
@@ -0,0 +1,613 @@
1
+ const require_required_methods = require('./required-methods-GwIEE6hP.cjs');
2
+ let _mongez_reinforcements = require("@mongez/reinforcements");
3
+ let _mongez_supportive_is = require("@mongez/supportive-is");
4
+
5
+ //#region ../seal/src/mutators/object-mutators.ts
6
+ /** Strip unknown keys from object */
7
+ const stripUnknownMutator = async (value, context) => {
8
+ const allowedKeys = [...context?.ctx.schema ? Object.keys(context.ctx.schema) : [], ...context?.options.allowedKeys ?? []];
9
+ const result = {};
10
+ for (const key in value) if (allowedKeys.includes(key)) result[key] = value[key];
11
+ return result;
12
+ };
13
+ /** Trim all string values in object */
14
+ const objectTrimMutator = async (value, context) => {
15
+ if (!(0, _mongez_supportive_is.isPlainObject)(value)) return value;
16
+ const result = {};
17
+ const recursive = context?.options.recursive ?? false;
18
+ for (const key in value) {
19
+ const item = value[key];
20
+ if (recursive) if (Array.isArray(item)) result[key] = await Promise.all(item.map(async (i) => typeof i === "string" ? (0, _mongez_reinforcements.trim)(i) : await objectTrimMutator(i, context)));
21
+ else if ((0, _mongez_supportive_is.isPlainObject)(item)) result[key] = await objectTrimMutator(item, context);
22
+ else result[key] = typeof item === "string" ? (0, _mongez_reinforcements.trim)(item) : item;
23
+ else result[key] = typeof item === "string" ? (0, _mongez_reinforcements.trim)(item) : item;
24
+ }
25
+ return result;
26
+ };
27
+ /** Parse JSON string */
28
+ const jsonMutator = async (value) => {
29
+ try {
30
+ return JSON.parse(value);
31
+ } catch {
32
+ return value;
33
+ }
34
+ };
35
+
36
+ //#endregion
37
+ //#region ../seal/src/validators/computed-validator.ts
38
+ /**
39
+ * Computed field validator
40
+ *
41
+ * Computes a value based on other validated fields in the schema.
42
+ * The computed value is persisted and can optionally be validated.
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * // Basic computed field
47
+ * const schema = v.object({
48
+ * title: v.string().required(),
49
+ * slug: v.computed(data => slugify(data.title)),
50
+ * });
51
+ *
52
+ * // With result validation
53
+ * const schema = v.object({
54
+ * title: v.string().required(),
55
+ * slug: v.computed(
56
+ * data => slugify(data.title),
57
+ * v.string().minLength(3)
58
+ * ),
59
+ * });
60
+ *
61
+ * // Async computation
62
+ * const schema = v.object({
63
+ * image: v.string().url(),
64
+ * thumbnail: v.computed(async data => {
65
+ * return await generateThumbnail(data.image);
66
+ * }),
67
+ * });
68
+ * ```
69
+ */
70
+ var ComputedValidator = class extends require_required_methods.BaseValidator {
71
+ /**
72
+ * Create a new computed field validator
73
+ *
74
+ * @param callback - Function to compute the value from validated data
75
+ * @param resultValidator - Optional validator to validate the computed result
76
+ */
77
+ constructor(callback, resultValidator) {
78
+ super();
79
+ this.callback = callback;
80
+ this.resultValidator = resultValidator;
81
+ }
82
+ /**
83
+ * Execute the callback and optionally validate the result
84
+ */
85
+ async validate(data, context) {
86
+ try {
87
+ const result = await this.callback(data, context);
88
+ if (this.resultValidator) {
89
+ const validation = await this.resultValidator.validate(result, context);
90
+ if (!validation.isValid) return {
91
+ isValid: false,
92
+ errors: validation.errors,
93
+ data: void 0
94
+ };
95
+ return {
96
+ isValid: true,
97
+ errors: [],
98
+ data: validation.data
99
+ };
100
+ }
101
+ return {
102
+ isValid: true,
103
+ errors: [],
104
+ data: result
105
+ };
106
+ } catch (error) {
107
+ return {
108
+ isValid: false,
109
+ errors: [{
110
+ type: "computed",
111
+ error: error instanceof Error ? error.message : "Computed field callback failed",
112
+ input: context.path
113
+ }],
114
+ data: void 0
115
+ };
116
+ }
117
+ }
118
+ /**
119
+ * Clone this validator with all its configuration
120
+ * Critical for ObjectValidator.clone(), extend(), merge(), etc.
121
+ */
122
+ clone() {
123
+ const cloned = super.clone();
124
+ cloned.callback = this.callback;
125
+ cloned.resultValidator = this.resultValidator?.clone();
126
+ return cloned;
127
+ }
128
+ /**
129
+ * Computed fields don't have a specific type to match
130
+ */
131
+ matchesType(value) {
132
+ return true;
133
+ }
134
+ /**
135
+ * @inheritdoc
136
+ *
137
+ * Computed fields are server-side runtime values — they have no input schema
138
+ * and cannot be represented in JSON Schema. Calling this method is always a
139
+ * programming error.
140
+ *
141
+ * @throws Error Always throws — computed/managed fields have no JSON Schema representation.
142
+ */
143
+ toJsonSchema(_target = "draft-2020-12") {
144
+ throw new Error("[Seal] toJsonSchema() is not supported on ComputedValidator / ManagedValidator. Computed fields are runtime-only and have no input JSON Schema representation. ObjectValidator.toJsonSchema() automatically skips computed fields — do not call toJsonSchema() on a computed validator directly.");
145
+ }
146
+ };
147
+
148
+ //#endregion
149
+ //#region ../seal/src/validators/object-validator.ts
150
+ /**
151
+ * Object validator class with generic schema type for proper type inference.
152
+ *
153
+ * Threads two distinct inferred shapes into `BaseValidator`'s `TInput`/`TOutput`:
154
+ *
155
+ * - `TInput` = `InferInputObjectShape<TSchema>` — what `~standard.validate()`
156
+ * accepts (caller's pre-validation payload; defaults/catches make
157
+ * keys optional)
158
+ * - `TOutput` = `InferOutputObjectShape<TSchema>` — what `~standard.validate()`
159
+ * returns on success (post-default, post-catch shape; guaranteed
160
+ * keys are required)
161
+ *
162
+ * Both helpers are used directly (not the full `Infer.*` walker) to avoid a
163
+ * recursive class-base evaluation that would otherwise occur when the
164
+ * brand-aware widening tries to inspect the class type.
165
+ */
166
+ var ObjectValidator = class ObjectValidator extends require_required_methods.BaseValidator {
167
+ constructor(schema, errorMessage) {
168
+ super();
169
+ this.schema = schema;
170
+ this.shouldAllowUnknown = false;
171
+ this.allowedKeys = [];
172
+ this.hasUnknownKeyRule = false;
173
+ this.addMutableRule(require_required_methods.objectRule, errorMessage);
174
+ }
175
+ /**
176
+ * Check if value is an object type (plain object, not array or date)
177
+ */
178
+ matchesType(value) {
179
+ return (0, _mongez_supportive_is.isPlainObject)(value);
180
+ }
181
+ /** Strip unknown keys from the data */
182
+ stripUnknown() {
183
+ const validator = this.instance;
184
+ return validator.addMutator(stripUnknownMutator, { get allowedKeys() {
185
+ return validator.allowedKeys;
186
+ } });
187
+ }
188
+ /** Add list of allowed keys that could be in the data but not necessarily validated */
189
+ allow(...keys) {
190
+ const validator = this.instance;
191
+ validator.allowedKeys.push(...keys);
192
+ return validator;
193
+ }
194
+ /** Trim values of the object properties */
195
+ trim(recursive = true) {
196
+ return this.instance.addMutator(objectTrimMutator, { recursive });
197
+ }
198
+ /** Whether to allow unknown properties
199
+ * Please note it will allow only unknown direct children keys, not nested children keys
200
+ */
201
+ allowUnknown(allow = true) {
202
+ const validator = this.instance;
203
+ validator.shouldAllowUnknown = allow;
204
+ return validator;
205
+ }
206
+ /**
207
+ * Create a copy of this object validator with the same configuration
208
+ * Copies schema, rules, mutators, transformers, and object-specific settings
209
+ *
210
+ * @returns A new ObjectValidator instance with copied configuration
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * const baseUser = v.object({ name: v.string() }).allowUnknown();
215
+ * const userCopy = baseUser.clone();
216
+ * // userCopy has the same schema and allowUnknown setting
217
+ * ```
218
+ */
219
+ clone(keys) {
220
+ const cloned = super.clone();
221
+ const newSchema = {};
222
+ for (const [key, validator] of Object.entries(this.schema)) {
223
+ if (keys && !keys.includes(key)) continue;
224
+ newSchema[key] = validator.clone();
225
+ }
226
+ cloned.schema = newSchema;
227
+ cloned.shouldAllowUnknown = this.shouldAllowUnknown;
228
+ cloned.allowedKeys = [...this.allowedKeys];
229
+ return cloned;
230
+ }
231
+ /**
232
+ * Extend this schema with additional fields
233
+ * Clones the current validator and adds new fields to the schema
234
+ * **Keeps original configuration** (allowUnknown, stripUnknown, etc.)
235
+ *
236
+ * If an ObjectValidator is provided, only its schema is used - its configuration is ignored.
237
+ * This is useful for creating reusable field collections that can be added to different schemas.
238
+ *
239
+ * @param schemaOrValidator - Plain schema object or ObjectValidator to extend with
240
+ * @returns A new ObjectValidator with merged schema and original configuration
241
+ *
242
+ * @example
243
+ * ```ts
244
+ * // Extend with plain schema
245
+ * const baseUser = v.object({
246
+ * name: v.string().required(),
247
+ * email: v.string().email().required()
248
+ * }).allowUnknown();
249
+ *
250
+ * const adminUser = baseUser.extend({
251
+ * role: v.string().in(['admin', 'superadmin']).required()
252
+ * });
253
+ * // adminUser has: name, email, role
254
+ * // adminUser keeps: allowUnknown() from base ✅
255
+ *
256
+ * // Extend with ObjectValidator (only schema is used)
257
+ * const auditFields = v.object({
258
+ * createdAt: v.date().required(),
259
+ * updatedAt: v.date().required()
260
+ * }).stripUnknown(); // This config is ignored!
261
+ *
262
+ * const fullUser = baseUser.extend(auditFields);
263
+ * // fullUser has: name, email, createdAt, updatedAt
264
+ * // fullUser keeps: allowUnknown() from base (NOT stripUnknown from auditFields) ✅
265
+ *
266
+ * // Chain multiple extends
267
+ * const complexSchema = baseUser
268
+ * .extend(auditFields)
269
+ * .extend({ metadata: v.object({}) });
270
+ * ```
271
+ */
272
+ extend(schemaOrValidator) {
273
+ const extended = this.clone();
274
+ const schemaToAdd = schemaOrValidator instanceof ObjectValidator ? schemaOrValidator.schema : schemaOrValidator;
275
+ for (const [key, validator] of Object.entries(schemaToAdd)) extended.schema[key] = validator.clone();
276
+ return extended;
277
+ }
278
+ /**
279
+ * Merge with another ObjectValidator
280
+ * Clones current validator, merges schemas, and **overrides configuration** with other validator's config
281
+ *
282
+ * Unlike extend(), merge() combines both schemas AND configurations.
283
+ * The other validator's configuration (allowUnknown, stripUnknown, etc.) takes precedence.
284
+ *
285
+ * @param validator - Another ObjectValidator to merge with
286
+ * @returns A new ObjectValidator with merged schema and configuration
287
+ *
288
+ * @example
289
+ * ```ts
290
+ * const baseUser = v.object({
291
+ * name: v.string().required()
292
+ * }).allowUnknown();
293
+ *
294
+ * const timestamps = v.object({
295
+ * createdAt: v.date().required(),
296
+ * updatedAt: v.date().required()
297
+ * }).stripUnknown();
298
+ *
299
+ * const merged = baseUser.merge(timestamps);
300
+ * // merged has: name, createdAt, updatedAt
301
+ * // merged config: stripUnknown() from timestamps (overrides allowUnknown) ✅
302
+ *
303
+ * // Chain multiple merges
304
+ * const full = baseUser.merge(timestamps).merge(softDeleteSchema);
305
+ * ```
306
+ */
307
+ merge(validator) {
308
+ const merged = this.clone();
309
+ for (const [key, schemaValidator] of Object.entries(validator.schema)) merged.schema[key] = schemaValidator.clone();
310
+ merged.shouldAllowUnknown = validator.shouldAllowUnknown;
311
+ merged.allowedKeys = [...merged.allowedKeys, ...validator.allowedKeys];
312
+ merged.rules.push(...validator.rules);
313
+ merged.mutators.push(...validator.mutators);
314
+ merged.dataTransformers.push(...validator.dataTransformers);
315
+ merged.attributesText = {
316
+ ...merged.attributesText,
317
+ ...validator.attributesText
318
+ };
319
+ merged.translatedAttributes = {
320
+ ...merged.translatedAttributes,
321
+ ...validator.translatedAttributes
322
+ };
323
+ return merged;
324
+ }
325
+ /**
326
+ * Create a new schema with only the specified fields
327
+ * Clones the current validator and keeps only the selected fields
328
+ * **Preserves all configuration** (allowUnknown, stripUnknown, etc.)
329
+ *
330
+ * @param keys - Field names to keep in the schema
331
+ * @returns A new ObjectValidator with only the picked fields
332
+ *
333
+ * @example
334
+ * ```ts
335
+ * const fullUser = v.object({
336
+ * id: v.int().required(),
337
+ * name: v.string().required(),
338
+ * email: v.string().email().required(),
339
+ * password: v.string().required(),
340
+ * role: v.string()
341
+ * }).allowUnknown();
342
+ *
343
+ * // For login - only need email and password
344
+ * const loginSchema = fullUser.pick('email', 'password');
345
+ * // loginSchema has: { email, password }
346
+ * // loginSchema keeps: allowUnknown() ✅
347
+ *
348
+ * // For public profile
349
+ * const publicSchema = fullUser.pick('id', 'name', 'role');
350
+ * // publicSchema has: { id, name, role }
351
+ * ```
352
+ */
353
+ pick(...keys) {
354
+ const picked = this.clone();
355
+ const newSchema = {};
356
+ for (const key of keys) if (key in picked.schema) newSchema[key] = picked.schema[key];
357
+ picked.schema = newSchema;
358
+ return picked;
359
+ }
360
+ /**
361
+ * Mark all or the given schema fields as optional
362
+ */
363
+ partial(...keys) {
364
+ const validationSchema = this.clone();
365
+ if (keys.length === 0) keys = Object.keys(validationSchema.schema);
366
+ for (const [key, validator] of Object.entries(validationSchema.schema)) if (keys.length === 0 || keys.includes(key)) validationSchema.schema[key] = validator.optional();
367
+ return validationSchema;
368
+ }
369
+ /**
370
+ * Make the all or the given fields as required
371
+ */
372
+ requiredFields(...keys) {
373
+ const validationSchema = this.clone();
374
+ if (keys.length === 0) keys = Object.keys(validationSchema.schema);
375
+ for (const [key, validator] of Object.entries(validationSchema.schema)) if (keys.length === 0 || keys.includes(key)) validationSchema.schema[key] = validator.required();
376
+ return validationSchema;
377
+ }
378
+ /**
379
+ * Create a new schema excluding the specified fields
380
+ * Clones the current validator and removes the specified fields
381
+ * **Preserves all configuration** (allowUnknown, stripUnknown, etc.)
382
+ *
383
+ * @param keys - Field names to exclude from the schema
384
+ * @returns A new ObjectValidator without the excluded fields
385
+ *
386
+ * @example
387
+ * ```ts
388
+ * const fullUser = v.object({
389
+ * id: v.int().required(),
390
+ * name: v.string().required(),
391
+ * email: v.string().email().required(),
392
+ * password: v.string().required(),
393
+ * role: v.string()
394
+ * }).allowUnknown();
395
+ *
396
+ * // For updates - exclude id
397
+ * const updateSchema = fullUser.without('id');
398
+ * // updateSchema has: { name, email, password, role }
399
+ * // updateSchema keeps: allowUnknown() ✅
400
+ *
401
+ * // For public API - exclude sensitive fields
402
+ * const publicSchema = fullUser.without('password', 'role');
403
+ * // publicSchema has: { id, name, email }
404
+ *
405
+ * // Combine with other methods
406
+ * const patchSchema = fullUser.without('id', 'password');
407
+ * // patchSchema has: { name, email, role }
408
+ * ```
409
+ */
410
+ without(...keys) {
411
+ const filtered = this.clone();
412
+ const newSchema = {};
413
+ for (const key in filtered.schema) if (!keys.includes(key)) newSchema[key] = filtered.schema[key];
414
+ filtered.schema = newSchema;
415
+ return filtered;
416
+ }
417
+ /** Mutate the data */
418
+ mutate(data, context) {
419
+ if (!(0, _mongez_supportive_is.isPlainObject)(data)) return data;
420
+ return super.mutate({ ...data }, context);
421
+ }
422
+ /** Validate the data */
423
+ async validate(data, context = { path: "" }) {
424
+ context.schema = this.schema;
425
+ const mutatedData = await this.mutate(data, context);
426
+ if (this.shouldAllowUnknown === false && !this.hasUnknownKeyRule) {
427
+ this.hasUnknownKeyRule = true;
428
+ const rule = this.addMutableRule(require_required_methods.unknownKeyRule, void 0, {
429
+ allowedKeys: this.allowedKeys,
430
+ schema: this.schema
431
+ });
432
+ this.setRuleAttributesList(rule);
433
+ }
434
+ const result = await super.validate(mutatedData, context);
435
+ if (result.isValid === false) return result;
436
+ if (data === void 0) return result;
437
+ const errors = [];
438
+ const validatedData = {};
439
+ const validationPromises = Object.entries(this.schema).filter(([, validator]) => !this.isComputedValidator(validator)).map(async ([key, validator]) => {
440
+ const value = mutatedData?.[key] !== void 0 ? mutatedData[key] : validator.getDefaultValue();
441
+ const childContext = {
442
+ ...context,
443
+ parent: mutatedData,
444
+ value,
445
+ key,
446
+ path: require_required_methods.setKeyPath(context.path, key)
447
+ };
448
+ const childResult = await validator.validate(value, childContext);
449
+ if (childResult.data !== void 0 && !validator.isOmitted()) validatedData[key] = childResult.data;
450
+ if (childResult.isValid === false) errors.push(...childResult.errors);
451
+ });
452
+ await Promise.all(validationPromises);
453
+ if (errors.length > 0) return {
454
+ isValid: false,
455
+ errors,
456
+ data: void 0
457
+ };
458
+ const computedFields = this.getComputedFields();
459
+ const computedPromises = Object.entries(computedFields).map(async ([key, validator]) => {
460
+ const childContext = {
461
+ ...context,
462
+ parent: validatedData,
463
+ value: void 0
464
+ };
465
+ const childResult = await validator.validate(validatedData, childContext);
466
+ if (childResult.data !== void 0 && !validator.isOmitted()) validatedData[key] = childResult.data;
467
+ if (childResult.isValid === false) errors.push(...childResult.errors);
468
+ });
469
+ await Promise.all(computedPromises);
470
+ if (errors.length > 0) return {
471
+ isValid: false,
472
+ errors,
473
+ data: void 0
474
+ };
475
+ const cleanedData = removeUndefinedValues(validatedData);
476
+ const transformedData = await this.startTransformationPipeline(cleanedData, context);
477
+ return {
478
+ isValid: true,
479
+ errors: [],
480
+ data: this.shouldAllowUnknown === false ? transformedData : {
481
+ ...transformedData,
482
+ ...(0, _mongez_reinforcements.except)(mutatedData, Object.keys(this.schema))
483
+ }
484
+ };
485
+ }
486
+ /**
487
+ * Check if a validator is a computed or managed field
488
+ * ManagedValidator extends ComputedValidator, so instanceof catches both
489
+ */
490
+ isComputedValidator(validator) {
491
+ return validator instanceof ComputedValidator;
492
+ }
493
+ /**
494
+ * Get all computed/managed fields from the schema
495
+ */
496
+ getComputedFields() {
497
+ const computed = {};
498
+ for (const [key, validator] of Object.entries(this.schema)) if (validator instanceof ComputedValidator) computed[key] = validator;
499
+ return computed;
500
+ }
501
+ /**
502
+ * @inheritdoc
503
+ *
504
+ * Recursively generates JSON Schema for all input fields in the schema.
505
+ * Computed/managed fields are skipped — they have no input representation.
506
+ *
507
+ * **Standard targets** (`draft-2020-12`, `draft-07`, `openapi-3.0`):
508
+ * - Fields marked `.optional()` are excluded from `required`.
509
+ *
510
+ * **`openai-strict` target** (OpenAI Structured Outputs):
511
+ * - ALL fields appear in `required` — OpenAI rejects schemas with optional fields.
512
+ * - Optional fields are instead expressed as nullable types:
513
+ * `{ type: ["string", "null"] }` so the model can output `null` for them.
514
+ * - Recursively applies `openai-strict` to all nested objects.
515
+ *
516
+ * @example
517
+ * ```ts
518
+ * v.object({
519
+ * name: v.string().required(),
520
+ * age: v.int().optional(),
521
+ * }).toJsonSchema("draft-2020-12")
522
+ * // → { type: "object",
523
+ * // properties: { name: { type: "string" }, age: { type: "integer" } },
524
+ * // required: ["name"], additionalProperties: false }
525
+ *
526
+ * v.object({
527
+ * name: v.string().required(),
528
+ * age: v.int().optional(),
529
+ * }).toJsonSchema("openai-strict")
530
+ * // → { type: "object",
531
+ * // properties: { name: { type: "string" }, age: { type: ["integer", "null"] } },
532
+ * // required: ["name", "age"], ← all fields
533
+ * // additionalProperties: false }
534
+ * ```
535
+ */
536
+ toJsonSchema(target = "draft-2020-12") {
537
+ const properties = {};
538
+ const required = [];
539
+ const isOpenAIStrict = target === "openai-strict";
540
+ for (const [key, validator] of Object.entries(this.schema)) {
541
+ if (validator instanceof ComputedValidator) continue;
542
+ let fieldSchema = validator.toJsonSchema(target);
543
+ if (isOpenAIStrict) {
544
+ if (validator.isOptional) fieldSchema = require_required_methods.wrapNullableStrict(fieldSchema);
545
+ required.push(key);
546
+ } else if (!validator.isOptional) required.push(key);
547
+ properties[key] = fieldSchema;
548
+ }
549
+ const schema = {
550
+ type: "object",
551
+ properties
552
+ };
553
+ if (required.length > 0) schema.required = required;
554
+ if (!this.shouldAllowUnknown) schema.additionalProperties = false;
555
+ if (this.isNullable) require_required_methods.applyNullable(schema, target);
556
+ return schema;
557
+ }
558
+ };
559
+ /** Recursively remove undefined values from an object */
560
+ function removeUndefinedValues(obj, visited = /* @__PURE__ */ new WeakMap()) {
561
+ if (obj === null) return obj;
562
+ if (Array.isArray(obj)) return obj.map((item) => removeUndefinedValues(item, visited));
563
+ if (!(0, _mongez_supportive_is.isPlainObject)(obj)) return obj;
564
+ if (visited.has(obj)) return visited.get(obj);
565
+ const result = {};
566
+ visited.set(obj, result);
567
+ for (const [key, value] of Object.entries(obj)) if (value !== void 0) result[key] = removeUndefinedValues(value, visited);
568
+ return result;
569
+ }
570
+
571
+ //#endregion
572
+ //#region ../seal/src/object.ts
573
+ /** Create an object schema without importing the complete `v` factory. */
574
+ const object = (schema, errorMessage) => new ObjectValidator(schema, errorMessage);
575
+
576
+ //#endregion
577
+ Object.defineProperty(exports, 'ComputedValidator', {
578
+ enumerable: true,
579
+ get: function () {
580
+ return ComputedValidator;
581
+ }
582
+ });
583
+ Object.defineProperty(exports, 'ObjectValidator', {
584
+ enumerable: true,
585
+ get: function () {
586
+ return ObjectValidator;
587
+ }
588
+ });
589
+ Object.defineProperty(exports, 'jsonMutator', {
590
+ enumerable: true,
591
+ get: function () {
592
+ return jsonMutator;
593
+ }
594
+ });
595
+ Object.defineProperty(exports, 'object', {
596
+ enumerable: true,
597
+ get: function () {
598
+ return object;
599
+ }
600
+ });
601
+ Object.defineProperty(exports, 'objectTrimMutator', {
602
+ enumerable: true,
603
+ get: function () {
604
+ return objectTrimMutator;
605
+ }
606
+ });
607
+ Object.defineProperty(exports, 'stripUnknownMutator', {
608
+ enumerable: true,
609
+ get: function () {
610
+ return stripUnknownMutator;
611
+ }
612
+ });
613
+ //# sourceMappingURL=object-_2YHdBxJ.cjs.map