unischema 1.0.1 → 1.2.0

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 (70) hide show
  1. package/README.md +780 -228
  2. package/dist/adapters/backend/index.d.mts +2 -1
  3. package/dist/adapters/backend/index.d.ts +2 -1
  4. package/dist/adapters/backend/index.js +17 -441
  5. package/dist/adapters/backend/index.mjs +9 -433
  6. package/dist/adapters/frontend/index.d.mts +2 -1
  7. package/dist/adapters/frontend/index.d.ts +2 -1
  8. package/dist/adapters/frontend/index.js +10 -421
  9. package/dist/adapters/frontend/index.mjs +8 -419
  10. package/dist/chunk-5A4ITJVD.mjs +124 -0
  11. package/dist/chunk-66RFUBVU.js +131 -0
  12. package/dist/chunk-75YSYC4K.mjs +85 -0
  13. package/dist/chunk-76BBWQDH.js +90 -0
  14. package/dist/chunk-7XES4A3M.mjs +237 -0
  15. package/dist/chunk-BVRXGZLS.js +17 -0
  16. package/dist/chunk-COMVAVFU.mjs +335 -0
  17. package/dist/chunk-DT2TQZU7.js +796 -0
  18. package/dist/chunk-FPCCH55A.js +103 -0
  19. package/dist/chunk-IUXRLMET.js +206 -0
  20. package/dist/chunk-JEW6U6CB.js +353 -0
  21. package/dist/chunk-KZCV5IW4.mjs +97 -0
  22. package/dist/chunk-KZZ7NVU3.mjs +41 -0
  23. package/dist/chunk-MFEBMQAU.mjs +779 -0
  24. package/dist/chunk-OIYG5D2I.js +50 -0
  25. package/dist/chunk-RW6HDA5H.mjs +194 -0
  26. package/dist/chunk-TTK77YBI.mjs +15 -0
  27. package/dist/chunk-TXT36BCE.js +248 -0
  28. package/dist/index-C17xs-fU.d.mts +140 -0
  29. package/dist/index-C17xs-fU.d.ts +140 -0
  30. package/dist/index.d.mts +26 -7
  31. package/dist/index.d.ts +26 -7
  32. package/dist/index.js +769 -499
  33. package/dist/index.mjs +695 -487
  34. package/dist/{schema-D9DGC9E_.d.ts → schema-DYE8Wz8X.d.mts} +264 -79
  35. package/dist/{schema-D9DGC9E_.d.mts → schema-Dtp-joeT.d.ts} +264 -79
  36. package/dist/validators/array.d.mts +15 -0
  37. package/dist/validators/array.d.ts +15 -0
  38. package/dist/validators/array.js +31 -0
  39. package/dist/validators/array.mjs +2 -0
  40. package/dist/validators/common.d.mts +13 -0
  41. package/dist/validators/common.d.ts +13 -0
  42. package/dist/validators/common.js +27 -0
  43. package/dist/validators/common.mjs +2 -0
  44. package/dist/validators/date.d.mts +23 -0
  45. package/dist/validators/date.d.ts +23 -0
  46. package/dist/validators/date.js +47 -0
  47. package/dist/validators/date.mjs +2 -0
  48. package/dist/validators/index.d.mts +46 -0
  49. package/dist/validators/index.d.ts +46 -0
  50. package/dist/validators/index.js +256 -0
  51. package/dist/validators/index.mjs +7 -0
  52. package/dist/validators/number.d.mts +25 -0
  53. package/dist/validators/number.d.ts +25 -0
  54. package/dist/validators/number.js +51 -0
  55. package/dist/validators/number.mjs +2 -0
  56. package/dist/validators/object.d.mts +11 -0
  57. package/dist/validators/object.d.ts +11 -0
  58. package/dist/validators/object.js +23 -0
  59. package/dist/validators/object.mjs +2 -0
  60. package/dist/validators/string.d.mts +37 -0
  61. package/dist/validators/string.d.ts +37 -0
  62. package/dist/validators/string.js +75 -0
  63. package/dist/validators/string.mjs +2 -0
  64. package/package.json +82 -5
  65. package/dist/adapters/backend/index.js.map +0 -1
  66. package/dist/adapters/backend/index.mjs.map +0 -1
  67. package/dist/adapters/frontend/index.js.map +0 -1
  68. package/dist/adapters/frontend/index.mjs.map +0 -1
  69. package/dist/index.js.map +0 -1
  70. package/dist/index.mjs.map +0 -1
package/dist/index.js CHANGED
@@ -1,470 +1,14 @@
1
1
  'use strict';
2
2
 
3
- // src/core/validators.ts
4
- function createError(context, code, message, soft = false) {
5
- return {
6
- field: context.path,
7
- code,
8
- message,
9
- severity: soft ? "soft" : "hard"
10
- };
11
- }
12
- var typeValidators = {
13
- string: (value, _params, context) => {
14
- if (value !== void 0 && value !== null && typeof value !== "string") {
15
- return createError(context, "INVALID_TYPE", `Expected string, got ${typeof value}`);
16
- }
17
- return null;
18
- },
19
- number: (value, _params, context) => {
20
- if (value !== void 0 && value !== null && typeof value !== "number") {
21
- return createError(context, "INVALID_TYPE", `Expected number, got ${typeof value}`);
22
- }
23
- if (typeof value === "number" && isNaN(value)) {
24
- return createError(context, "INVALID_NUMBER", "Value is not a valid number");
25
- }
26
- return null;
27
- },
28
- boolean: (value, _params, context) => {
29
- if (value !== void 0 && value !== null && typeof value !== "boolean") {
30
- return createError(context, "INVALID_TYPE", `Expected boolean, got ${typeof value}`);
31
- }
32
- return null;
33
- },
34
- date: (value, _params, context) => {
35
- if (value === void 0 || value === null) return null;
36
- if (value instanceof Date) {
37
- if (isNaN(value.getTime())) {
38
- return createError(context, "INVALID_DATE", "Invalid date value");
39
- }
40
- return null;
41
- }
42
- if (typeof value === "string") {
43
- const parsed = new Date(value);
44
- if (isNaN(parsed.getTime())) {
45
- return createError(context, "INVALID_DATE", "Invalid date format");
46
- }
47
- return null;
48
- }
49
- return createError(context, "INVALID_TYPE", `Expected date, got ${typeof value}`);
50
- },
51
- array: (value, _params, context) => {
52
- if (value !== void 0 && value !== null && !Array.isArray(value)) {
53
- return createError(context, "INVALID_TYPE", `Expected array, got ${typeof value}`);
54
- }
55
- return null;
56
- },
57
- object: (value, _params, context) => {
58
- if (value !== void 0 && value !== null) {
59
- if (typeof value !== "object" || Array.isArray(value)) {
60
- return createError(context, "INVALID_TYPE", `Expected object, got ${typeof value}`);
61
- }
62
- }
63
- return null;
64
- }
65
- };
66
- var ruleValidators = {
67
- required: (value, _params, context) => {
68
- const isEmpty = value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
69
- if (isEmpty) {
70
- return createError(context, "REQUIRED", "This field is required");
71
- }
72
- return null;
73
- },
74
- min: (value, params, context) => {
75
- const min = params?.value;
76
- const soft = params?.soft;
77
- const message = params?.message;
78
- if (value === void 0 || value === null) return null;
79
- if (typeof value === "number") {
80
- if (value < min) {
81
- return createError(
82
- context,
83
- "MIN_VALUE",
84
- message || `Value must be at least ${min}`,
85
- soft
86
- );
87
- }
88
- }
89
- if (typeof value === "string") {
90
- if (value.length < min) {
91
- return createError(
92
- context,
93
- "MIN_LENGTH",
94
- message || `Must be at least ${min} characters`,
95
- soft
96
- );
97
- }
98
- }
99
- if (Array.isArray(value)) {
100
- if (value.length < min) {
101
- return createError(
102
- context,
103
- "MIN_ITEMS",
104
- message || `Must have at least ${min} items`,
105
- soft
106
- );
107
- }
108
- }
109
- return null;
110
- },
111
- max: (value, params, context) => {
112
- const max = params?.value;
113
- const soft = params?.soft;
114
- const message = params?.message;
115
- if (value === void 0 || value === null) return null;
116
- if (typeof value === "number") {
117
- if (value > max) {
118
- return createError(
119
- context,
120
- "MAX_VALUE",
121
- message || `Value must be at most ${max}`,
122
- soft
123
- );
124
- }
125
- }
126
- if (typeof value === "string") {
127
- if (value.length > max) {
128
- return createError(
129
- context,
130
- "MAX_LENGTH",
131
- message || `Must be at most ${max} characters`,
132
- soft
133
- );
134
- }
135
- }
136
- if (Array.isArray(value)) {
137
- if (value.length > max) {
138
- return createError(
139
- context,
140
- "MAX_ITEMS",
141
- message || `Must have at most ${max} items`,
142
- soft
143
- );
144
- }
145
- }
146
- return null;
147
- },
148
- email: (value, params, context) => {
149
- if (value === void 0 || value === null || value === "") return null;
150
- const soft = params?.soft;
151
- const message = params?.message;
152
- if (typeof value !== "string") {
153
- return createError(context, "INVALID_EMAIL", "Email must be a string", soft);
154
- }
155
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
156
- if (!emailRegex.test(value)) {
157
- return createError(
158
- context,
159
- "INVALID_EMAIL",
160
- message || "Invalid email address",
161
- soft
162
- );
163
- }
164
- return null;
165
- },
166
- pattern: (value, params, context) => {
167
- if (value === void 0 || value === null || value === "") return null;
168
- const pattern = params?.pattern;
169
- const soft = params?.soft;
170
- const message = params?.message;
171
- if (typeof value !== "string") return null;
172
- const regex = new RegExp(pattern);
173
- if (!regex.test(value)) {
174
- return createError(
175
- context,
176
- "PATTERN_MISMATCH",
177
- message || `Value does not match required pattern`,
178
- soft
179
- );
180
- }
181
- return null;
182
- },
183
- url: (value, params, context) => {
184
- if (value === void 0 || value === null || value === "") return null;
185
- const soft = params?.soft;
186
- const message = params?.message;
187
- if (typeof value !== "string") {
188
- return createError(context, "INVALID_URL", "URL must be a string", soft);
189
- }
190
- try {
191
- new URL(value);
192
- return null;
193
- } catch {
194
- return createError(
195
- context,
196
- "INVALID_URL",
197
- message || "Invalid URL format",
198
- soft
199
- );
200
- }
201
- },
202
- ipAddress: (value, params, context) => {
203
- if (value === void 0 || value === null || value === "") return null;
204
- const soft = params?.soft;
205
- const message = params?.message;
206
- if (typeof value !== "string") {
207
- return createError(context, "INVALID_IP", "IP address must be a string", soft);
208
- }
209
- const ipv4Pattern = /^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
210
- if (!ipv4Pattern.test(value)) {
211
- return createError(
212
- context,
213
- "INVALID_IP",
214
- message || "Invalid IP address format",
215
- soft
216
- );
217
- }
218
- return null;
219
- },
220
- enum: (value, params, context) => {
221
- if (value === void 0 || value === null) return null;
222
- const values = params?.values;
223
- const soft = params?.soft;
224
- const message = params?.message;
225
- if (!values.includes(value)) {
226
- return createError(
227
- context,
228
- "INVALID_ENUM",
229
- message || `Value must be one of: ${values.join(", ")}`,
230
- soft
231
- );
232
- }
233
- return null;
234
- },
235
- custom: (value, params, context) => {
236
- const validate2 = params?.validate;
237
- const soft = params?.soft;
238
- const message = params?.message;
239
- if (!validate2) return null;
240
- const result = validate2(value, context);
241
- if (typeof result === "boolean") {
242
- if (!result) {
243
- return createError(
244
- context,
245
- "CUSTOM_VALIDATION",
246
- message || "Validation failed",
247
- soft
248
- );
249
- }
250
- return null;
251
- }
252
- if (!result.valid) {
253
- return createError(
254
- context,
255
- "CUSTOM_VALIDATION",
256
- result.message || message || "Validation failed",
257
- soft
258
- );
259
- }
260
- return null;
261
- },
262
- // Enterprise patterns - matches field against another field
263
- matches: (value, params, context) => {
264
- if (value === void 0 || value === null) return null;
265
- const otherField = params?.field;
266
- const soft = params?.soft;
267
- const message = params?.message;
268
- const root = context.root;
269
- const otherValue = root[otherField];
270
- if (value !== otherValue) {
271
- return createError(
272
- context,
273
- "FIELD_MISMATCH",
274
- message || `Must match ${otherField}`,
275
- soft
276
- );
277
- }
278
- return null;
279
- },
280
- // Integer validation
281
- integer: (value, params, context) => {
282
- if (value === void 0 || value === null) return null;
283
- const soft = params?.soft;
284
- const message = params?.message;
285
- if (typeof value !== "number" || !Number.isInteger(value)) {
286
- return createError(
287
- context,
288
- "NOT_INTEGER",
289
- message || "Value must be an integer",
290
- soft
291
- );
292
- }
293
- return null;
294
- },
295
- // Positive number validation
296
- positive: (value, params, context) => {
297
- if (value === void 0 || value === null) return null;
298
- const soft = params?.soft;
299
- const message = params?.message;
300
- if (typeof value === "number" && value <= 0) {
301
- return createError(
302
- context,
303
- "NOT_POSITIVE",
304
- message || "Value must be positive",
305
- soft
306
- );
307
- }
308
- return null;
309
- },
310
- // Negative number validation
311
- negative: (value, params, context) => {
312
- if (value === void 0 || value === null) return null;
313
- const soft = params?.soft;
314
- const message = params?.message;
315
- if (typeof value === "number" && value >= 0) {
316
- return createError(
317
- context,
318
- "NOT_NEGATIVE",
319
- message || "Value must be negative",
320
- soft
321
- );
322
- }
323
- return null;
324
- }
325
- };
326
- var customValidators = /* @__PURE__ */ new Map();
327
- function registerValidator(name, validator) {
328
- customValidators.set(name, validator);
329
- }
330
- function getValidator(name) {
331
- return ruleValidators[name] ?? customValidators.get(name);
332
- }
333
- function getTypeValidator(type) {
334
- return typeValidators[type];
335
- }
336
-
337
- // src/core/engine.ts
338
- function validateField(fieldDef, value, context) {
339
- const errors = [];
340
- const typeValidator = getTypeValidator(fieldDef.type);
341
- if (typeValidator) {
342
- const typeError = typeValidator(value, void 0, context);
343
- if (typeError) {
344
- errors.push(typeError);
345
- return errors;
346
- }
347
- }
348
- if (fieldDef.required) {
349
- const requiredValidator = getValidator("required");
350
- if (requiredValidator) {
351
- const error = requiredValidator(value, void 0, context);
352
- if (error) {
353
- errors.push(error);
354
- return errors;
355
- }
356
- }
357
- } else if (value === void 0 || value === null || value === "") {
358
- return errors;
359
- }
360
- for (const rule of fieldDef.rules) {
361
- const validator = getValidator(rule.type);
362
- if (!validator) {
363
- console.warn(`Unknown validator: ${rule.type}`);
364
- continue;
365
- }
366
- const params = {
367
- ...rule.params,
368
- soft: rule.soft,
369
- message: rule.message
370
- };
371
- const error = validator(value, params, context);
372
- if (error) {
373
- errors.push(error);
374
- }
375
- }
376
- if (fieldDef.type === "object" && fieldDef.schema && value !== null && value !== void 0) {
377
- const nestedResult = validateSchema(fieldDef.schema, value, context.path, context.root);
378
- errors.push(...nestedResult.hardErrors, ...nestedResult.softErrors);
379
- }
380
- if (fieldDef.type === "array" && fieldDef.items && Array.isArray(value)) {
381
- for (let i = 0; i < value.length; i++) {
382
- const itemContext = {
383
- path: `${context.path}[${i}]`,
384
- root: context.root,
385
- parent: value
386
- };
387
- const itemErrors = validateField(fieldDef.items, value[i], itemContext);
388
- errors.push(...itemErrors);
389
- }
390
- }
391
- return errors;
392
- }
393
- function validateSchema(schema2, data, basePath = "", root) {
394
- const hardErrors = [];
395
- const softErrors = [];
396
- const rootData = root ?? data;
397
- for (const [fieldName, fieldDef] of Object.entries(schema2.fields)) {
398
- const value = data[fieldName];
399
- const path = basePath ? `${basePath}.${fieldName}` : fieldName;
400
- const context = {
401
- path,
402
- root: rootData,
403
- parent: data
404
- };
405
- const errors = validateField(fieldDef, value, context);
406
- for (const error of errors) {
407
- if (error.severity === "soft") {
408
- softErrors.push(error);
409
- } else {
410
- hardErrors.push(error);
411
- }
412
- }
413
- }
414
- return {
415
- valid: hardErrors.length === 0,
416
- hardErrors,
417
- softErrors
418
- };
419
- }
420
- function validate(schema2, data) {
421
- return validateSchema(schema2, data);
422
- }
423
- function isValid(schema2, data) {
424
- return validate(schema2, data).valid;
425
- }
426
- function assertValid(schema2, data) {
427
- const result = validate(schema2, data);
428
- if (!result.valid) {
429
- const error = new Error("Validation failed");
430
- error.errors = result.hardErrors;
431
- throw error;
432
- }
433
- return data;
434
- }
435
- function mergeResults(...results) {
436
- const hardErrors = [];
437
- const softErrors = [];
438
- for (const result of results) {
439
- hardErrors.push(...result.hardErrors);
440
- softErrors.push(...result.softErrors);
441
- }
442
- return {
443
- valid: hardErrors.length === 0,
444
- hardErrors,
445
- softErrors
446
- };
447
- }
448
- function validResult() {
449
- return {
450
- valid: true,
451
- hardErrors: [],
452
- softErrors: []
453
- };
454
- }
455
- function errorResult(field2, code, message, soft = false) {
456
- const error = {
457
- field: field2,
458
- code,
459
- message,
460
- severity: soft ? "soft" : "hard"
461
- };
462
- return {
463
- valid: soft,
464
- hardErrors: soft ? [] : [error],
465
- softErrors: soft ? [error] : []
466
- };
467
- }
3
+ var chunkBVRXGZLS_js = require('./chunk-BVRXGZLS.js');
4
+ var chunkDT2TQZU7_js = require('./chunk-DT2TQZU7.js');
5
+ require('./chunk-76BBWQDH.js');
6
+ require('./chunk-FPCCH55A.js');
7
+ require('./chunk-JEW6U6CB.js');
8
+ require('./chunk-IUXRLMET.js');
9
+ require('./chunk-TXT36BCE.js');
10
+ require('./chunk-66RFUBVU.js');
11
+ require('./chunk-OIYG5D2I.js');
468
12
 
469
13
  // src/schema/field.ts
470
14
  var BaseFieldBuilder = class {
@@ -472,6 +16,9 @@ var BaseFieldBuilder = class {
472
16
  this._rules = [];
473
17
  this._required = false;
474
18
  this._meta = {};
19
+ this._transforms = [];
20
+ this._nullable = false;
21
+ this._nullish = false;
475
22
  this._type = type;
476
23
  }
477
24
  /**
@@ -521,6 +68,59 @@ var BaseFieldBuilder = class {
521
68
  });
522
69
  return this;
523
70
  }
71
+ /**
72
+ * Add async custom validation
73
+ */
74
+ refineAsync(validate2, options) {
75
+ const opts = typeof options === "string" ? { message: options } : options || {};
76
+ this._rules.push({
77
+ type: "refineAsync",
78
+ params: { validate: validate2 },
79
+ message: opts.message,
80
+ soft: opts.soft,
81
+ async: true,
82
+ debounce: opts.debounce,
83
+ timeout: opts.timeout || 5e3
84
+ });
85
+ return this;
86
+ }
87
+ /**
88
+ * Add async soft validation (warning only)
89
+ */
90
+ refineAsyncSoft(validate2, options) {
91
+ const opts = typeof options === "string" ? { message: options } : options || {};
92
+ return this.refineAsync(validate2, { ...opts, soft: true });
93
+ }
94
+ /**
95
+ * Transform value before validation (applied after preprocessing)
96
+ */
97
+ transform(transformer) {
98
+ this._transforms.push(transformer);
99
+ return this;
100
+ }
101
+ /**
102
+ * Preprocess value before transformations and validation
103
+ * Useful for handling null/undefined values
104
+ */
105
+ preprocess(preprocessor) {
106
+ this._preprocess = preprocessor;
107
+ return this;
108
+ }
109
+ /**
110
+ * Allow null values
111
+ */
112
+ nullable() {
113
+ this._nullable = true;
114
+ return this;
115
+ }
116
+ /**
117
+ * Allow null or undefined values
118
+ */
119
+ nullish() {
120
+ this._nullish = true;
121
+ this._nullable = true;
122
+ return this;
123
+ }
524
124
  /**
525
125
  * Add field metadata
526
126
  */
@@ -528,6 +128,50 @@ var BaseFieldBuilder = class {
528
128
  this._meta = { ...this._meta, ...data };
529
129
  return this;
530
130
  }
131
+ /**
132
+ * Field must not match another field
133
+ */
134
+ notMatches(field2, message) {
135
+ this._rules.push({
136
+ type: "notMatches",
137
+ params: { field: field2 },
138
+ message
139
+ });
140
+ return this;
141
+ }
142
+ /**
143
+ * Field must be greater than another field (for numbers)
144
+ */
145
+ greaterThan(field2, message) {
146
+ this._rules.push({
147
+ type: "greaterThan",
148
+ params: { field: field2 },
149
+ message
150
+ });
151
+ return this;
152
+ }
153
+ /**
154
+ * Field must be less than another field (for numbers)
155
+ */
156
+ lessThan(field2, message) {
157
+ this._rules.push({
158
+ type: "lessThan",
159
+ params: { field: field2 },
160
+ message
161
+ });
162
+ return this;
163
+ }
164
+ /**
165
+ * Field depends on another field being set
166
+ */
167
+ dependsOn(field2, message) {
168
+ this._rules.push({
169
+ type: "dependsOn",
170
+ params: { field: field2 },
171
+ message
172
+ });
173
+ return this;
174
+ }
531
175
  /**
532
176
  * Build the field definition
533
177
  */
@@ -537,7 +181,11 @@ var BaseFieldBuilder = class {
537
181
  rules: [...this._rules],
538
182
  required: this._required,
539
183
  defaultValue: this._defaultValue,
540
- meta: Object.keys(this._meta).length > 0 ? this._meta : void 0
184
+ meta: Object.keys(this._meta).length > 0 ? this._meta : void 0,
185
+ transforms: this._transforms.length > 0 ? [...this._transforms] : void 0,
186
+ preprocess: this._preprocess,
187
+ nullable: this._nullable || void 0,
188
+ nullish: this._nullish || void 0
541
189
  };
542
190
  }
543
191
  };
@@ -621,6 +269,150 @@ var StringFieldBuilder = class extends BaseFieldBuilder {
621
269
  });
622
270
  return this;
623
271
  }
272
+ /**
273
+ * Validate as IPv6 address
274
+ */
275
+ ipv6(message) {
276
+ this._rules.push({
277
+ type: "ipv6",
278
+ message
279
+ });
280
+ return this;
281
+ }
282
+ /**
283
+ * Only alphabetic characters (a-zA-Z)
284
+ */
285
+ alpha(message) {
286
+ this._rules.push({
287
+ type: "alpha",
288
+ message
289
+ });
290
+ return this;
291
+ }
292
+ /**
293
+ * Only alphanumeric characters (a-zA-Z0-9)
294
+ */
295
+ alphanumeric(message) {
296
+ this._rules.push({
297
+ type: "alphanumeric",
298
+ message
299
+ });
300
+ return this;
301
+ }
302
+ /**
303
+ * Only numeric digits
304
+ */
305
+ numeric(message) {
306
+ this._rules.push({
307
+ type: "numeric",
308
+ message
309
+ });
310
+ return this;
311
+ }
312
+ /**
313
+ * Must be lowercase
314
+ */
315
+ lowercase(message) {
316
+ this._rules.push({
317
+ type: "lowercase",
318
+ message
319
+ });
320
+ return this;
321
+ }
322
+ /**
323
+ * Must be uppercase
324
+ */
325
+ uppercase(message) {
326
+ this._rules.push({
327
+ type: "uppercase",
328
+ message
329
+ });
330
+ return this;
331
+ }
332
+ /**
333
+ * URL-friendly slug (lowercase, alphanumeric, hyphens)
334
+ */
335
+ slug(message) {
336
+ this._rules.push({
337
+ type: "slug",
338
+ message
339
+ });
340
+ return this;
341
+ }
342
+ /**
343
+ * Hexadecimal string
344
+ */
345
+ hex(message) {
346
+ this._rules.push({
347
+ type: "hex",
348
+ message
349
+ });
350
+ return this;
351
+ }
352
+ /**
353
+ * Base64 encoded string
354
+ */
355
+ base64(message) {
356
+ this._rules.push({
357
+ type: "base64",
358
+ message
359
+ });
360
+ return this;
361
+ }
362
+ /**
363
+ * Valid JSON string
364
+ */
365
+ json(message) {
366
+ this._rules.push({
367
+ type: "json",
368
+ message
369
+ });
370
+ return this;
371
+ }
372
+ /**
373
+ * Exact length
374
+ */
375
+ length(len, message) {
376
+ this._rules.push({
377
+ type: "length",
378
+ params: { length: len },
379
+ message
380
+ });
381
+ return this;
382
+ }
383
+ /**
384
+ * Must contain substring
385
+ */
386
+ contains(substring, message) {
387
+ this._rules.push({
388
+ type: "contains",
389
+ params: { substring },
390
+ message
391
+ });
392
+ return this;
393
+ }
394
+ /**
395
+ * Must start with prefix
396
+ */
397
+ startsWith(prefix, message) {
398
+ this._rules.push({
399
+ type: "startsWith",
400
+ params: { prefix },
401
+ message
402
+ });
403
+ return this;
404
+ }
405
+ /**
406
+ * Must end with suffix
407
+ */
408
+ endsWith(suffix, message) {
409
+ this._rules.push({
410
+ type: "endsWith",
411
+ params: { suffix },
412
+ message
413
+ });
414
+ return this;
415
+ }
624
416
  /**
625
417
  * Match a regex pattern
626
418
  */
@@ -668,11 +460,11 @@ var StringFieldBuilder = class extends BaseFieldBuilder {
668
460
  }
669
461
  };
670
462
  var EnumFieldBuilder = class extends BaseFieldBuilder {
671
- constructor(values, rules = [], required = false, meta = {}) {
463
+ constructor(values, rules = [], required2 = false, meta = {}) {
672
464
  super("string");
673
465
  this._values = values;
674
466
  this._rules = [...rules];
675
- this._required = required;
467
+ this._required = required2;
676
468
  this._meta = { ...meta };
677
469
  }
678
470
  /**
@@ -784,6 +576,119 @@ var NumberFieldBuilder = class extends BaseFieldBuilder {
784
576
  });
785
577
  return this;
786
578
  }
579
+ /**
580
+ * Must be a valid port number (0-65535)
581
+ */
582
+ port(message) {
583
+ this._rules.push({
584
+ type: "port",
585
+ message
586
+ });
587
+ return this;
588
+ }
589
+ /**
590
+ * Must be a valid latitude (-90 to 90)
591
+ */
592
+ latitude(message) {
593
+ this._rules.push({
594
+ type: "latitude",
595
+ message
596
+ });
597
+ return this;
598
+ }
599
+ /**
600
+ * Must be a valid longitude (-180 to 180)
601
+ */
602
+ longitude(message) {
603
+ this._rules.push({
604
+ type: "longitude",
605
+ message
606
+ });
607
+ return this;
608
+ }
609
+ /**
610
+ * Must be a percentage (0-100)
611
+ */
612
+ percentage(message) {
613
+ this._rules.push({
614
+ type: "percentage",
615
+ message
616
+ });
617
+ return this;
618
+ }
619
+ /**
620
+ * Must be between min and max (inclusive)
621
+ */
622
+ between(min, max, message) {
623
+ this._rules.push({
624
+ type: "numberBetween",
625
+ params: { min, max },
626
+ message
627
+ });
628
+ return this;
629
+ }
630
+ /**
631
+ * Must be divisible by a number
632
+ */
633
+ divisibleBy(divisor, message) {
634
+ this._rules.push({
635
+ type: "divisibleBy",
636
+ params: { divisor },
637
+ message
638
+ });
639
+ return this;
640
+ }
641
+ /**
642
+ * Must be a multiple of a number
643
+ */
644
+ multipleOf(multiple, message) {
645
+ this._rules.push({
646
+ type: "multipleOf",
647
+ params: { multiple },
648
+ message
649
+ });
650
+ return this;
651
+ }
652
+ /**
653
+ * Must be an even number
654
+ */
655
+ even(message) {
656
+ this._rules.push({
657
+ type: "even",
658
+ message
659
+ });
660
+ return this;
661
+ }
662
+ /**
663
+ * Must be an odd number
664
+ */
665
+ odd(message) {
666
+ this._rules.push({
667
+ type: "odd",
668
+ message
669
+ });
670
+ return this;
671
+ }
672
+ /**
673
+ * Must be a safe integer
674
+ */
675
+ safe(message) {
676
+ this._rules.push({
677
+ type: "safe",
678
+ message
679
+ });
680
+ return this;
681
+ }
682
+ /**
683
+ * Must be a finite number
684
+ */
685
+ finite(message) {
686
+ this._rules.push({
687
+ type: "finite",
688
+ message
689
+ });
690
+ return this;
691
+ }
787
692
  /**
788
693
  * Add a soft validation with message
789
694
  */
@@ -916,6 +821,108 @@ var DateFieldBuilder = class extends BaseFieldBuilder {
916
821
  });
917
822
  return this;
918
823
  }
824
+ /**
825
+ * Must be today
826
+ */
827
+ today(message) {
828
+ this._rules.push({
829
+ type: "today",
830
+ message
831
+ });
832
+ return this;
833
+ }
834
+ /**
835
+ * Must be yesterday
836
+ */
837
+ yesterday(message) {
838
+ this._rules.push({
839
+ type: "yesterday",
840
+ message
841
+ });
842
+ return this;
843
+ }
844
+ /**
845
+ * Must be tomorrow
846
+ */
847
+ tomorrow(message) {
848
+ this._rules.push({
849
+ type: "tomorrow",
850
+ message
851
+ });
852
+ return this;
853
+ }
854
+ /**
855
+ * Must be within this week
856
+ */
857
+ thisWeek(message) {
858
+ this._rules.push({
859
+ type: "thisWeek",
860
+ message
861
+ });
862
+ return this;
863
+ }
864
+ /**
865
+ * Must be within this month
866
+ */
867
+ thisMonth(message) {
868
+ this._rules.push({
869
+ type: "thisMonth",
870
+ message
871
+ });
872
+ return this;
873
+ }
874
+ /**
875
+ * Must be within this year
876
+ */
877
+ thisYear(message) {
878
+ this._rules.push({
879
+ type: "thisYear",
880
+ message
881
+ });
882
+ return this;
883
+ }
884
+ /**
885
+ * Must be a weekday
886
+ */
887
+ weekday(message) {
888
+ this._rules.push({
889
+ type: "weekday",
890
+ message
891
+ });
892
+ return this;
893
+ }
894
+ /**
895
+ * Must be a weekend
896
+ */
897
+ weekend(message) {
898
+ this._rules.push({
899
+ type: "weekend",
900
+ message
901
+ });
902
+ return this;
903
+ }
904
+ /**
905
+ * Validate age is within range
906
+ */
907
+ age(min, max, message) {
908
+ this._rules.push({
909
+ type: "age",
910
+ params: { min, max },
911
+ message
912
+ });
913
+ return this;
914
+ }
915
+ /**
916
+ * Must be between two dates
917
+ */
918
+ between(start, end, message) {
919
+ this._rules.push({
920
+ type: "dateBetween",
921
+ params: { start, end },
922
+ message
923
+ });
924
+ return this;
925
+ }
919
926
  };
920
927
  var ArrayFieldBuilder = class extends BaseFieldBuilder {
921
928
  constructor(itemBuilder) {
@@ -979,6 +986,69 @@ var ArrayFieldBuilder = class extends BaseFieldBuilder {
979
986
  });
980
987
  return this;
981
988
  }
989
+ /**
990
+ * Must include a specific item
991
+ */
992
+ includes(item, message) {
993
+ this._rules.push({
994
+ type: "includes",
995
+ params: { item },
996
+ message
997
+ });
998
+ return this;
999
+ }
1000
+ /**
1001
+ * Must not include a specific item
1002
+ */
1003
+ excludes(item, message) {
1004
+ this._rules.push({
1005
+ type: "excludes",
1006
+ params: { item },
1007
+ message
1008
+ });
1009
+ return this;
1010
+ }
1011
+ /**
1012
+ * Must be empty
1013
+ */
1014
+ empty(message) {
1015
+ this._rules.push({
1016
+ type: "empty",
1017
+ message
1018
+ });
1019
+ return this;
1020
+ }
1021
+ /**
1022
+ * Must not be empty
1023
+ */
1024
+ notEmpty(message) {
1025
+ this._rules.push({
1026
+ type: "notEmpty",
1027
+ message
1028
+ });
1029
+ return this;
1030
+ }
1031
+ /**
1032
+ * Must be sorted
1033
+ */
1034
+ sorted(order = "asc", message) {
1035
+ this._rules.push({
1036
+ type: "sorted",
1037
+ params: { order },
1038
+ message
1039
+ });
1040
+ return this;
1041
+ }
1042
+ /**
1043
+ * Must not contain falsy values
1044
+ */
1045
+ compact(message) {
1046
+ this._rules.push({
1047
+ type: "compact",
1048
+ message
1049
+ });
1050
+ return this;
1051
+ }
982
1052
  build() {
983
1053
  return {
984
1054
  type: this._type,
@@ -986,7 +1056,11 @@ var ArrayFieldBuilder = class extends BaseFieldBuilder {
986
1056
  required: this._required,
987
1057
  defaultValue: this._defaultValue,
988
1058
  items: this._itemDef,
989
- meta: Object.keys(this._meta).length > 0 ? this._meta : void 0
1059
+ meta: Object.keys(this._meta).length > 0 ? this._meta : void 0,
1060
+ transforms: this._transforms.length > 0 ? [...this._transforms] : void 0,
1061
+ preprocess: this._preprocess,
1062
+ nullable: this._nullable || void 0,
1063
+ nullish: this._nullish || void 0
990
1064
  };
991
1065
  }
992
1066
  };
@@ -1006,10 +1080,80 @@ var ObjectFieldBuilder = class extends BaseFieldBuilder {
1006
1080
  required: this._required,
1007
1081
  defaultValue: this._defaultValue,
1008
1082
  schema: this._schema,
1009
- meta: Object.keys(this._meta).length > 0 ? this._meta : void 0
1083
+ meta: Object.keys(this._meta).length > 0 ? this._meta : void 0,
1084
+ transforms: this._transforms.length > 0 ? [...this._transforms] : void 0,
1085
+ preprocess: this._preprocess,
1086
+ nullable: this._nullable || void 0,
1087
+ nullish: this._nullish || void 0
1010
1088
  };
1011
1089
  }
1012
1090
  };
1091
+ var coerce = {
1092
+ /**
1093
+ * Coerce value to string
1094
+ */
1095
+ string() {
1096
+ return new StringFieldBuilder().preprocess((value) => {
1097
+ if (value === null || value === void 0) return value;
1098
+ return String(value);
1099
+ });
1100
+ },
1101
+ /**
1102
+ * Coerce value to number
1103
+ */
1104
+ number() {
1105
+ return new NumberFieldBuilder().preprocess((value) => {
1106
+ if (value === null || value === void 0) return value;
1107
+ if (typeof value === "number") return value;
1108
+ if (typeof value === "string") {
1109
+ const parsed = parseFloat(value);
1110
+ return isNaN(parsed) ? value : parsed;
1111
+ }
1112
+ if (typeof value === "boolean") return value ? 1 : 0;
1113
+ return value;
1114
+ });
1115
+ },
1116
+ /**
1117
+ * Coerce value to boolean
1118
+ */
1119
+ boolean() {
1120
+ return new BooleanFieldBuilder().preprocess((value) => {
1121
+ if (value === null || value === void 0) return value;
1122
+ if (typeof value === "boolean") return value;
1123
+ if (typeof value === "string") {
1124
+ const lower = value.toLowerCase().trim();
1125
+ if (lower === "true" || lower === "1" || lower === "yes" || lower === "on") return true;
1126
+ if (lower === "false" || lower === "0" || lower === "no" || lower === "off") return false;
1127
+ }
1128
+ if (typeof value === "number") return value !== 0;
1129
+ return value;
1130
+ });
1131
+ },
1132
+ /**
1133
+ * Coerce value to date
1134
+ */
1135
+ date() {
1136
+ return new DateFieldBuilder().preprocess((value) => {
1137
+ if (value === null || value === void 0) return value;
1138
+ if (value instanceof Date) return value;
1139
+ if (typeof value === "string" || typeof value === "number") {
1140
+ const date = new Date(value);
1141
+ return isNaN(date.getTime()) ? value : date;
1142
+ }
1143
+ return value;
1144
+ });
1145
+ },
1146
+ /**
1147
+ * Coerce value to array
1148
+ */
1149
+ array(itemBuilder) {
1150
+ return new ArrayFieldBuilder(itemBuilder).preprocess((value) => {
1151
+ if (value === null || value === void 0) return value;
1152
+ if (Array.isArray(value)) return value;
1153
+ return [value];
1154
+ });
1155
+ }
1156
+ };
1013
1157
 
1014
1158
  // src/schema/schema.ts
1015
1159
  function schema(fields) {
@@ -1060,6 +1204,86 @@ function partial(baseSchema) {
1060
1204
  }
1061
1205
  return schema(partialFields);
1062
1206
  }
1207
+ function deepPartial(baseSchema) {
1208
+ const deepPartialFields = {};
1209
+ for (const [key, builder] of Object.entries(baseSchema._fields)) {
1210
+ const clonedBuilder = Object.create(Object.getPrototypeOf(builder));
1211
+ Object.assign(clonedBuilder, builder);
1212
+ clonedBuilder._required = false;
1213
+ if (builder instanceof ObjectFieldBuilder) {
1214
+ const fieldDef = builder.build();
1215
+ if (fieldDef.schema) {
1216
+ const nestedFields = {};
1217
+ for (const [nestedKey, nestedDef] of Object.entries(fieldDef.schema.fields)) {
1218
+ const nestedBuilder = Object.create(BaseFieldBuilder.prototype);
1219
+ Object.assign(nestedBuilder, {
1220
+ _type: nestedDef.type,
1221
+ _rules: nestedDef.rules || [],
1222
+ _required: false,
1223
+ // Make optional
1224
+ _defaultValue: nestedDef.defaultValue,
1225
+ _meta: nestedDef.meta || {},
1226
+ _transforms: nestedDef.transforms || [],
1227
+ _preprocess: nestedDef.preprocess,
1228
+ _nullable: nestedDef.nullable || false,
1229
+ _nullish: nestedDef.nullish || false
1230
+ });
1231
+ nestedFields[nestedKey] = nestedBuilder;
1232
+ }
1233
+ const nestedSchema = schema(nestedFields);
1234
+ const deepNestedSchema = deepPartial(nestedSchema);
1235
+ clonedBuilder._schema = deepNestedSchema.definition;
1236
+ }
1237
+ }
1238
+ deepPartialFields[key] = clonedBuilder;
1239
+ }
1240
+ return schema(deepPartialFields);
1241
+ }
1242
+ function passthrough(baseSchema) {
1243
+ const result = schema(baseSchema._fields);
1244
+ result.definition.passthrough = true;
1245
+ return result;
1246
+ }
1247
+ function strict(baseSchema) {
1248
+ const result = schema(baseSchema._fields);
1249
+ result.definition.strict = true;
1250
+ return result;
1251
+ }
1252
+ function catchall(baseSchema, fieldBuilder) {
1253
+ const result = schema(baseSchema._fields);
1254
+ result.definition.catchall = fieldBuilder.build();
1255
+ return result;
1256
+ }
1257
+ function required(baseSchema, keys) {
1258
+ const keySet = new Set(keys);
1259
+ const newFields = {};
1260
+ for (const [key, builder] of Object.entries(baseSchema._fields)) {
1261
+ if (keySet.has(key)) {
1262
+ const clonedBuilder = Object.create(Object.getPrototypeOf(builder));
1263
+ Object.assign(clonedBuilder, builder);
1264
+ clonedBuilder._required = true;
1265
+ newFields[key] = clonedBuilder;
1266
+ } else {
1267
+ newFields[key] = builder;
1268
+ }
1269
+ }
1270
+ return schema(newFields);
1271
+ }
1272
+ function optional(baseSchema, keys) {
1273
+ const keySet = new Set(keys);
1274
+ const newFields = {};
1275
+ for (const [key, builder] of Object.entries(baseSchema._fields)) {
1276
+ if (keySet.has(key)) {
1277
+ const clonedBuilder = Object.create(Object.getPrototypeOf(builder));
1278
+ Object.assign(clonedBuilder, builder);
1279
+ clonedBuilder._required = false;
1280
+ newFields[key] = clonedBuilder;
1281
+ } else {
1282
+ newFields[key] = builder;
1283
+ }
1284
+ }
1285
+ return schema(newFields);
1286
+ }
1063
1287
  function merge(schema1, schema2) {
1064
1288
  return schema({
1065
1289
  ...schema1._fields,
@@ -1117,20 +1341,74 @@ var field = {
1117
1341
  }
1118
1342
  };
1119
1343
 
1120
- // src/types/index.ts
1121
- function toEnterpriseResponse(result, data) {
1122
- return {
1123
- status: result.valid ? "success" : "validation_error",
1124
- data: result.valid ? data : void 0,
1125
- errors: [...result.hardErrors, ...result.softErrors],
1126
- msg: result.valid ? "Validation successful" : "Validation failed",
1127
- validation: {
1128
- hard_validations: result.hardErrors,
1129
- soft_validations: result.softErrors
1130
- }
1131
- };
1132
- }
1133
-
1344
+ Object.defineProperty(exports, "toEnterpriseResponse", {
1345
+ enumerable: true,
1346
+ get: function () { return chunkBVRXGZLS_js.toEnterpriseResponse; }
1347
+ });
1348
+ Object.defineProperty(exports, "assertValid", {
1349
+ enumerable: true,
1350
+ get: function () { return chunkDT2TQZU7_js.assertValid; }
1351
+ });
1352
+ Object.defineProperty(exports, "assertValidAsync", {
1353
+ enumerable: true,
1354
+ get: function () { return chunkDT2TQZU7_js.assertValidAsync; }
1355
+ });
1356
+ Object.defineProperty(exports, "errorResult", {
1357
+ enumerable: true,
1358
+ get: function () { return chunkDT2TQZU7_js.errorResult; }
1359
+ });
1360
+ Object.defineProperty(exports, "getTypeValidator", {
1361
+ enumerable: true,
1362
+ get: function () { return chunkDT2TQZU7_js.getTypeValidator; }
1363
+ });
1364
+ Object.defineProperty(exports, "getValidator", {
1365
+ enumerable: true,
1366
+ get: function () { return chunkDT2TQZU7_js.getValidator; }
1367
+ });
1368
+ Object.defineProperty(exports, "isValid", {
1369
+ enumerable: true,
1370
+ get: function () { return chunkDT2TQZU7_js.isValid; }
1371
+ });
1372
+ Object.defineProperty(exports, "isValidAsync", {
1373
+ enumerable: true,
1374
+ get: function () { return chunkDT2TQZU7_js.isValidAsync; }
1375
+ });
1376
+ Object.defineProperty(exports, "mergeResults", {
1377
+ enumerable: true,
1378
+ get: function () { return chunkDT2TQZU7_js.mergeResults; }
1379
+ });
1380
+ Object.defineProperty(exports, "registerValidator", {
1381
+ enumerable: true,
1382
+ get: function () { return chunkDT2TQZU7_js.registerValidator; }
1383
+ });
1384
+ Object.defineProperty(exports, "ruleValidators", {
1385
+ enumerable: true,
1386
+ get: function () { return chunkDT2TQZU7_js.ruleValidators; }
1387
+ });
1388
+ Object.defineProperty(exports, "typeValidators", {
1389
+ enumerable: true,
1390
+ get: function () { return chunkDT2TQZU7_js.typeValidators; }
1391
+ });
1392
+ Object.defineProperty(exports, "validResult", {
1393
+ enumerable: true,
1394
+ get: function () { return chunkDT2TQZU7_js.validResult; }
1395
+ });
1396
+ Object.defineProperty(exports, "validate", {
1397
+ enumerable: true,
1398
+ get: function () { return chunkDT2TQZU7_js.validate; }
1399
+ });
1400
+ Object.defineProperty(exports, "validateAsync", {
1401
+ enumerable: true,
1402
+ get: function () { return chunkDT2TQZU7_js.validateAsync; }
1403
+ });
1404
+ Object.defineProperty(exports, "validateSchema", {
1405
+ enumerable: true,
1406
+ get: function () { return chunkDT2TQZU7_js.validateSchema; }
1407
+ });
1408
+ Object.defineProperty(exports, "validateSchemaAsync", {
1409
+ enumerable: true,
1410
+ get: function () { return chunkDT2TQZU7_js.validateSchemaAsync; }
1411
+ });
1134
1412
  exports.ArrayFieldBuilder = ArrayFieldBuilder;
1135
1413
  exports.BaseFieldBuilder = BaseFieldBuilder;
1136
1414
  exports.BooleanFieldBuilder = BooleanFieldBuilder;
@@ -1139,25 +1417,17 @@ exports.EnumFieldBuilder = EnumFieldBuilder;
1139
1417
  exports.NumberFieldBuilder = NumberFieldBuilder;
1140
1418
  exports.ObjectFieldBuilder = ObjectFieldBuilder;
1141
1419
  exports.StringFieldBuilder = StringFieldBuilder;
1142
- exports.assertValid = assertValid;
1143
- exports.errorResult = errorResult;
1420
+ exports.catchall = catchall;
1421
+ exports.coerce = coerce;
1422
+ exports.deepPartial = deepPartial;
1144
1423
  exports.extend = extend;
1145
1424
  exports.field = field;
1146
- exports.getTypeValidator = getTypeValidator;
1147
- exports.getValidator = getValidator;
1148
- exports.isValid = isValid;
1149
1425
  exports.merge = merge;
1150
- exports.mergeResults = mergeResults;
1151
1426
  exports.omit = omit;
1427
+ exports.optional = optional;
1152
1428
  exports.partial = partial;
1429
+ exports.passthrough = passthrough;
1153
1430
  exports.pick = pick;
1154
- exports.registerValidator = registerValidator;
1155
- exports.ruleValidators = ruleValidators;
1431
+ exports.required = required;
1156
1432
  exports.schema = schema;
1157
- exports.toEnterpriseResponse = toEnterpriseResponse;
1158
- exports.typeValidators = typeValidators;
1159
- exports.validResult = validResult;
1160
- exports.validate = validate;
1161
- exports.validateSchema = validateSchema;
1162
- //# sourceMappingURL=index.js.map
1163
- //# sourceMappingURL=index.js.map
1433
+ exports.strict = strict;