@stacksjs/bun-router 0.0.17 → 0.0.19

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 (153) hide show
  1. package/dist/chunk-2mx7fq49.js +4 -0
  2. package/dist/chunk-a8p83068.js +103 -0
  3. package/dist/{chunk-cgptvjdf.js → chunk-y3xq6wq6.js} +1 -1
  4. package/dist/cli.js +4 -3
  5. package/dist/container/index.js +1149 -211
  6. package/dist/container/service-provider.d.ts +3 -3
  7. package/dist/development/performance-profiler.d.ts +3 -3
  8. package/dist/development/route-debugger.d.ts +1 -1
  9. package/dist/development/route-inspector.d.ts +2 -2
  10. package/dist/index.js +369 -2209
  11. package/dist/observability/integration.d.ts +1 -1
  12. package/dist/response/macros.d.ts +1 -1
  13. package/dist/router/index.d.ts +7 -7
  14. package/dist/router/router.d.ts +0 -32
  15. package/dist/testing/performance-testing.d.ts +2 -2
  16. package/dist/testing/test-client.d.ts +1 -1
  17. package/dist/testing/websocket-testing.d.ts +1 -1
  18. package/package.json +7 -7
  19. package/dist/chunk-1ahs68ys.js +0 -18
  20. package/dist/chunk-g3ybefhg.js +0 -1923
  21. package/src/auth.ts +0 -489
  22. package/src/cache/lru-cache.ts +0 -457
  23. package/src/cache/middleware-memoization.ts +0 -531
  24. package/src/cache/route-cache-warmer.ts +0 -486
  25. package/src/cache/sqlite-cache.ts +0 -783
  26. package/src/cache/streaming-cache.ts +0 -572
  27. package/src/cli/colors.ts +0 -29
  28. package/src/cli/index.ts +0 -287
  29. package/src/cli/middleware.ts +0 -291
  30. package/src/cli/openapi.ts +0 -407
  31. package/src/cli/router.ts +0 -188
  32. package/src/cli/routes.ts +0 -265
  33. package/src/cli/utils.ts +0 -531
  34. package/src/cli.ts +0 -5
  35. package/src/config.ts +0 -322
  36. package/src/container/container.ts +0 -786
  37. package/src/container/contextual-binding.ts +0 -606
  38. package/src/container/decorators.ts +0 -368
  39. package/src/container/index.ts +0 -49
  40. package/src/container/service-provider.ts +0 -596
  41. package/src/development/hot-reload.ts +0 -673
  42. package/src/development/index.ts +0 -499
  43. package/src/development/performance-profiler.ts +0 -717
  44. package/src/development/route-debugger.ts +0 -527
  45. package/src/development/route-inspector.ts +0 -749
  46. package/src/development/typescript-utilities.ts +0 -682
  47. package/src/docs.ts +0 -397
  48. package/src/errors/circuit-breaker.ts +0 -733
  49. package/src/errors/error-handler.ts +0 -569
  50. package/src/errors/error-reporting.ts +0 -672
  51. package/src/errors/exceptions.ts +0 -536
  52. package/src/errors/graceful-degradation.ts +0 -623
  53. package/src/errors/index.ts +0 -21
  54. package/src/errors/router-errors.ts +0 -632
  55. package/src/file-serving/static-files.ts +0 -718
  56. package/src/index.ts +0 -66
  57. package/src/middleware/auth.ts +0 -220
  58. package/src/middleware/content_security_policy.ts +0 -215
  59. package/src/middleware/cors.ts +0 -142
  60. package/src/middleware/csrf.ts +0 -166
  61. package/src/middleware/ddos_protection.ts +0 -279
  62. package/src/middleware/file_security.ts +0 -191
  63. package/src/middleware/file_upload.ts +0 -275
  64. package/src/middleware/helmet.ts +0 -268
  65. package/src/middleware/index.ts +0 -117
  66. package/src/middleware/input_validation.ts +0 -453
  67. package/src/middleware/json_body.ts +0 -37
  68. package/src/middleware/performance_alerting.ts +0 -540
  69. package/src/middleware/performance_dashboard.ts +0 -661
  70. package/src/middleware/performance_monitor.ts +0 -945
  71. package/src/middleware/pipeline.ts +0 -489
  72. package/src/middleware/rate_limit.ts +0 -251
  73. package/src/middleware/request_id.ts +0 -36
  74. package/src/middleware/request_signing.ts +0 -638
  75. package/src/middleware/request_tracer.ts +0 -653
  76. package/src/middleware/response_cache.ts +0 -778
  77. package/src/middleware/security.ts +0 -482
  78. package/src/middleware/security_suite.ts +0 -257
  79. package/src/middleware/session.ts +0 -91
  80. package/src/model-binding/index.ts +0 -18
  81. package/src/model-binding/model-middleware.ts +0 -425
  82. package/src/model-binding/model-registry.ts +0 -550
  83. package/src/model-binding.ts +0 -370
  84. package/src/model-resolver-factory.ts +0 -106
  85. package/src/observability/correlation.ts +0 -691
  86. package/src/observability/health-checks.ts +0 -729
  87. package/src/observability/index.ts +0 -184
  88. package/src/observability/integration.ts +0 -548
  89. package/src/observability/metrics.ts +0 -753
  90. package/src/observability/tracing.ts +0 -638
  91. package/src/optimization/bun-utilities.ts +0 -778
  92. package/src/query-builder-integration.ts +0 -137
  93. package/src/request/context.ts +0 -109
  94. package/src/request/enhanced-request.ts +0 -876
  95. package/src/request/macros.ts +0 -822
  96. package/src/response/macros.ts +0 -665
  97. package/src/response/response-factory.ts +0 -596
  98. package/src/router/api-routes.ts +0 -243
  99. package/src/router/file-based-routing.ts +0 -697
  100. package/src/router/file-streaming.ts +0 -383
  101. package/src/router/fluent-routing.ts +0 -866
  102. package/src/router/group-organization.ts +0 -229
  103. package/src/router/handler-resolver.ts +0 -327
  104. package/src/router/http-methods.ts +0 -407
  105. package/src/router/index.ts +0 -193
  106. package/src/router/middleware-groups.ts +0 -222
  107. package/src/router/middleware-integration.ts +0 -399
  108. package/src/router/middleware.ts +0 -234
  109. package/src/router/model-binding.ts +0 -215
  110. package/src/router/optimized-route-matching.ts +0 -302
  111. package/src/router/route-building.ts +0 -221
  112. package/src/router/route-compiler.ts +0 -691
  113. package/src/router/route-matching.ts +0 -368
  114. package/src/router/route-trie.ts +0 -450
  115. package/src/router/router.ts +0 -1616
  116. package/src/router/server.ts +0 -684
  117. package/src/router/validation-integration.ts +0 -449
  118. package/src/router/view-rendering.ts +0 -233
  119. package/src/router/websocket.ts +0 -100
  120. package/src/routing/route-caching.ts +0 -402
  121. package/src/routing/route-throttling.ts +0 -469
  122. package/src/routing/subdomain-routing.ts +0 -492
  123. package/src/session/database-store.ts +0 -109
  124. package/src/session/file-store.ts +0 -148
  125. package/src/session/index.ts +0 -244
  126. package/src/session/memory-store.ts +0 -88
  127. package/src/session/redis-store.ts +0 -93
  128. package/src/streaming/index.ts +0 -17
  129. package/src/streaming/sse-handler.ts +0 -482
  130. package/src/streaming/stream-handler.ts +0 -552
  131. package/src/testing/auth-testing.ts +0 -448
  132. package/src/testing/file-upload-testing.ts +0 -543
  133. package/src/testing/index.ts +0 -10
  134. package/src/testing/middleware-testing.ts +0 -322
  135. package/src/testing/model-binding-testing.ts +0 -645
  136. package/src/testing/performance-testing.ts +0 -738
  137. package/src/testing/test-client.ts +0 -310
  138. package/src/testing/test-request.ts +0 -315
  139. package/src/testing/test-response.ts +0 -332
  140. package/src/testing/types.ts +0 -224
  141. package/src/testing/websocket-testing.ts +0 -590
  142. package/src/types/controller-types.ts +0 -385
  143. package/src/types/core.ts +0 -683
  144. package/src/types/middleware-types.ts +0 -422
  145. package/src/types/request-response-augmentation.ts +0 -489
  146. package/src/types/route-inference.ts +0 -372
  147. package/src/types.ts +0 -2123
  148. package/src/url.ts +0 -131
  149. package/src/utils/index.ts +0 -1
  150. package/src/utils/query-preservation.ts +0 -201
  151. package/src/utils.ts +0 -395
  152. package/src/validation/validator.ts +0 -688
  153. package/src/websocket/clustering.ts +0 -769
@@ -1,688 +0,0 @@
1
- /**
2
- * Request/Response Enhancements - Validation System
3
- *
4
- * Laravel-style validation with custom rules and error handling
5
- */
6
-
7
- import type { EnhancedRequest, NextFunction } from '../types'
8
- import { ValidationException } from '../errors/exceptions'
9
-
10
- // Hoisted email check. Pragmatic RFC 5322 approximation: requires one `@`,
11
- // a non-empty local part without surrounding/consecutive dots, and a domain
12
- // with at least one label dot and a 2+ char TLD. The previous regex
13
- // accepted addresses like `a@.com` and consecutive dots.
14
- const EMAIL_REGEX = /^[A-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[A-Z0-9](?:[A-Z0-9-]*[A-Z0-9])?(?:\.[A-Z0-9](?:[A-Z0-9-]*[A-Z0-9])?)*\.[A-Z]{2,}$/i
15
-
16
- export interface ValidationRule {
17
- name: string
18
- validate: (value: any, parameters: string[], field: string, data: Record<string, any>) => Promise<boolean> | boolean
19
- message: string | ((_field: string, _parameters: string[]) => string)
20
- }
21
-
22
- export interface ValidationRules {
23
- [field: string]: string | ValidationRule[]
24
- }
25
-
26
- export interface ValidationErrors {
27
- [field: string]: string[]
28
- }
29
-
30
- export interface ValidatorConfig {
31
- stopOnFirstFailure?: boolean
32
- customMessages?: Record<string, string>
33
- customAttributes?: Record<string, string>
34
- bail?: boolean
35
- }
36
-
37
- /**
38
- * Built-in validation rules
39
- */
40
- export const BuiltInRules: Record<string, ValidationRule> = {
41
- required: {
42
- name: 'required',
43
- validate: (value) => {
44
- if (value === null || value === undefined)
45
- return false
46
- if (typeof value === 'string')
47
- return value.trim().length > 0
48
- if (Array.isArray(value))
49
- return value.length > 0
50
- if (typeof value === 'object')
51
- return Object.keys(value).length > 0
52
- return true
53
- },
54
- message: 'The :field field is required.',
55
- },
56
-
57
- string: {
58
- name: 'string',
59
- validate: value => typeof value === 'string',
60
- message: 'The :field field must be a string.',
61
- },
62
-
63
- number: {
64
- name: 'number',
65
- validate: value => typeof value === 'number' && !Number.isNaN(value),
66
- message: 'The :field field must be a number.',
67
- },
68
-
69
- integer: {
70
- name: 'integer',
71
- validate: value => Number.isInteger(Number(value)),
72
- message: 'The :field field must be an integer.',
73
- },
74
-
75
- boolean: {
76
- name: 'boolean',
77
- validate: value => typeof value === 'boolean' || value === 'true' || value === 'false' || value === '1' || value === '0',
78
- message: 'The :field field must be true or false.',
79
- },
80
-
81
- email: {
82
- name: 'email',
83
- validate: value => typeof value === 'string' && EMAIL_REGEX.test(value),
84
- message: 'The :field field must be a valid email address.',
85
- },
86
-
87
- url: {
88
- name: 'url',
89
- validate: (value) => {
90
- try {
91
- const url = new URL(value)
92
- return Boolean(url)
93
- }
94
- catch {
95
- return false
96
- }
97
- },
98
- message: 'The :field field must be a valid URL.',
99
- },
100
-
101
- min: {
102
- name: 'min',
103
- validate: (value, parameters) => {
104
- const min = Number(parameters[0])
105
- if (typeof value === 'string')
106
- return value.length >= min
107
- if (typeof value === 'number')
108
- return value >= min
109
- if (Array.isArray(value))
110
- return value.length >= min
111
- return false
112
- },
113
- message: (field, parameters) => `The ${field} field must be at least ${parameters[0]} characters.`,
114
- },
115
-
116
- max: {
117
- name: 'max',
118
- validate: (value, parameters) => {
119
- const max = Number(parameters[0])
120
- if (typeof value === 'string')
121
- return value.length <= max
122
- if (typeof value === 'number')
123
- return value <= max
124
- if (Array.isArray(value))
125
- return value.length <= max
126
- return false
127
- },
128
- message: (field, parameters) => `The ${field} field must not exceed ${parameters[0]} characters.`,
129
- },
130
-
131
- between: {
132
- name: 'between',
133
- validate: (value, parameters) => {
134
- const min = Number(parameters[0])
135
- const max = Number(parameters[1])
136
- if (typeof value === 'string')
137
- return value.length >= min && value.length <= max
138
- if (typeof value === 'number')
139
- return value >= min && value <= max
140
- if (Array.isArray(value))
141
- return value.length >= min && value.length <= max
142
- return false
143
- },
144
- message: (field, parameters) => `The ${field} field must be between ${parameters[0]} and ${parameters[1]}.`,
145
- },
146
-
147
- in: {
148
- name: 'in',
149
- validate: (value, parameters) => parameters.includes(String(value)),
150
- message: (field, parameters) => `The ${field} field must be one of: ${parameters.join(', ')}.`,
151
- },
152
-
153
- notIn: {
154
- name: 'not_in',
155
- validate: (value, parameters) => !parameters.includes(String(value)),
156
- message: (field, parameters) => `The ${field} field must not be one of: ${parameters.join(', ')}.`,
157
- },
158
-
159
- regex: {
160
- name: 'regex',
161
- validate: (value, parameters) => {
162
- const pattern = new RegExp(parameters[0])
163
- return typeof value === 'string' && pattern.test(value)
164
- },
165
- message: 'The :field field format is invalid.',
166
- },
167
-
168
- alpha: {
169
- name: 'alpha',
170
- validate: value => typeof value === 'string' && /^[a-z]+$/i.test(value),
171
- message: 'The :field field must contain only letters.',
172
- },
173
-
174
- alphaNum: {
175
- name: 'alpha_num',
176
- validate: value => typeof value === 'string' && /^[a-z0-9]+$/i.test(value),
177
- message: 'The :field field must contain only letters and numbers.',
178
- },
179
-
180
- alphaDash: {
181
- name: 'alpha_dash',
182
- validate: value => typeof value === 'string' && /^[\w-]+$/.test(value),
183
- message: 'The :field field must contain only letters, numbers, dashes, and underscores.',
184
- },
185
-
186
- date: {
187
- name: 'date',
188
- validate: (value) => {
189
- const date = new Date(value)
190
- return !Number.isNaN(date.getTime())
191
- },
192
- message: 'The :field field must be a valid date.',
193
- },
194
-
195
- dateAfter: {
196
- name: 'after',
197
- validate: (value, parameters) => {
198
- const date = new Date(value)
199
- const afterDate = new Date(parameters[0])
200
- return !Number.isNaN(date.getTime()) && !Number.isNaN(afterDate.getTime()) && date > afterDate
201
- },
202
- message: (field, parameters) => `The ${field} field must be after ${parameters[0]}.`,
203
- },
204
-
205
- dateBefore: {
206
- name: 'before',
207
- validate: (value, parameters) => {
208
- const date = new Date(value)
209
- const beforeDate = new Date(parameters[0])
210
- return !Number.isNaN(date.getTime()) && !Number.isNaN(beforeDate.getTime()) && date < beforeDate
211
- },
212
- message: (field, parameters) => `The ${field} field must be before ${parameters[0]}.`,
213
- },
214
-
215
- confirmed: {
216
- name: 'confirmed',
217
- validate: (value, parameters, field, data) => {
218
- const confirmationField = parameters[0] || `${field}_confirmation`
219
- return value === data[confirmationField]
220
- },
221
- message: 'The :field confirmation does not match.',
222
- },
223
-
224
- same: {
225
- name: 'same',
226
- validate: (value, parameters, field, data) => {
227
- return value === data[parameters[0]]
228
- },
229
- message: (field, parameters) => `The ${field} field must match ${parameters[0]}.`,
230
- },
231
-
232
- different: {
233
- name: 'different',
234
- validate: (value, parameters, field, data) => {
235
- return value !== data[parameters[0]]
236
- },
237
- message: (field, parameters) => `The ${field} field must be different from ${parameters[0]}.`,
238
- },
239
-
240
- json: {
241
- name: 'json',
242
- validate: (value) => {
243
- try {
244
- JSON.parse(value)
245
- return true
246
- }
247
- catch {
248
- return false
249
- }
250
- },
251
- message: 'The :field field must be valid JSON.',
252
- },
253
-
254
- uuid: {
255
- name: 'uuid',
256
- validate: (value) => {
257
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i
258
- return typeof value === 'string' && uuidRegex.test(value)
259
- },
260
- message: 'The :field field must be a valid UUID.',
261
- },
262
-
263
- array: {
264
- name: 'array',
265
- validate: value => Array.isArray(value),
266
- message: 'The :field field must be an array.',
267
- },
268
-
269
- object: {
270
- name: 'object',
271
- validate: value => typeof value === 'object' && value !== null && !Array.isArray(value),
272
- message: 'The :field field must be an object.',
273
- },
274
- }
275
-
276
- /**
277
- * Database validation rules (require external implementation)
278
- */
279
- export const DatabaseRules: Record<string, ValidationRule> = {
280
- unique: {
281
- name: 'unique',
282
- validate: async (_value, _parameters) => {
283
- // This would need to be implemented with actual database queries
284
- // For now, return true as a placeholder
285
- console.warn('Database validation rule "unique" requires external implementation')
286
- return true
287
- },
288
- message: 'The :field field must be unique.',
289
- },
290
-
291
- exists: {
292
- name: 'exists',
293
- validate: async (_value, _parameters) => {
294
- // This would need to be implemented with actual database queries
295
- // For now, return true as a placeholder
296
- console.warn('Database validation rule "exists" requires external implementation')
297
- return true
298
- },
299
- message: 'The selected :field is invalid.',
300
- },
301
- }
302
-
303
- /**
304
- * Main validator class
305
- */
306
- export class Validator {
307
- private rules: Record<string, ValidationRule> = {}
308
- private config: ValidatorConfig
309
-
310
- constructor(config: ValidatorConfig = {}) {
311
- this.config = {
312
- stopOnFirstFailure: false,
313
- bail: false,
314
- ...config,
315
- }
316
-
317
- // Register built-in rules
318
- this.registerRules(BuiltInRules)
319
- }
320
-
321
- /**
322
- * Register validation rules
323
- */
324
- registerRule(rule: ValidationRule): void {
325
- this.rules[rule.name] = rule
326
- }
327
-
328
- /**
329
- * Register multiple validation rules
330
- */
331
- registerRules(rules: Record<string, ValidationRule>): void {
332
- Object.values(rules).forEach(rule => this.registerRule(rule))
333
- }
334
-
335
- /**
336
- * Parse validation rule string
337
- */
338
- private parseRuleString(ruleString: string): Array<{ name: string, parameters: string[] }> {
339
- return ruleString.split('|').map((rule) => {
340
- const [name, ...paramParts] = rule.split(':')
341
- const parameters = paramParts.length > 0 ? paramParts.join(':').split(',') : []
342
- return { name: name.trim(), parameters }
343
- })
344
- }
345
-
346
- /**
347
- * Validate data against rules
348
- */
349
- async validate(data: Record<string, any>, rules: ValidationRules): Promise<ValidationErrors> {
350
- const errors: ValidationErrors = {}
351
-
352
- for (const [field, fieldRules] of Object.entries(rules)) {
353
- const fieldErrors: string[] = []
354
- const value = this.getNestedValue(data, field)
355
-
356
- // Parse rules if they're in string format
357
- const parsedRules = typeof fieldRules === 'string'
358
- ? this.parseRuleString(fieldRules)
359
- : fieldRules.map(rule => ({ name: rule.name, parameters: [] }))
360
-
361
- for (const { name, parameters } of parsedRules) {
362
- const rule = this.rules[name]
363
- if (!rule) {
364
- console.warn(`Validation rule "${name}" not found`)
365
- continue
366
- }
367
-
368
- try {
369
- const isValid = await rule.validate(value, parameters, field, data)
370
-
371
- if (!isValid) {
372
- const message = this.formatErrorMessage(rule, field, parameters)
373
- fieldErrors.push(message)
374
-
375
- if (this.config.stopOnFirstFailure || this.config.bail) {
376
- break
377
- }
378
- }
379
- }
380
- catch (error) {
381
- console.error(`Error validating rule "${name}" for field "${field}":`, error)
382
- fieldErrors.push(`Validation error for ${field}`)
383
- }
384
- }
385
-
386
- if (fieldErrors.length > 0) {
387
- errors[field] = fieldErrors
388
- }
389
- }
390
-
391
- return errors
392
- }
393
-
394
- /**
395
- * Validate and throw exception if validation fails
396
- */
397
- async validateOrFail(data: Record<string, any>, rules: ValidationRules): Promise<void> {
398
- const errors = await this.validate(data, rules)
399
-
400
- if (Object.keys(errors).length > 0) {
401
- throw new ValidationException('Validation failed', errors)
402
- }
403
- }
404
-
405
- /**
406
- * Get nested value from object using dot notation
407
- */
408
- private getNestedValue(obj: Record<string, any>, path: string): any {
409
- return path.split('.').reduce((current, key) => {
410
- return current && current[key] !== undefined ? current[key] : undefined
411
- }, obj)
412
- }
413
-
414
- /**
415
- * Format error message
416
- */
417
- private formatErrorMessage(rule: ValidationRule, field: string, parameters: string[]): string {
418
- const customMessage = this.config.customMessages?.[`${field}.${rule.name}`]
419
- || this.config.customMessages?.[rule.name]
420
-
421
- if (customMessage) {
422
- return this.replacePlaceholders(customMessage, field, parameters)
423
- }
424
-
425
- const message = typeof rule.message === 'function'
426
- ? rule.message(field, parameters)
427
- : rule.message
428
-
429
- return this.replacePlaceholders(message, field, parameters)
430
- }
431
-
432
- /**
433
- * Replace placeholders in error messages
434
- */
435
- private replacePlaceholders(message: string, field: string, parameters: string[]): string {
436
- const fieldName = this.config.customAttributes?.[field] || field.replace(/_/g, ' ')
437
-
438
- return message
439
- .replace(/:field/g, fieldName)
440
- .replace(/:attribute/g, fieldName)
441
- .replace(/:value/g, parameters[0] || '')
442
- .replace(/:other/g, parameters[1] || '')
443
- }
444
- }
445
-
446
- /**
447
- * Global validator instance
448
- */
449
- export const globalValidator: Validator = new Validator()
450
-
451
- /**
452
- * Validation middleware factory
453
- */
454
- export function createValidationMiddleware(rules: ValidationRules, config?: ValidatorConfig) {
455
- const validator = new Validator(config)
456
-
457
- return async (req: EnhancedRequest, next: NextFunction): Promise<Response | null> => {
458
- try {
459
- // Get data from request body, query, and params
460
- const data = {
461
- ...req.query,
462
- ...req.params,
463
- ...(req.jsonBody || {}),
464
- ...(req.formBody || {}),
465
- }
466
-
467
- await validator.validateOrFail(data, rules)
468
-
469
- // Add validated data to request
470
- req.validated = data
471
-
472
- return await next()
473
- }
474
- catch (error) {
475
- if (error instanceof ValidationException) {
476
- throw error
477
- }
478
- throw new ValidationException('Validation error occurred')
479
- }
480
- }
481
- }
482
-
483
- /**
484
- * Validation rule builder for fluent API
485
- */
486
- export class ValidationRuleBuilder {
487
- private rules: string[] = []
488
-
489
- required(): this {
490
- this.rules.push('required')
491
- return this
492
- }
493
-
494
- string(): this {
495
- this.rules.push('string')
496
- return this
497
- }
498
-
499
- number(): this {
500
- this.rules.push('number')
501
- return this
502
- }
503
-
504
- integer(): this {
505
- this.rules.push('integer')
506
- return this
507
- }
508
-
509
- boolean(): this {
510
- this.rules.push('boolean')
511
- return this
512
- }
513
-
514
- email(): this {
515
- this.rules.push('email')
516
- return this
517
- }
518
-
519
- url(): this {
520
- this.rules.push('url')
521
- return this
522
- }
523
-
524
- min(value: number): this {
525
- this.rules.push(`min:${value}`)
526
- return this
527
- }
528
-
529
- max(value: number): this {
530
- this.rules.push(`max:${value}`)
531
- return this
532
- }
533
-
534
- between(min: number, max: number): this {
535
- this.rules.push(`between:${min},${max}`)
536
- return this
537
- }
538
-
539
- in(...values: string[]): this {
540
- this.rules.push(`in:${values.join(',')}`)
541
- return this
542
- }
543
-
544
- notIn(...values: string[]): this {
545
- this.rules.push(`not_in:${values.join(',')}`)
546
- return this
547
- }
548
-
549
- regex(pattern: string): this {
550
- this.rules.push(`regex:${pattern}`)
551
- return this
552
- }
553
-
554
- alpha(): this {
555
- this.rules.push('alpha')
556
- return this
557
- }
558
-
559
- alphaNum(): this {
560
- this.rules.push('alpha_num')
561
- return this
562
- }
563
-
564
- alphaDash(): this {
565
- this.rules.push('alpha_dash')
566
- return this
567
- }
568
-
569
- date(): this {
570
- this.rules.push('date')
571
- return this
572
- }
573
-
574
- after(date: string): this {
575
- this.rules.push(`after:${date}`)
576
- return this
577
- }
578
-
579
- before(date: string): this {
580
- this.rules.push(`before:${date}`)
581
- return this
582
- }
583
-
584
- confirmed(field?: string): this {
585
- this.rules.push(field ? `confirmed:${field}` : 'confirmed')
586
- return this
587
- }
588
-
589
- same(field: string): this {
590
- this.rules.push(`same:${field}`)
591
- return this
592
- }
593
-
594
- different(field: string): this {
595
- this.rules.push(`different:${field}`)
596
- return this
597
- }
598
-
599
- json(): this {
600
- this.rules.push('json')
601
- return this
602
- }
603
-
604
- uuid(): this {
605
- this.rules.push('uuid')
606
- return this
607
- }
608
-
609
- array(): this {
610
- this.rules.push('array')
611
- return this
612
- }
613
-
614
- object(): this {
615
- this.rules.push('object')
616
- return this
617
- }
618
-
619
- unique(table: string, column?: string): this {
620
- this.rules.push(column ? `unique:${table},${column}` : `unique:${table}`)
621
- return this
622
- }
623
-
624
- exists(table: string, column?: string): this {
625
- this.rules.push(column ? `exists:${table},${column}` : `exists:${table}`)
626
- return this
627
- }
628
-
629
- custom(ruleName: string, ...parameters: string[]): this {
630
- this.rules.push(parameters.length > 0 ? `${ruleName}:${parameters.join(',')}` : ruleName)
631
- return this
632
- }
633
-
634
- build(): string {
635
- return this.rules.join('|')
636
- }
637
- }
638
-
639
- /**
640
- * Factory function to create validation rule builder
641
- */
642
- export function rule(): ValidationRuleBuilder {
643
- return new ValidationRuleBuilder()
644
- }
645
-
646
- /**
647
- * Validation helper functions
648
- */
649
- export const ValidationHelpers = {
650
- /**
651
- * Create validation rules object
652
- */
653
- rules(rules: Record<string, string | ValidationRuleBuilder>): ValidationRules {
654
- const result: ValidationRules = {}
655
-
656
- for (const [field, fieldRules] of Object.entries(rules)) {
657
- result[field] = fieldRules instanceof ValidationRuleBuilder
658
- ? fieldRules.build()
659
- : fieldRules
660
- }
661
-
662
- return result
663
- },
664
-
665
- /**
666
- * Validate single value
667
- */
668
- async validateValue(value: any, rules: string, field = 'value'): Promise<string[]> {
669
- const validator = new Validator()
670
- const errors = await validator.validate({ [field]: value }, { [field]: rules })
671
- return errors[field] || []
672
- },
673
-
674
- /**
675
- * Check if value passes validation
676
- */
677
- async passes(value: any, rules: string): Promise<boolean> {
678
- const errors = await this.validateValue(value, rules)
679
- return errors.length === 0
680
- },
681
-
682
- /**
683
- * Check if value fails validation
684
- */
685
- async fails(value: any, rules: string): Promise<boolean> {
686
- return !(await this.passes(value, rules))
687
- },
688
- }