@stacksjs/bun-router 0.0.13 → 0.0.14
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.
- package/CHANGELOG.md +770 -0
- package/README.md +584 -261
- package/package.json +43 -47
- package/bin/cli.ts +0 -9
- package/dist/auth.d.ts +0 -134
- package/dist/cache/lru-cache.d.ts +0 -139
- package/dist/cache/middleware-memoization.d.ts +0 -151
- package/dist/cache/route-cache-warmer.d.ts +0 -161
- package/dist/cache/sqlite-cache.d.ts +0 -209
- package/dist/cache/streaming-cache.d.ts +0 -132
- package/dist/chunk-1mvtv6jw.js +0 -13012
- package/dist/cli/colors.d.ts +0 -15
- package/dist/cli/index.d.ts +0 -10
- package/dist/cli/middleware.d.ts +0 -31
- package/dist/cli/openapi.d.ts +0 -17
- package/dist/cli/router.d.ts +0 -15
- package/dist/cli/routes.d.ts +0 -29
- package/dist/cli/utils.d.ts +0 -74
- package/dist/cli.d.ts +0 -1
- package/dist/cli.js +0 -3195
- package/dist/config.d.ts +0 -7
- package/dist/container/container.d.ts +0 -273
- package/dist/container/contextual-binding.d.ts +0 -240
- package/dist/container/decorators.d.ts +0 -141
- package/dist/container/service-provider.d.ts +0 -285
- package/dist/development/hot-reload.d.ts +0 -187
- package/dist/development/index.d.ts +0 -167
- package/dist/development/performance-profiler.d.ts +0 -217
- package/dist/development/route-debugger.d.ts +0 -154
- package/dist/development/route-inspector.d.ts +0 -211
- package/dist/development/typescript-utilities.d.ts +0 -209
- package/dist/docs.d.ts +0 -11
- package/dist/errors/circuit-breaker.d.ts +0 -195
- package/dist/errors/error-handler.d.ts +0 -88
- package/dist/errors/error-reporting.d.ts +0 -144
- package/dist/errors/exceptions.d.ts +0 -184
- package/dist/errors/graceful-degradation.d.ts +0 -154
- package/dist/errors/index.d.ts +0 -9
- package/dist/errors/router-errors.d.ts +0 -110
- package/dist/file-serving/static-files.d.ts +0 -143
- package/dist/index.d.ts +0 -14
- package/dist/index.js +0 -13933
- package/dist/middleware/auth.d.ts +0 -63
- package/dist/middleware/content_security_policy.d.ts +0 -53
- package/dist/middleware/cors.d.ts +0 -5
- package/dist/middleware/csrf.d.ts +0 -7
- package/dist/middleware/ddos_protection.d.ts +0 -39
- package/dist/middleware/file_security.d.ts +0 -26
- package/dist/middleware/file_upload.d.ts +0 -38
- package/dist/middleware/helmet.d.ts +0 -54
- package/dist/middleware/index.d.ts +0 -44
- package/dist/middleware/input_validation.d.ts +0 -45
- package/dist/middleware/json_body.d.ts +0 -4
- package/dist/middleware/performance_alerting.d.ts +0 -87
- package/dist/middleware/performance_dashboard.d.ts +0 -87
- package/dist/middleware/performance_monitor.d.ts +0 -209
- package/dist/middleware/pipeline.d.ts +0 -131
- package/dist/middleware/rate_limit.d.ts +0 -36
- package/dist/middleware/request_id.d.ts +0 -4
- package/dist/middleware/request_signing.d.ts +0 -153
- package/dist/middleware/request_tracer.d.ts +0 -72
- package/dist/middleware/response_cache.d.ts +0 -97
- package/dist/middleware/security.d.ts +0 -69
- package/dist/middleware/security_suite.d.ts +0 -46
- package/dist/middleware/session.d.ts +0 -23
- package/dist/model-binding/index.d.ts +0 -2
- package/dist/model-binding/model-middleware.d.ts +0 -118
- package/dist/model-binding/model-registry.d.ts +0 -164
- package/dist/model-binding.d.ts +0 -185
- package/dist/model-resolver-factory.d.ts +0 -31
- package/dist/observability/correlation.d.ts +0 -187
- package/dist/observability/health-checks.d.ts +0 -186
- package/dist/observability/index.d.ts +0 -60
- package/dist/observability/integration.d.ts +0 -147
- package/dist/observability/metrics.d.ts +0 -184
- package/dist/observability/tracing.d.ts +0 -187
- package/dist/optimization/bun-utilities.d.ts +0 -224
- package/dist/query-builder-integration.d.ts +0 -36
- package/dist/request/context.d.ts +0 -34
- package/dist/request/enhanced-request.d.ts +0 -213
- package/dist/request/macros.d.ts +0 -300
- package/dist/response/macros.d.ts +0 -245
- package/dist/response/response-factory.d.ts +0 -133
- package/dist/router/api-routes.d.ts +0 -5
- package/dist/router/file-based-routing.d.ts +0 -118
- package/dist/router/file-streaming.d.ts +0 -5
- package/dist/router/fluent-router.d.ts +0 -315
- package/dist/router/fluent-routing.d.ts +0 -271
- package/dist/router/group-organization.d.ts +0 -5
- package/dist/router/handler-resolver.d.ts +0 -24
- package/dist/router/http-methods.d.ts +0 -10
- package/dist/router/index.d.ts +0 -114
- package/dist/router/middleware-groups.d.ts +0 -94
- package/dist/router/middleware-integration.d.ts +0 -112
- package/dist/router/middleware.d.ts +0 -5
- package/dist/router/model-binding.d.ts +0 -5
- package/dist/router/optimized-route-matching.d.ts +0 -6
- package/dist/router/route-building.d.ts +0 -5
- package/dist/router/route-compiler.d.ts +0 -153
- package/dist/router/route-matching.d.ts +0 -5
- package/dist/router/route-trie.d.ts +0 -114
- package/dist/router/router.d.ts +0 -294
- package/dist/router/server.d.ts +0 -5
- package/dist/router/validation-integration.d.ts +0 -170
- package/dist/router/view-rendering.d.ts +0 -5
- package/dist/router/websocket.d.ts +0 -5
- package/dist/routing/route-caching.d.ts +0 -129
- package/dist/routing/route-throttling.d.ts +0 -150
- package/dist/routing/subdomain-routing.d.ts +0 -206
- package/dist/session/database-store.d.ts +0 -51
- package/dist/session/file-store.d.ts +0 -22
- package/dist/session/index.d.ts +0 -106
- package/dist/session/memory-store.d.ts +0 -21
- package/dist/session/redis-store.d.ts +0 -31
- package/dist/streaming/index.d.ts +0 -3
- package/dist/streaming/sse-handler.d.ts +0 -138
- package/dist/streaming/stream-handler.d.ts +0 -114
- package/dist/testing/auth-testing.d.ts +0 -156
- package/dist/testing/file-upload-testing.d.ts +0 -190
- package/dist/testing/index.d.ts +0 -10
- package/dist/testing/middleware-testing.d.ts +0 -138
- package/dist/testing/model-binding-testing.d.ts +0 -186
- package/dist/testing/performance-testing.d.ts +0 -235
- package/dist/testing/test-client.d.ts +0 -117
- package/dist/testing/test-request.d.ts +0 -85
- package/dist/testing/test-response.d.ts +0 -90
- package/dist/testing/types.d.ts +0 -207
- package/dist/testing/websocket-testing.d.ts +0 -227
- package/dist/types/controller-types.d.ts +0 -208
- package/dist/types/core.d.ts +0 -543
- package/dist/types/middleware-types.d.ts +0 -227
- package/dist/types/request-response-augmentation.d.ts +0 -261
- package/dist/types/route-inference.d.ts +0 -168
- package/dist/types.d.ts +0 -1782
- package/dist/url.d.ts +0 -56
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/query-preservation.d.ts +0 -48
- package/dist/utils.d.ts +0 -69
- package/dist/validation/validator.d.ts +0 -140
- package/dist/websocket/clustering.d.ts +0 -185
- package/src/auth.ts +0 -469
- package/src/cache/lru-cache.ts +0 -457
- package/src/cache/middleware-memoization.ts +0 -531
- package/src/cache/route-cache-warmer.ts +0 -486
- package/src/cache/sqlite-cache.ts +0 -783
- package/src/cache/streaming-cache.ts +0 -572
- package/src/cli/colors.ts +0 -29
- package/src/cli/index.ts +0 -287
- package/src/cli/middleware.ts +0 -291
- package/src/cli/openapi.ts +0 -407
- package/src/cli/router.ts +0 -188
- package/src/cli/routes.ts +0 -265
- package/src/cli/utils.ts +0 -531
- package/src/cli.ts +0 -5
- package/src/config.ts +0 -322
- package/src/container/container.ts +0 -740
- package/src/container/contextual-binding.ts +0 -603
- package/src/container/decorators.ts +0 -359
- package/src/container/service-provider.ts +0 -596
- package/src/development/hot-reload.ts +0 -673
- package/src/development/index.ts +0 -499
- package/src/development/performance-profiler.ts +0 -717
- package/src/development/route-debugger.ts +0 -527
- package/src/development/route-inspector.ts +0 -749
- package/src/development/typescript-utilities.ts +0 -682
- package/src/docs.ts +0 -397
- package/src/errors/circuit-breaker.ts +0 -732
- package/src/errors/error-handler.ts +0 -569
- package/src/errors/error-reporting.ts +0 -672
- package/src/errors/exceptions.ts +0 -536
- package/src/errors/graceful-degradation.ts +0 -621
- package/src/errors/index.ts +0 -21
- package/src/errors/router-errors.ts +0 -632
- package/src/file-serving/static-files.ts +0 -581
- package/src/index.ts +0 -14
- package/src/middleware/auth.ts +0 -219
- package/src/middleware/content_security_policy.ts +0 -215
- package/src/middleware/cors.ts +0 -74
- package/src/middleware/csrf.ts +0 -108
- package/src/middleware/ddos_protection.ts +0 -255
- package/src/middleware/file_security.ts +0 -191
- package/src/middleware/file_upload.ts +0 -264
- package/src/middleware/helmet.ts +0 -268
- package/src/middleware/index.ts +0 -117
- package/src/middleware/input_validation.ts +0 -449
- package/src/middleware/json_body.ts +0 -37
- package/src/middleware/performance_alerting.ts +0 -538
- package/src/middleware/performance_dashboard.ts +0 -661
- package/src/middleware/performance_monitor.ts +0 -943
- package/src/middleware/pipeline.ts +0 -489
- package/src/middleware/rate_limit.ts +0 -245
- package/src/middleware/request_id.ts +0 -36
- package/src/middleware/request_signing.ts +0 -636
- package/src/middleware/request_tracer.ts +0 -636
- package/src/middleware/response_cache.ts +0 -743
- package/src/middleware/security.ts +0 -482
- package/src/middleware/security_suite.ts +0 -257
- package/src/middleware/session.ts +0 -91
- package/src/model-binding/index.ts +0 -18
- package/src/model-binding/model-middleware.ts +0 -425
- package/src/model-binding/model-registry.ts +0 -550
- package/src/model-binding.ts +0 -370
- package/src/model-resolver-factory.ts +0 -106
- package/src/observability/correlation.ts +0 -691
- package/src/observability/health-checks.ts +0 -729
- package/src/observability/index.ts +0 -184
- package/src/observability/integration.ts +0 -548
- package/src/observability/metrics.ts +0 -753
- package/src/observability/tracing.ts +0 -638
- package/src/optimization/bun-utilities.ts +0 -778
- package/src/query-builder-integration.ts +0 -137
- package/src/request/context.ts +0 -62
- package/src/request/enhanced-request.ts +0 -857
- package/src/request/macros.ts +0 -688
- package/src/response/macros.ts +0 -612
- package/src/response/response-factory.ts +0 -596
- package/src/router/api-routes.ts +0 -243
- package/src/router/file-based-routing.ts +0 -670
- package/src/router/file-streaming.ts +0 -372
- package/src/router/fluent-router.ts +0 -927
- package/src/router/fluent-routing.ts +0 -797
- package/src/router/group-organization.ts +0 -213
- package/src/router/handler-resolver.ts +0 -291
- package/src/router/http-methods.ts +0 -377
- package/src/router/index.ts +0 -187
- package/src/router/middleware-groups.ts +0 -222
- package/src/router/middleware-integration.ts +0 -399
- package/src/router/middleware.ts +0 -231
- package/src/router/model-binding.ts +0 -215
- package/src/router/optimized-route-matching.ts +0 -253
- package/src/router/route-building.ts +0 -212
- package/src/router/route-compiler.ts +0 -702
- package/src/router/route-matching.ts +0 -349
- package/src/router/route-trie.ts +0 -464
- package/src/router/router.ts +0 -1581
- package/src/router/server.ts +0 -462
- package/src/router/validation-integration.ts +0 -443
- package/src/router/view-rendering.ts +0 -233
- package/src/router/websocket.ts +0 -100
- package/src/routing/route-caching.ts +0 -402
- package/src/routing/route-throttling.ts +0 -469
- package/src/routing/subdomain-routing.ts +0 -492
- package/src/session/database-store.ts +0 -109
- package/src/session/file-store.ts +0 -148
- package/src/session/index.ts +0 -244
- package/src/session/memory-store.ts +0 -88
- package/src/session/redis-store.ts +0 -93
- package/src/streaming/index.ts +0 -17
- package/src/streaming/sse-handler.ts +0 -482
- package/src/streaming/stream-handler.ts +0 -552
- package/src/testing/auth-testing.ts +0 -446
- package/src/testing/file-upload-testing.ts +0 -543
- package/src/testing/index.ts +0 -10
- package/src/testing/middleware-testing.ts +0 -322
- package/src/testing/model-binding-testing.ts +0 -645
- package/src/testing/performance-testing.ts +0 -738
- package/src/testing/test-client.ts +0 -310
- package/src/testing/test-request.ts +0 -315
- package/src/testing/test-response.ts +0 -332
- package/src/testing/types.ts +0 -224
- package/src/testing/websocket-testing.ts +0 -590
- package/src/types/controller-types.ts +0 -385
- package/src/types/core.ts +0 -683
- package/src/types/middleware-types.ts +0 -419
- package/src/types/request-response-augmentation.ts +0 -489
- package/src/types/route-inference.ts +0 -357
- package/src/types.ts +0 -2055
- package/src/url.ts +0 -126
- package/src/utils/index.ts +0 -1
- package/src/utils/query-preservation.ts +0 -201
- package/src/utils.ts +0 -327
- package/src/validation/validator.ts +0 -685
- package/src/websocket/clustering.ts +0 -762
|
@@ -1,857 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Enhanced Request Methods
|
|
3
|
-
*
|
|
4
|
-
* Implements fluent request methods with full TypeScript support
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import type {
|
|
8
|
-
EnhancedRequest,
|
|
9
|
-
InputValue,
|
|
10
|
-
RequestInput,
|
|
11
|
-
ValidatedData,
|
|
12
|
-
} from '../types'
|
|
13
|
-
import { Validator } from '../validation/validator'
|
|
14
|
-
|
|
15
|
-
// ============================================================================
|
|
16
|
-
// Types
|
|
17
|
-
// ============================================================================
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* Validation rules type
|
|
21
|
-
*/
|
|
22
|
-
export type ValidationRules = Record<string, string | ValidationRule[]>
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Validation rule interface
|
|
26
|
-
*/
|
|
27
|
-
export interface ValidationRule {
|
|
28
|
-
name: string
|
|
29
|
-
validate: (value: unknown, parameters: string[], field: string, data: Record<string, unknown>) => Promise<boolean> | boolean
|
|
30
|
-
message: string | ((_field: string, _parameters: string[]) => string)
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Safe validated data wrapper
|
|
35
|
-
*/
|
|
36
|
-
export interface SafeData<T extends Record<string, unknown> = Record<string, unknown>> {
|
|
37
|
-
only: <K extends keyof T>(keys: K[]) => Pick<T, K>
|
|
38
|
-
except: <K extends keyof T>(keys: K[]) => Omit<T, K>
|
|
39
|
-
merge: <U extends Record<string, unknown>>(data: U) => T & U
|
|
40
|
-
all: () => T
|
|
41
|
-
has: (key: keyof T) => boolean
|
|
42
|
-
get: <K extends keyof T>(key: K) => T[K]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Collection interface for array data
|
|
47
|
-
*/
|
|
48
|
-
export interface Collection<T> {
|
|
49
|
-
items: T[]
|
|
50
|
-
count: () => number
|
|
51
|
-
first: () => T | undefined
|
|
52
|
-
last: () => T | undefined
|
|
53
|
-
map: <U>(fn: (item: T, index: number) => U) => Collection<U>
|
|
54
|
-
filter: (fn: (item: T, index: number) => boolean) => Collection<T>
|
|
55
|
-
find: (fn: (item: T, index: number) => boolean) => T | undefined
|
|
56
|
-
reduce: <U>(fn: (acc: U, item: T, index: number) => U, initial: U) => U
|
|
57
|
-
forEach: (fn: (item: T, index: number) => void) => void
|
|
58
|
-
toArray: () => T[]
|
|
59
|
-
isEmpty: () => boolean
|
|
60
|
-
isNotEmpty: () => boolean
|
|
61
|
-
pluck: <K extends keyof T>(key: K) => Collection<T[K]>
|
|
62
|
-
unique: () => Collection<T>
|
|
63
|
-
sortBy: <K extends keyof T>(key: K, direction?: 'asc' | 'desc') => Collection<T>
|
|
64
|
-
groupBy: <K extends keyof T>(key: K) => Map<T[K], Collection<T>>
|
|
65
|
-
chunk: (size: number) => Collection<Collection<T>>
|
|
66
|
-
take: (count: number) => Collection<T>
|
|
67
|
-
skip: (count: number) => Collection<T>
|
|
68
|
-
reverse: () => Collection<T>
|
|
69
|
-
sum: (key?: keyof T) => number
|
|
70
|
-
avg: (key?: keyof T) => number
|
|
71
|
-
min: (key?: keyof T) => T | undefined
|
|
72
|
-
max: (key?: keyof T) => T | undefined
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// ============================================================================
|
|
76
|
-
// Collection Implementation
|
|
77
|
-
// ============================================================================
|
|
78
|
-
|
|
79
|
-
/**
|
|
80
|
-
* Collection class for array manipulation
|
|
81
|
-
*/
|
|
82
|
-
export class CollectionImpl<T> implements Collection<T> {
|
|
83
|
-
items: T[]
|
|
84
|
-
|
|
85
|
-
constructor(items: T[]) {
|
|
86
|
-
this.items = [...items]
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
count(): number {
|
|
90
|
-
return this.items.length
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
first(): T | undefined {
|
|
94
|
-
return this.items[0]
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
last(): T | undefined {
|
|
98
|
-
return this.items[this.items.length - 1]
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
map<U>(fn: (item: T, index: number) => U): Collection<U> {
|
|
102
|
-
return new CollectionImpl(this.items.map(fn))
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
filter(fn: (item: T, index: number) => boolean): Collection<T> {
|
|
106
|
-
return new CollectionImpl(this.items.filter(fn))
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
find(fn: (item: T, index: number) => boolean): T | undefined {
|
|
110
|
-
return this.items.find(fn)
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
reduce<U>(fn: (acc: U, item: T, index: number) => U, initial: U): U {
|
|
114
|
-
return this.items.reduce(fn, initial)
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
forEach(fn: (item: T, index: number) => void): void {
|
|
118
|
-
this.items.forEach(fn)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
toArray(): T[] {
|
|
122
|
-
return [...this.items]
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
isEmpty(): boolean {
|
|
126
|
-
return this.items.length === 0
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
isNotEmpty(): boolean {
|
|
130
|
-
return this.items.length > 0
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
pluck<K extends keyof T>(key: K): Collection<T[K]> {
|
|
134
|
-
return new CollectionImpl(this.items.map(item => item[key]))
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
unique(): Collection<T> {
|
|
138
|
-
return new CollectionImpl([...new Set(this.items)])
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
sortBy<K extends keyof T>(key: K, direction: 'asc' | 'desc' = 'asc'): Collection<T> {
|
|
142
|
-
const sorted = [...this.items].sort((a, b) => {
|
|
143
|
-
const aVal = a[key]
|
|
144
|
-
const bVal = b[key]
|
|
145
|
-
if (aVal < bVal)
|
|
146
|
-
return direction === 'asc' ? -1 : 1
|
|
147
|
-
if (aVal > bVal)
|
|
148
|
-
return direction === 'asc' ? 1 : -1
|
|
149
|
-
return 0
|
|
150
|
-
})
|
|
151
|
-
return new CollectionImpl(sorted)
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
groupBy<K extends keyof T>(key: K): Map<T[K], Collection<T>> {
|
|
155
|
-
const groups = new Map<T[K], T[]>()
|
|
156
|
-
for (const item of this.items) {
|
|
157
|
-
const groupKey = item[key]
|
|
158
|
-
if (!groups.has(groupKey)) {
|
|
159
|
-
groups.set(groupKey, [])
|
|
160
|
-
}
|
|
161
|
-
groups.get(groupKey)!.push(item)
|
|
162
|
-
}
|
|
163
|
-
const result = new Map<T[K], Collection<T>>()
|
|
164
|
-
for (const [k, v] of groups) {
|
|
165
|
-
result.set(k, new CollectionImpl(v))
|
|
166
|
-
}
|
|
167
|
-
return result
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
chunk(size: number): Collection<Collection<T>> {
|
|
171
|
-
const chunks: Collection<T>[] = []
|
|
172
|
-
for (let i = 0; i < this.items.length; i += size) {
|
|
173
|
-
chunks.push(new CollectionImpl(this.items.slice(i, i + size)))
|
|
174
|
-
}
|
|
175
|
-
return new CollectionImpl(chunks)
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
take(count: number): Collection<T> {
|
|
179
|
-
return new CollectionImpl(this.items.slice(0, count))
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
skip(count: number): Collection<T> {
|
|
183
|
-
return new CollectionImpl(this.items.slice(count))
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
reverse(): Collection<T> {
|
|
187
|
-
return new CollectionImpl([...this.items].reverse())
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
sum(key?: keyof T): number {
|
|
191
|
-
if (key) {
|
|
192
|
-
return this.items.reduce((acc, item) => acc + (Number(item[key]) || 0), 0)
|
|
193
|
-
}
|
|
194
|
-
return this.items.reduce((acc, item) => acc + (Number(item) || 0), 0)
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
avg(key?: keyof T): number {
|
|
198
|
-
if (this.items.length === 0)
|
|
199
|
-
return 0
|
|
200
|
-
return this.sum(key) / this.items.length
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
min(key?: keyof T): T | undefined {
|
|
204
|
-
if (this.items.length === 0)
|
|
205
|
-
return undefined
|
|
206
|
-
if (key) {
|
|
207
|
-
return this.items.reduce((min, item) =>
|
|
208
|
-
item[key] < min[key] ? item : min,
|
|
209
|
-
)
|
|
210
|
-
}
|
|
211
|
-
return this.items.reduce((min, item) => (item < min ? item : min))
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
max(key?: keyof T): T | undefined {
|
|
215
|
-
if (this.items.length === 0)
|
|
216
|
-
return undefined
|
|
217
|
-
if (key) {
|
|
218
|
-
return this.items.reduce((max, item) =>
|
|
219
|
-
item[key] > max[key] ? item : max,
|
|
220
|
-
)
|
|
221
|
-
}
|
|
222
|
-
return this.items.reduce((max, item) => (item > max ? item : max))
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// ============================================================================
|
|
227
|
-
// Safe Data Implementation
|
|
228
|
-
// ============================================================================
|
|
229
|
-
|
|
230
|
-
/**
|
|
231
|
-
* Create a safe data wrapper
|
|
232
|
-
*/
|
|
233
|
-
export function createSafeData<T extends Record<string, unknown>>(data: T): SafeData<T> {
|
|
234
|
-
return {
|
|
235
|
-
only: <K extends keyof T>(keys: K[]): Pick<T, K> => {
|
|
236
|
-
const result = {} as Pick<T, K>
|
|
237
|
-
for (const key of keys) {
|
|
238
|
-
if (key in data) {
|
|
239
|
-
result[key] = data[key]
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
return result
|
|
243
|
-
},
|
|
244
|
-
|
|
245
|
-
except: <K extends keyof T>(keys: K[]): Omit<T, K> => {
|
|
246
|
-
const result = { ...data }
|
|
247
|
-
for (const key of keys) {
|
|
248
|
-
delete result[key]
|
|
249
|
-
}
|
|
250
|
-
return result as Omit<T, K>
|
|
251
|
-
},
|
|
252
|
-
|
|
253
|
-
// eslint-disable-next-line pickier/no-unused-vars
|
|
254
|
-
merge: <U extends Record<string, unknown>>(mergeData: U): T & U => {
|
|
255
|
-
return { ...data, ...mergeData }
|
|
256
|
-
},
|
|
257
|
-
|
|
258
|
-
all: (): T => ({ ...data }),
|
|
259
|
-
|
|
260
|
-
has: (key: keyof T): boolean => key in data,
|
|
261
|
-
|
|
262
|
-
get: <K extends keyof T>(key: K): T[K] => data[key],
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
// ============================================================================
|
|
267
|
-
// Enhanced Request Methods
|
|
268
|
-
// ============================================================================
|
|
269
|
-
|
|
270
|
-
/**
|
|
271
|
-
* Enhanced request methods interface
|
|
272
|
-
*/
|
|
273
|
-
export interface EnhancedRequestMethods {
|
|
274
|
-
/**
|
|
275
|
-
* Validate the request data
|
|
276
|
-
*/
|
|
277
|
-
validate: <T extends Record<string, unknown> = Record<string, unknown>>(
|
|
278
|
-
rules: ValidationRules,
|
|
279
|
-
messages?: Record<string, string>,
|
|
280
|
-
) => Promise<T>
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Get validated data as typed object
|
|
284
|
-
*/
|
|
285
|
-
getValidated: <T extends Record<string, unknown> = Record<string, unknown>>() => T
|
|
286
|
-
|
|
287
|
-
/**
|
|
288
|
-
* Get safe validated data wrapper
|
|
289
|
-
*/
|
|
290
|
-
safe: <T extends Record<string, unknown> = Record<string, unknown>>() => SafeData<T>
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Execute callback when input has a value
|
|
294
|
-
*/
|
|
295
|
-
whenHas: <T>(
|
|
296
|
-
key: string,
|
|
297
|
-
callback: (value: T) => void,
|
|
298
|
-
defaultCallback?: () => void,
|
|
299
|
-
) => void
|
|
300
|
-
|
|
301
|
-
/**
|
|
302
|
-
* Execute callback when input is filled (not empty)
|
|
303
|
-
*/
|
|
304
|
-
whenFilled: <T>(
|
|
305
|
-
key: string,
|
|
306
|
-
callback: (value: T) => void,
|
|
307
|
-
defaultCallback?: () => void,
|
|
308
|
-
) => void
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Parse date input
|
|
312
|
-
*/
|
|
313
|
-
date: (key: string, format?: string) => Date | null
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Parse enum input
|
|
317
|
-
*/
|
|
318
|
-
enum: <T extends Record<string, string | number>>(
|
|
319
|
-
key: string,
|
|
320
|
-
enumType: T,
|
|
321
|
-
) => T[keyof T] | null
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Get input as collection
|
|
325
|
-
*/
|
|
326
|
-
collect: <T = unknown>(key: string) => Collection<T>
|
|
327
|
-
|
|
328
|
-
/**
|
|
329
|
-
* Get all input keys
|
|
330
|
-
*/
|
|
331
|
-
keys: () => string[]
|
|
332
|
-
|
|
333
|
-
/**
|
|
334
|
-
* Get input with type casting
|
|
335
|
-
*/
|
|
336
|
-
string: (key: string, defaultValue?: string) => string
|
|
337
|
-
integer: (key: string, defaultValue?: number) => number
|
|
338
|
-
float: (key: string, defaultValue?: number) => number
|
|
339
|
-
boolean: (key: string, defaultValue?: boolean) => boolean
|
|
340
|
-
|
|
341
|
-
/**
|
|
342
|
-
* Check if input matches a value
|
|
343
|
-
*/
|
|
344
|
-
isValue: (key: string, value: unknown) => boolean
|
|
345
|
-
|
|
346
|
-
/**
|
|
347
|
-
* Get old input (for form repopulation)
|
|
348
|
-
*/
|
|
349
|
-
old: <T = unknown>(key: string, defaultValue?: T) => T
|
|
350
|
-
|
|
351
|
-
/**
|
|
352
|
-
* Flash input to session for form repopulation
|
|
353
|
-
*/
|
|
354
|
-
flashInput: (keys?: string[]) => void
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Flash only specific keys
|
|
358
|
-
*/
|
|
359
|
-
flashInputOnly: (keys: string[]) => void
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Flash except specific keys
|
|
363
|
-
*/
|
|
364
|
-
flashInputExcept: (keys: string[]) => void
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Get input as array
|
|
368
|
-
*/
|
|
369
|
-
array: <T = unknown>(key: string) => T[]
|
|
370
|
-
|
|
371
|
-
/**
|
|
372
|
-
* Get input value from any source (query, body, params)
|
|
373
|
-
* Laravel-style request.get()
|
|
374
|
-
*/
|
|
375
|
-
get: <T = unknown>(key: string, defaultValue?: T) => T
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Get all input data
|
|
379
|
-
*/
|
|
380
|
-
all: () => RequestInput
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Get only specified keys
|
|
384
|
-
*/
|
|
385
|
-
only: <T extends Record<string, unknown> = Record<string, unknown>>(keys: string[]) => T
|
|
386
|
-
|
|
387
|
-
/**
|
|
388
|
-
* Get all except specified keys
|
|
389
|
-
*/
|
|
390
|
-
except: <T extends Record<string, unknown> = Record<string, unknown>>(keys: string[]) => T
|
|
391
|
-
|
|
392
|
-
/**
|
|
393
|
-
* Check if input has a key
|
|
394
|
-
*/
|
|
395
|
-
has: (key: string | string[]) => boolean
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Check if input has any of the keys
|
|
399
|
-
*/
|
|
400
|
-
hasAny: (keys: string[]) => boolean
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Check if input is filled (not empty)
|
|
404
|
-
*/
|
|
405
|
-
filled: (key: string | string[]) => boolean
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Check if input is missing
|
|
409
|
-
*/
|
|
410
|
-
missing: (key: string | string[]) => boolean
|
|
411
|
-
|
|
412
|
-
/**
|
|
413
|
-
* Merge additional data into input
|
|
414
|
-
*/
|
|
415
|
-
merge: (data: Record<string, unknown>) => void
|
|
416
|
-
|
|
417
|
-
/**
|
|
418
|
-
* Get input value or fail
|
|
419
|
-
*/
|
|
420
|
-
input: <T = unknown>(key: string, defaultValue?: T) => T
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
// ============================================================================
|
|
424
|
-
// Request Enhancement
|
|
425
|
-
// ============================================================================
|
|
426
|
-
|
|
427
|
-
/**
|
|
428
|
-
* Enhance request with additional methods
|
|
429
|
-
*/
|
|
430
|
-
export function enhanceRequestWithMethods(request: EnhancedRequest): EnhancedRequest & EnhancedRequestMethods {
|
|
431
|
-
const enhanced = request as EnhancedRequest & EnhancedRequestMethods & {
|
|
432
|
-
_validatedData?: ValidatedData
|
|
433
|
-
_oldInput?: RequestInput
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
// Get all input data
|
|
437
|
-
const getAllInput = (): RequestInput => {
|
|
438
|
-
const input: RequestInput = {}
|
|
439
|
-
|
|
440
|
-
// Query parameters
|
|
441
|
-
if (request.query) {
|
|
442
|
-
for (const [key, value] of Object.entries(request.query)) {
|
|
443
|
-
input[key] = value as InputValue
|
|
444
|
-
}
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// JSON body
|
|
448
|
-
if (request.jsonBody) {
|
|
449
|
-
for (const [key, value] of Object.entries(request.jsonBody as Record<string, unknown>)) {
|
|
450
|
-
input[key] = value as InputValue
|
|
451
|
-
}
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
// Form body
|
|
455
|
-
if (request.formBody) {
|
|
456
|
-
for (const [key, value] of Object.entries(request.formBody)) {
|
|
457
|
-
input[key] = value as InputValue
|
|
458
|
-
}
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
// Route params
|
|
462
|
-
if (request.params) {
|
|
463
|
-
for (const [key, value] of Object.entries(request.params)) {
|
|
464
|
-
input[key] = value
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
return input
|
|
469
|
-
}
|
|
470
|
-
|
|
471
|
-
/**
|
|
472
|
-
* Validate the request
|
|
473
|
-
*/
|
|
474
|
-
enhanced.validate = async <T extends Record<string, unknown>>(
|
|
475
|
-
rules: ValidationRules,
|
|
476
|
-
messages?: Record<string, string>,
|
|
477
|
-
): Promise<T> => {
|
|
478
|
-
const input = getAllInput()
|
|
479
|
-
const validator = new Validator({
|
|
480
|
-
customMessages: messages,
|
|
481
|
-
})
|
|
482
|
-
|
|
483
|
-
const errors = await validator.validate(input as Record<string, unknown>, rules as Record<string, string>)
|
|
484
|
-
|
|
485
|
-
if (Object.keys(errors).length > 0) {
|
|
486
|
-
const error = new Error('Validation failed') as Error & { errors: Record<string, string[]> }
|
|
487
|
-
error.errors = errors
|
|
488
|
-
throw error
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
enhanced._validatedData = input as ValidatedData
|
|
492
|
-
return input as T
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
/**
|
|
496
|
-
* Get validated data as typed object
|
|
497
|
-
*/
|
|
498
|
-
enhanced.getValidated = <T extends Record<string, unknown>>(): T => {
|
|
499
|
-
return (enhanced._validatedData || {}) as T
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
/**
|
|
503
|
-
* Get safe validated data wrapper
|
|
504
|
-
*/
|
|
505
|
-
enhanced.safe = <T extends Record<string, unknown>>(): SafeData<T> => {
|
|
506
|
-
return createSafeData(enhanced.getValidated<T>())
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
/**
|
|
510
|
-
* Execute callback when input has a value
|
|
511
|
-
*/
|
|
512
|
-
enhanced.whenHas = <T>(
|
|
513
|
-
key: string,
|
|
514
|
-
callback: (value: T) => void,
|
|
515
|
-
defaultCallback?: () => void,
|
|
516
|
-
): void => {
|
|
517
|
-
const input = getAllInput()
|
|
518
|
-
if (key in input && input[key] !== undefined) {
|
|
519
|
-
callback(input[key] as T)
|
|
520
|
-
}
|
|
521
|
-
else if (defaultCallback) {
|
|
522
|
-
defaultCallback()
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
/**
|
|
527
|
-
* Execute callback when input is filled
|
|
528
|
-
*/
|
|
529
|
-
enhanced.whenFilled = <T>(
|
|
530
|
-
key: string,
|
|
531
|
-
callback: (value: T) => void,
|
|
532
|
-
defaultCallback?: () => void,
|
|
533
|
-
): void => {
|
|
534
|
-
const input = getAllInput()
|
|
535
|
-
const value = input[key]
|
|
536
|
-
const isFilled = value !== undefined
|
|
537
|
-
&& value !== null
|
|
538
|
-
&& value !== ''
|
|
539
|
-
&& !(Array.isArray(value) && value.length === 0)
|
|
540
|
-
|
|
541
|
-
if (isFilled) {
|
|
542
|
-
callback(value as T)
|
|
543
|
-
}
|
|
544
|
-
else if (defaultCallback) {
|
|
545
|
-
defaultCallback()
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
/**
|
|
550
|
-
* Parse date input
|
|
551
|
-
*/
|
|
552
|
-
enhanced.date = (key: string, _format?: string): Date | null => {
|
|
553
|
-
const input = getAllInput()
|
|
554
|
-
const value = input[key]
|
|
555
|
-
|
|
556
|
-
if (!value)
|
|
557
|
-
return null
|
|
558
|
-
|
|
559
|
-
const date = new Date(String(value))
|
|
560
|
-
return Number.isNaN(date.getTime()) ? null : date
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
/**
|
|
564
|
-
* Parse enum input
|
|
565
|
-
*/
|
|
566
|
-
enhanced.enum = <T extends Record<string, string | number>>(
|
|
567
|
-
key: string,
|
|
568
|
-
enumType: T,
|
|
569
|
-
): T[keyof T] | null => {
|
|
570
|
-
const input = getAllInput()
|
|
571
|
-
const value = input[key]
|
|
572
|
-
|
|
573
|
-
if (value === undefined || value === null)
|
|
574
|
-
return null
|
|
575
|
-
|
|
576
|
-
const enumValues = Object.values(enumType)
|
|
577
|
-
if (enumValues.includes(value as T[keyof T])) {
|
|
578
|
-
return value as T[keyof T]
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Try to match by key
|
|
582
|
-
const stringValue = String(value)
|
|
583
|
-
if (stringValue in enumType) {
|
|
584
|
-
return enumType[stringValue as keyof T]
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
return null
|
|
588
|
-
}
|
|
589
|
-
|
|
590
|
-
/**
|
|
591
|
-
* Get input as collection
|
|
592
|
-
*/
|
|
593
|
-
enhanced.collect = <T = unknown>(key: string): Collection<T> => {
|
|
594
|
-
const input = getAllInput()
|
|
595
|
-
const value = input[key]
|
|
596
|
-
|
|
597
|
-
if (Array.isArray(value)) {
|
|
598
|
-
return new CollectionImpl(value as T[])
|
|
599
|
-
}
|
|
600
|
-
|
|
601
|
-
return new CollectionImpl(value ? [value as T] : [])
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
/**
|
|
605
|
-
* Get all input keys
|
|
606
|
-
*/
|
|
607
|
-
enhanced.keys = (): string[] => {
|
|
608
|
-
return Object.keys(getAllInput())
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
/**
|
|
612
|
-
* Get string input
|
|
613
|
-
*/
|
|
614
|
-
enhanced.string = (key: string, defaultValue: string = ''): string => {
|
|
615
|
-
const input = getAllInput()
|
|
616
|
-
const value = input[key]
|
|
617
|
-
return value !== undefined && value !== null ? String(value) : defaultValue
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
/**
|
|
621
|
-
* Get integer input
|
|
622
|
-
*/
|
|
623
|
-
enhanced.integer = (key: string, defaultValue: number = 0): number => {
|
|
624
|
-
const input = getAllInput()
|
|
625
|
-
const value = input[key]
|
|
626
|
-
const parsed = Number.parseInt(String(value), 10)
|
|
627
|
-
return Number.isNaN(parsed) ? defaultValue : parsed
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
/**
|
|
631
|
-
* Get float input
|
|
632
|
-
*/
|
|
633
|
-
enhanced.float = (key: string, defaultValue: number = 0): number => {
|
|
634
|
-
const input = getAllInput()
|
|
635
|
-
const value = input[key]
|
|
636
|
-
const parsed = Number.parseFloat(String(value))
|
|
637
|
-
return Number.isNaN(parsed) ? defaultValue : parsed
|
|
638
|
-
}
|
|
639
|
-
|
|
640
|
-
/**
|
|
641
|
-
* Get boolean input
|
|
642
|
-
*/
|
|
643
|
-
enhanced.boolean = (key: string, defaultValue: boolean = false): boolean => {
|
|
644
|
-
const input = getAllInput()
|
|
645
|
-
const value = input[key]
|
|
646
|
-
|
|
647
|
-
if (value === undefined || value === null)
|
|
648
|
-
return defaultValue
|
|
649
|
-
if (typeof value === 'boolean')
|
|
650
|
-
return value
|
|
651
|
-
if (value === 'true' || value === '1' || value === 1)
|
|
652
|
-
return true
|
|
653
|
-
if (value === 'false' || value === '0' || value === 0)
|
|
654
|
-
return false
|
|
655
|
-
|
|
656
|
-
return defaultValue
|
|
657
|
-
}
|
|
658
|
-
|
|
659
|
-
/**
|
|
660
|
-
* Check if input matches a value
|
|
661
|
-
*/
|
|
662
|
-
enhanced.isValue = (key: string, value: unknown): boolean => {
|
|
663
|
-
const input = getAllInput()
|
|
664
|
-
return input[key] === value
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/**
|
|
668
|
-
* Get old input
|
|
669
|
-
*/
|
|
670
|
-
enhanced.old = <T = unknown>(key: string, defaultValue?: T): T => {
|
|
671
|
-
const oldInput = enhanced._oldInput || {}
|
|
672
|
-
return (oldInput[key] as T) ?? (defaultValue as T)
|
|
673
|
-
}
|
|
674
|
-
|
|
675
|
-
/**
|
|
676
|
-
* Flash input to session for form repopulation
|
|
677
|
-
*/
|
|
678
|
-
enhanced.flashInput = (keys?: string[]): void => {
|
|
679
|
-
const input = getAllInput()
|
|
680
|
-
if (keys) {
|
|
681
|
-
const filtered: RequestInput = {}
|
|
682
|
-
for (const key of keys) {
|
|
683
|
-
if (key in input) {
|
|
684
|
-
filtered[key] = input[key]
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
enhanced._oldInput = filtered
|
|
688
|
-
}
|
|
689
|
-
else {
|
|
690
|
-
enhanced._oldInput = input
|
|
691
|
-
}
|
|
692
|
-
}
|
|
693
|
-
|
|
694
|
-
/**
|
|
695
|
-
* Flash only specific keys
|
|
696
|
-
*/
|
|
697
|
-
enhanced.flashInputOnly = (keys: string[]): void => {
|
|
698
|
-
enhanced.flashInput(keys)
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
/**
|
|
702
|
-
* Flash except specific keys
|
|
703
|
-
*/
|
|
704
|
-
enhanced.flashInputExcept = (keys: string[]): void => {
|
|
705
|
-
const input = getAllInput()
|
|
706
|
-
const filtered: RequestInput = {}
|
|
707
|
-
for (const [key, value] of Object.entries(input)) {
|
|
708
|
-
if (!keys.includes(key)) {
|
|
709
|
-
filtered[key] = value
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
enhanced._oldInput = filtered
|
|
713
|
-
}
|
|
714
|
-
|
|
715
|
-
/**
|
|
716
|
-
* Get input as array
|
|
717
|
-
*/
|
|
718
|
-
enhanced.array = <T = unknown>(key: string): T[] => {
|
|
719
|
-
const input = getAllInput()
|
|
720
|
-
const value = input[key]
|
|
721
|
-
|
|
722
|
-
if (Array.isArray(value)) {
|
|
723
|
-
return value as T[]
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
return value !== undefined && value !== null ? [value as T] : []
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
/**
|
|
730
|
-
* Get input value from any source (query, body, params) - Laravel style
|
|
731
|
-
*/
|
|
732
|
-
enhanced.get = <T = unknown>(key: string, defaultValue?: T): T => {
|
|
733
|
-
const input = getAllInput()
|
|
734
|
-
const value = input[key]
|
|
735
|
-
return (value !== undefined ? value : defaultValue) as T
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
/**
|
|
739
|
-
* Get all input data
|
|
740
|
-
*/
|
|
741
|
-
enhanced.all = (): RequestInput => {
|
|
742
|
-
return getAllInput()
|
|
743
|
-
}
|
|
744
|
-
|
|
745
|
-
/**
|
|
746
|
-
* Get only specified keys
|
|
747
|
-
*/
|
|
748
|
-
enhanced.only = <T extends Record<string, unknown> = Record<string, unknown>>(keys: string[]): T => {
|
|
749
|
-
const input = getAllInput()
|
|
750
|
-
const result = {} as T
|
|
751
|
-
for (const key of keys) {
|
|
752
|
-
if (key in input) {
|
|
753
|
-
(result as Record<string, unknown>)[key] = input[key]
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
return result
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
/**
|
|
760
|
-
* Get all except specified keys
|
|
761
|
-
*/
|
|
762
|
-
enhanced.except = <T extends Record<string, unknown> = Record<string, unknown>>(keys: string[]): T => {
|
|
763
|
-
const input = getAllInput()
|
|
764
|
-
const result = { ...input } as T
|
|
765
|
-
for (const key of keys) {
|
|
766
|
-
delete (result as Record<string, unknown>)[key]
|
|
767
|
-
}
|
|
768
|
-
return result
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
/**
|
|
772
|
-
* Check if input has a key (or all keys if array)
|
|
773
|
-
*/
|
|
774
|
-
enhanced.has = (key: string | string[]): boolean => {
|
|
775
|
-
const input = getAllInput()
|
|
776
|
-
if (Array.isArray(key)) {
|
|
777
|
-
return key.every(k => k in input && input[k] !== undefined)
|
|
778
|
-
}
|
|
779
|
-
return key in input && input[key] !== undefined
|
|
780
|
-
}
|
|
781
|
-
|
|
782
|
-
/**
|
|
783
|
-
* Check if input has any of the keys
|
|
784
|
-
*/
|
|
785
|
-
enhanced.hasAny = (keys: string[]): boolean => {
|
|
786
|
-
const input = getAllInput()
|
|
787
|
-
return keys.some(k => k in input && input[k] !== undefined)
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
/**
|
|
791
|
-
* Check if input is filled (not empty)
|
|
792
|
-
*/
|
|
793
|
-
enhanced.filled = (key: string | string[]): boolean => {
|
|
794
|
-
const input = getAllInput()
|
|
795
|
-
const isFilled = (k: string): boolean => {
|
|
796
|
-
const value = input[k]
|
|
797
|
-
return value !== undefined
|
|
798
|
-
&& value !== null
|
|
799
|
-
&& value !== ''
|
|
800
|
-
&& !(Array.isArray(value) && value.length === 0)
|
|
801
|
-
}
|
|
802
|
-
|
|
803
|
-
if (Array.isArray(key)) {
|
|
804
|
-
return key.every(isFilled)
|
|
805
|
-
}
|
|
806
|
-
return isFilled(key)
|
|
807
|
-
}
|
|
808
|
-
|
|
809
|
-
/**
|
|
810
|
-
* Check if input is missing
|
|
811
|
-
*/
|
|
812
|
-
enhanced.missing = (key: string | string[]): boolean => {
|
|
813
|
-
const input = getAllInput()
|
|
814
|
-
if (Array.isArray(key)) {
|
|
815
|
-
return key.every(k => !(k in input) || input[k] === undefined)
|
|
816
|
-
}
|
|
817
|
-
return !(key in input) || input[key] === undefined
|
|
818
|
-
}
|
|
819
|
-
|
|
820
|
-
/**
|
|
821
|
-
* Merge additional data into input
|
|
822
|
-
*/
|
|
823
|
-
enhanced.merge = (data: Record<string, unknown>): void => {
|
|
824
|
-
if (request.jsonBody && typeof request.jsonBody === 'object') {
|
|
825
|
-
Object.assign(request.jsonBody, data)
|
|
826
|
-
}
|
|
827
|
-
else {
|
|
828
|
-
(request as any).jsonBody = data
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
/**
|
|
833
|
-
* Get input value - alias for get() for Laravel compatibility
|
|
834
|
-
*/
|
|
835
|
-
enhanced.input = <T = unknown>(key: string, defaultValue?: T): T => {
|
|
836
|
-
return enhanced.get(key, defaultValue)
|
|
837
|
-
}
|
|
838
|
-
|
|
839
|
-
return enhanced
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
// ============================================================================
|
|
843
|
-
// Middleware for Request Enhancement
|
|
844
|
-
// ============================================================================
|
|
845
|
-
|
|
846
|
-
/**
|
|
847
|
-
* Middleware to enhance request with additional methods
|
|
848
|
-
*/
|
|
849
|
-
export function enhancedRequestMiddleware() {
|
|
850
|
-
return async (req: EnhancedRequest, next: () => Promise<Response | null>): Promise<Response | null> => {
|
|
851
|
-
enhanceRequestWithMethods(req)
|
|
852
|
-
return next()
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
// Note: Collection interface and CollectionImpl class are already exported above
|
|
857
|
-
// enhanceRequestWithMethods is already exported above
|