@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,786 +0,0 @@
1
- /**
2
- * IoC Container for Dependency Resolution
3
- *
4
- * Comprehensive dependency injection container with automatic resolution,
5
- * lifecycle management, and contextual binding support
6
- */
7
-
8
- import { CircularDependencyException } from '../errors/router-errors'
9
-
10
- // Extend Reflect with metadata methods
11
- declare global {
12
- // eslint-disable-next-line ts/no-namespace
13
- namespace Reflect {
14
- function getMetadata(_metadataKey: any, _target: any, _propertyKey?: string | symbol): any
15
- function defineMetadata(_metadataKey: any, _metadataValue: any, _target: any, _propertyKey?: string | symbol): void
16
- }
17
- }
18
-
19
- // Container binding types
20
- export type BindingScope = 'singleton' | 'transient' | 'scoped' | 'request'
21
-
22
- // Token can be a string, symbol, function, constructor, or generic Function
23
- // eslint-disable-next-line ts/no-unsafe-function-type
24
- export type Token = string | symbol | ((...args: any[]) => any) | (new (...args: any[]) => any) | Function
25
-
26
- export interface BindingMetadata {
27
- scope: BindingScope
28
- tags?: string[]
29
- when?: (context: ResolutionContext) => boolean
30
- factory?: (..._args: any[]) => any
31
- dependencies?: Token[]
32
- lazy?: boolean
33
- decorators?: ((..._args: any[]) => any)[]
34
- }
35
-
36
- export interface Binding<T = any> {
37
- token: Token
38
- implementation?: new (...args: any[]) => T
39
- instance?: T
40
- factory?: (...args: any[]) => T
41
- value?: T
42
- metadata: BindingMetadata
43
- }
44
-
45
- export interface ResolutionContext {
46
- container: Container
47
- token: Token
48
- parent?: ResolutionContext
49
- environment?: string
50
- requestId?: string
51
- depth: number
52
- resolving: Set<Token>
53
- }
54
-
55
- export interface ContainerOptions {
56
- autoRegister?: boolean
57
- strictMode?: boolean
58
- maxDepth?: number
59
- enableDecorators?: boolean
60
- enableInterception?: boolean
61
- defaultScope?: BindingScope
62
- }
63
-
64
- // Dependency injection decorators
65
- export const INJECTABLE_METADATA_KEY: unique symbol = Symbol('injectable')
66
- export const INJECT_METADATA_KEY: unique symbol = Symbol('inject')
67
- export const OPTIONAL_METADATA_KEY: unique symbol = Symbol('optional')
68
- export const TAGGED_METADATA_KEY: unique symbol = Symbol('tagged')
69
-
70
- // Decorator metadata
71
- export interface InjectableMetadata {
72
- token?: string | symbol
73
- scope?: BindingScope
74
- tags?: string[]
75
- }
76
-
77
- export interface InjectMetadata {
78
- token: Token
79
- optional?: boolean
80
- tags?: string[]
81
- when?: (context: ResolutionContext) => boolean
82
- }
83
-
84
- /**
85
- * Main IoC Container implementation
86
- */
87
- export class Container {
88
- private bindings = new Map<Token, Binding>()
89
- // Tag → tokens index, maintained on register/unbind so tagged lookups
90
- // are O(matches) instead of scanning every binding
91
- private tagIndex = new Map<string, Set<Token>>()
92
- private instances = new Map<Token, any>()
93
- private scopedInstances = new Map<string, Map<Token, any>>()
94
- private interceptors = new Map<Token, ((..._args: any[]) => any)[]>()
95
- private parent?: Container
96
- private children = new Set<Container>()
97
- private options: Required<ContainerOptions>
98
-
99
- constructor(options: ContainerOptions = {}) {
100
- this.options = {
101
- autoRegister: options.autoRegister ?? true,
102
- strictMode: options.strictMode ?? false,
103
- maxDepth: options.maxDepth ?? 50,
104
- enableDecorators: options.enableDecorators ?? true,
105
- enableInterception: options.enableInterception ?? false,
106
- defaultScope: options.defaultScope ?? 'transient',
107
- }
108
- }
109
-
110
- /**
111
- * Bind a token to an implementation
112
- */
113
- bind<T>(token: Token): BindingBuilder<T> {
114
- return new BindingBuilder<T>(this, token)
115
- }
116
-
117
- /**
118
- * Register a binding
119
- */
120
- register<T>(binding: Binding<T>): this {
121
- // Re-registering a token replaces its tag index entries
122
- const existing = this.bindings.get(binding.token)
123
- if (existing?.metadata?.tags) {
124
- for (const tag of existing.metadata.tags) {
125
- this.tagIndex.get(tag)?.delete(binding.token)
126
- }
127
- }
128
-
129
- this.bindings.set(binding.token, binding)
130
-
131
- if (binding.metadata?.tags) {
132
- for (const tag of binding.metadata.tags) {
133
- let tokens = this.tagIndex.get(tag)
134
- if (!tokens) {
135
- tokens = new Set()
136
- this.tagIndex.set(tag, tokens)
137
- }
138
- tokens.add(binding.token)
139
- }
140
- }
141
- return this
142
- }
143
-
144
- /**
145
- * Bind a singleton
146
- */
147
- singleton<T>(
148
- token: Token,
149
- implementation: new (...args: any[]) => T,
150
- ): Container {
151
- return this.bind<T>(token).to(implementation).inSingletonScope().build()
152
- }
153
-
154
- /**
155
- * Bind a transient
156
- */
157
- transient<T>(
158
- token: Token,
159
- implementation: new (...args: any[]) => T,
160
- ): Container {
161
- return this.bind<T>(token).to(implementation).inTransientScope().build()
162
- }
163
-
164
- /**
165
- * Bind a value
166
- */
167
- value<T>(token: Token, value: T): Container {
168
- return this.bind<T>(token).toValue(value).build()
169
- }
170
-
171
- /**
172
- * Bind a factory
173
- */
174
- factory<T>(
175
- token: Token,
176
- factory: (...args: any[]) => T,
177
- ): Container {
178
- return this.bind<T>(token).toFactory(factory).build()
179
- }
180
-
181
- /**
182
- * Resolve a dependency
183
- */
184
- resolve<T>(token: Token, context?: Partial<ResolutionContext>): T {
185
- const resolutionContext: ResolutionContext = {
186
- container: this,
187
- token,
188
- environment: context?.environment || 'development',
189
- requestId: context?.requestId || this.generateRequestId(),
190
- depth: context?.depth || 0,
191
- resolving: context?.resolving || new Set(),
192
- parent: context?.parent,
193
- }
194
-
195
- return this.resolveInternal<T>(token, resolutionContext)
196
- }
197
-
198
- /**
199
- * Resolve all instances of a token (useful for arrays of services)
200
- */
201
- resolveAll<T>(token: Token): T[] {
202
- // Direct binding plus anything tagged with the token (when it's a
203
- // string), deduplicated by token
204
- const tokens = new Set<Token>()
205
- if (this.bindings.has(token)) {
206
- tokens.add(token)
207
- }
208
- if (typeof token === 'string') {
209
- for (const tagged of this.tagIndex.get(token) ?? []) {
210
- tokens.add(tagged)
211
- }
212
- }
213
-
214
- return Array.from(tokens, t => this.resolve<T>(t))
215
- }
216
-
217
- /**
218
- * Resolve with tags
219
- */
220
- resolveTagged<T>(tag: string): T[] {
221
- const tokens = this.tagIndex.get(tag)
222
- if (!tokens || tokens.size === 0) {
223
- return []
224
- }
225
- return Array.from(tokens, token => this.resolve<T>(token))
226
- }
227
-
228
- /**
229
- * Get all bindings with a specific tag
230
- */
231
- getTaggedBindings<T>(tag: string): Binding<T>[] {
232
- const tokens = this.tagIndex.get(tag)
233
- if (!tokens || tokens.size === 0) {
234
- return []
235
- }
236
- const bindings: Binding<T>[] = []
237
- for (const token of tokens) {
238
- const binding = this.bindings.get(token)
239
- if (binding) {
240
- bindings.push(binding as Binding<T>)
241
- }
242
- }
243
- return bindings
244
- }
245
-
246
- /**
247
- * Add interceptor for a service
248
- */
249
- addInterceptor<T>(token: Token, interceptor: (service: T) => T): void {
250
- const key = this.tokenToString(token)
251
- if (!this.interceptors.has(key)) {
252
- this.interceptors.set(key, [])
253
- }
254
- this.interceptors.get(key)!.push(interceptor as (_service: any) => any)
255
- }
256
-
257
- /**
258
- * Register controller (basic implementation for compatibility)
259
- */
260
- registerController(controller: new (...args: any[]) => any): void {
261
- // Basic implementation - just register as singleton
262
- this.singleton(controller, controller)
263
- }
264
-
265
- /**
266
- * Get controller instance
267
- */
268
- getController<T>(controller: new (...args: any[]) => T): T {
269
- return this.resolve<T>(controller)
270
- }
271
-
272
- /**
273
- * Check if a token is bound
274
- */
275
- isBound(token: Token): boolean {
276
- return this.bindings.has(token) || (this.parent?.isBound(token) ?? false)
277
- }
278
-
279
- /**
280
- * Unbind a token
281
- */
282
- unbind(token: Token): this {
283
- const binding = this.bindings.get(token)
284
- if (binding?.metadata?.tags) {
285
- for (const tag of binding.metadata.tags) {
286
- this.tagIndex.get(tag)?.delete(token)
287
- }
288
- }
289
- this.bindings.delete(token)
290
- this.instances.delete(token)
291
- return this
292
- }
293
-
294
- /**
295
- * Create a child container
296
- */
297
- createChild(options?: ContainerOptions): Container {
298
- const child = new Container({ ...this.options, ...options })
299
- child.parent = this
300
- this.children.add(child)
301
- return child
302
- }
303
-
304
- /**
305
- * Create a scoped container
306
- */
307
- createScope(scopeId: string): Container {
308
- const scope = this.createChild()
309
- scope.scopedInstances.set(scopeId, new Map())
310
- return scope
311
- }
312
-
313
- /**
314
- * Get all bindings
315
- */
316
- getBindings(): Map<Token, Binding> {
317
- return new Map(this.bindings)
318
- }
319
-
320
- /**
321
- * Clear all bindings and instances
322
- */
323
- clear(): this {
324
- this.bindings.clear()
325
- this.tagIndex.clear()
326
- this.instances.clear()
327
- this.scopedInstances.clear()
328
- return this
329
- }
330
-
331
- /**
332
- * Add interceptor
333
- */
334
- intercept<T>(
335
- token: string | symbol | ((..._args: any[]) => any),
336
- interceptor: (instance: T, context: ResolutionContext) => T,
337
- ): this {
338
- if (!this.interceptors.has(token)) {
339
- this.interceptors.set(token, [])
340
- }
341
- this.interceptors.get(token)!.push(interceptor)
342
- return this
343
- }
344
-
345
- /**
346
- * Internal resolution logic
347
- */
348
- private resolveInternal<T>(token: Token, context: ResolutionContext): T {
349
- // Check for circular dependencies
350
- if (context.resolving.has(token)) {
351
- // Build the dependency chain for better error message
352
- const chain = Array.from(context.resolving).map(t => this.tokenToString(t))
353
- chain.push(this.tokenToString(token))
354
- throw new CircularDependencyException(chain)
355
- }
356
-
357
- // Check depth limit
358
- if (context.depth > this.options.maxDepth) {
359
- const chain = Array.from(context.resolving).map(t => this.tokenToString(t))
360
- throw new Error(
361
- `Maximum resolution depth exceeded (${this.options.maxDepth}).\n`
362
- + `This usually indicates a circular or very deep dependency chain.\n`
363
- + `Current resolution chain:\n${chain.map((t, i) => ` ${i + 1}. ${t}`).join('\n')}`,
364
- )
365
- }
366
-
367
- context.resolving.add(token)
368
- context.depth++
369
-
370
- try {
371
- // Try to resolve from current container
372
- const binding = this.bindings.get(token)
373
-
374
- if (binding) {
375
- // Check contextual conditions
376
- if (binding.metadata.when && !binding.metadata.when(context)) {
377
- throw new Error(`Contextual binding condition not met for: ${this.tokenToString(token)}`)
378
- }
379
-
380
- return this.createInstance<T>(binding, context)
381
- }
382
-
383
- // Try parent container
384
- if (this.parent) {
385
- // Create a fresh context for parent resolution to avoid false circular dependency detection
386
- const parentContext: ResolutionContext = {
387
- resolving: new Set(),
388
- depth: 0,
389
- container: this.parent,
390
- token,
391
- }
392
- return this.parent.resolveInternal<T>(token, parentContext)
393
- }
394
-
395
- // Auto-registration attempt
396
- if (this.options.autoRegister && typeof token === 'function') {
397
- return this.autoRegisterAndResolve<T>(token as new (..._args: any[]) => T, context)
398
- }
399
-
400
- // Strict mode check
401
- if (this.options.strictMode) {
402
- throw new Error(`No binding found for: ${this.tokenToString(token)}`)
403
- }
404
-
405
- // Try to create instance directly
406
- if (typeof token === 'function') {
407
- return this.createInstanceFromConstructor<T>(token as new (..._args: any[]) => T, context)
408
- }
409
-
410
- throw new Error(`Cannot resolve: ${this.tokenToString(token)}`)
411
- }
412
- finally {
413
- context.resolving.delete(token)
414
- context.depth--
415
- }
416
- }
417
-
418
- /**
419
- * Create instance from binding
420
- */
421
- protected createInstance<T>(binding: Binding<T>, context: ResolutionContext): T {
422
- let instance: T
423
-
424
- // Check for existing singleton
425
- if (binding.metadata.scope === 'singleton' && this.instances.has(binding.token)) {
426
- instance = this.instances.get(binding.token)
427
- }
428
- // Check for scoped instance
429
- else if (binding.metadata.scope === 'scoped' && context.requestId) {
430
- const scopedMap = this.scopedInstances.get(context.requestId)
431
- if (scopedMap?.has(binding.token)) {
432
- instance = scopedMap.get(binding.token)
433
- }
434
- else {
435
- instance = this.createNewInstance<T>(binding, context)
436
- if (!scopedMap) {
437
- this.scopedInstances.set(context.requestId, new Map())
438
- }
439
- this.scopedInstances.get(context.requestId)!.set(binding.token, instance)
440
- }
441
- }
442
- // Create new instance
443
- else {
444
- instance = this.createNewInstance<T>(binding, context)
445
-
446
- // Store singleton
447
- if (binding.metadata.scope === 'singleton') {
448
- this.instances.set(binding.token, instance)
449
- }
450
- }
451
-
452
- // Apply interceptors
453
- const tokenKey = this.tokenToString(binding.token)
454
- if (this.interceptors.has(tokenKey)) {
455
- const interceptors = this.interceptors.get(tokenKey)!
456
- for (const interceptor of interceptors) {
457
- instance = interceptor(instance)
458
- }
459
- }
460
-
461
- return instance
462
- }
463
-
464
- /**
465
- * Create new instance from binding
466
- */
467
- private createNewInstance<T>(binding: Binding<T>, context: ResolutionContext): T {
468
- if (binding.value !== undefined) {
469
- return binding.value
470
- }
471
-
472
- if (binding.factory) {
473
- const dependencies = this.resolveDependencies(binding.metadata.dependencies || [], context)
474
- return binding.factory(...dependencies)
475
- }
476
-
477
- if (binding.instance) {
478
- return binding.instance
479
- }
480
-
481
- if (binding.implementation) {
482
- return this.createInstanceFromConstructor<T>(binding.implementation, context)
483
- }
484
-
485
- throw new Error(`Invalid binding configuration for: ${this.tokenToString(binding.token)}`)
486
- }
487
-
488
- /**
489
- * Create instance from constructor
490
- */
491
- private createInstanceFromConstructor<T>(
492
- constructor: new (...args: any[]) => T,
493
- context: ResolutionContext,
494
- ): T {
495
- const dependencies = this.getConstructorDependencies(constructor)
496
- const resolvedDependencies = this.resolveDependencies(dependencies, context)
497
-
498
- const instance = new constructor(...resolvedDependencies)
499
-
500
- // Apply decorators if enabled
501
- if (this.options.enableDecorators) {
502
- this.applyDecorators(instance, constructor)
503
- }
504
-
505
- return instance
506
- }
507
-
508
- /**
509
- * Get constructor dependencies using reflection
510
- */
511
- private getConstructorDependencies(constructor: ((...args: any[]) => any) | (new (...args: any[]) => any)): Token[] {
512
- // Check for explicit metadata
513
- let injectMetadata = Reflect.getMetadata?.(INJECT_METADATA_KEY, constructor) as InjectMetadata[]
514
- || (constructor as any)[INJECT_METADATA_KEY] as InjectMetadata[]
515
-
516
- // If not found on the constructor itself, check the constructor property
517
- // For classes, the metadata might be stored on the constructor property
518
- if (!injectMetadata && (constructor as any).constructor) {
519
- injectMetadata = (constructor as any).constructor[INJECT_METADATA_KEY] as InjectMetadata[]
520
- }
521
-
522
- // Also check if this is a class and the metadata is on the class itself
523
- if (!injectMetadata && typeof constructor === 'function' && constructor.prototype) {
524
- // This is a class constructor, check if metadata is stored on the class
525
- const classMetadata = (constructor as any)[INJECT_METADATA_KEY] as InjectMetadata[]
526
- if (classMetadata) {
527
- injectMetadata = classMetadata
528
- }
529
- }
530
-
531
- // Final check: if this is a class, look for metadata on the class itself
532
- if (!injectMetadata && typeof constructor === 'function') {
533
- const directMetadata = (constructor as any)[INJECT_METADATA_KEY] as InjectMetadata[]
534
- if (directMetadata) {
535
- injectMetadata = directMetadata
536
- }
537
- }
538
-
539
- if (injectMetadata) {
540
- return injectMetadata.map(meta => meta.token)
541
- }
542
-
543
- // Try to get parameter types from TypeScript metadata
544
- const paramTypes = Reflect.getMetadata?.('design:paramtypes', constructor) as Token[]
545
- if (paramTypes) {
546
- return paramTypes
547
- }
548
-
549
- // Fallback to parsing constructor string (less reliable)
550
- return this.parseConstructorDependencies(constructor)
551
- }
552
-
553
- /**
554
- * Parse constructor dependencies from function string
555
- */
556
- private parseConstructorDependencies(constructor: ((...args: any[]) => any) | (new (...args: any[]) => any)): string[] {
557
- const constructorString = constructor.toString()
558
- const match = constructorString.match(/constructor\s*\(([^)]*)\)/)
559
-
560
- if (!match || !match[1]) {
561
- return []
562
- }
563
-
564
- return match[1]
565
- .split(',')
566
- .map(param => param.trim().split(':')[0].trim())
567
- .filter(param => param.length > 0)
568
- }
569
-
570
- /**
571
- * Resolve array of dependencies
572
- */
573
- private resolveDependencies(
574
- dependencies: Token[],
575
- context: ResolutionContext,
576
- ): any[] {
577
- return dependencies.map(dep => this.resolveInternal(dep, context))
578
- }
579
-
580
- /**
581
- * Auto-register and resolve
582
- */
583
- private autoRegisterAndResolve<T>(
584
- constructor: new (...args: any[]) => T,
585
- context: ResolutionContext,
586
- ): T {
587
- // Check for injectable metadata
588
- const metadata = Reflect.getMetadata?.(INJECTABLE_METADATA_KEY, constructor) as InjectableMetadata
589
-
590
- const binding: Binding<T> = {
591
- token: constructor,
592
- implementation: constructor,
593
- metadata: {
594
- scope: metadata?.scope || this.options.defaultScope,
595
- tags: metadata?.tags,
596
- },
597
- }
598
-
599
- this.register(binding)
600
- return this.resolveInternal<T>(constructor, context)
601
- }
602
-
603
- /**
604
- * Apply decorators to instance
605
- */
606
- private applyDecorators(instance: any, constructor: ((..._args: any[]) => any) | (new (..._args: any[]) => any)): void {
607
- const decorators = Reflect.getMetadata?.('decorators', constructor) as ((..._args: any[]) => any)[]
608
- if (decorators) {
609
- for (const decorator of decorators) {
610
- decorator(instance)
611
- }
612
- }
613
- }
614
-
615
- /**
616
- * Check if binding has tag
617
- */
618
- private hasTag(binding: Binding, tag: string): boolean {
619
- return binding.metadata.tags?.includes(tag) ?? false
620
- }
621
-
622
- /**
623
- * Convert token to string for error messages
624
- */
625
- private tokenToString(token: Token): string {
626
- if (typeof token === 'string')
627
- return token
628
- if (typeof token === 'symbol')
629
- return token.toString()
630
- if (typeof token === 'function')
631
- return token.name || 'anonymous'
632
- return 'unknown'
633
- }
634
-
635
- /**
636
- * Generate unique request ID
637
- */
638
- private generateRequestId(): string {
639
- return `req_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`
640
- }
641
- }
642
-
643
- /**
644
- * Fluent binding builder
645
- */
646
- export class BindingBuilder<T> {
647
- private binding: Partial<Binding<T>>
648
-
649
- constructor(private container: Container, token: Token) {
650
- this.binding = {
651
- token,
652
- metadata: {
653
- scope: 'transient',
654
- },
655
- }
656
- }
657
-
658
- /**
659
- * Bind to implementation
660
- */
661
- to(implementation: new (...args: any[]) => T): this {
662
- this.binding.implementation = implementation
663
- return this
664
- }
665
-
666
- /**
667
- * Bind to value
668
- */
669
- toValue(value: T): this {
670
- this.binding.value = value
671
- this.binding.metadata!.scope = 'singleton'
672
- return this
673
- }
674
-
675
- /**
676
- * Bind to factory
677
- */
678
- toFactory(factory: (...args: any[]) => T): this {
679
- this.binding.factory = factory
680
- return this
681
- }
682
-
683
- /**
684
- * Bind to existing instance
685
- */
686
- toInstance(instance: T): this {
687
- this.binding.instance = instance
688
- this.binding.metadata!.scope = 'singleton'
689
- return this
690
- }
691
-
692
- /**
693
- * Set singleton scope
694
- */
695
- inSingletonScope(): this {
696
- this.binding.metadata!.scope = 'singleton'
697
- return this
698
- }
699
-
700
- /**
701
- * Set transient scope
702
- */
703
- inTransientScope(): this {
704
- this.binding.metadata!.scope = 'transient'
705
- return this
706
- }
707
-
708
- /**
709
- * Set scoped scope
710
- */
711
- inScopedScope(): this {
712
- this.binding.metadata!.scope = 'scoped'
713
- return this
714
- }
715
-
716
- /**
717
- * Set request scope
718
- */
719
- inRequestScope(): this {
720
- this.binding.metadata!.scope = 'request'
721
- return this
722
- }
723
-
724
- /**
725
- * Add tags
726
- */
727
- withTags(...tags: string[]): this {
728
- this.binding.metadata!.tags = [...(this.binding.metadata!.tags || []), ...tags]
729
- return this
730
- }
731
-
732
- /**
733
- * Add contextual condition
734
- */
735
- when(condition: (context: ResolutionContext) => boolean): this {
736
- this.binding.metadata!.when = condition
737
- return this
738
- }
739
-
740
- /**
741
- * Set as lazy
742
- */
743
- lazy(): this {
744
- this.binding.metadata!.lazy = true
745
- return this
746
- }
747
-
748
- /**
749
- * Build and register binding
750
- */
751
- build(): Container {
752
- this.container.register(this.binding as Binding<T>)
753
- return this.container
754
- }
755
- }
756
-
757
- /**
758
- * Global container instance
759
- */
760
- let globalContainer: Container | null = null
761
-
762
- /**
763
- * Get or create global container
764
- */
765
- export function getContainer(): Container {
766
- if (!globalContainer) {
767
- globalContainer = new Container()
768
- }
769
- return globalContainer
770
- }
771
-
772
- /**
773
- * Set global container
774
- */
775
- export function setContainer(container: Container): void {
776
- globalContainer = container
777
- }
778
-
779
- /**
780
- * Create new container
781
- */
782
- export function createContainer(options?: ContainerOptions): Container {
783
- return new Container(options)
784
- }
785
-
786
- export { Container as DIContainer }