@stacksjs/bun-router 0.0.17 → 0.0.18

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 (146) hide show
  1. package/dist/cli.js +1 -1
  2. package/dist/container/service-provider.d.ts +3 -3
  3. package/dist/development/performance-profiler.d.ts +3 -3
  4. package/dist/development/route-debugger.d.ts +1 -1
  5. package/dist/development/route-inspector.d.ts +2 -2
  6. package/dist/observability/integration.d.ts +1 -1
  7. package/dist/response/macros.d.ts +1 -1
  8. package/dist/router/index.d.ts +7 -7
  9. package/dist/router/router.d.ts +0 -32
  10. package/dist/testing/performance-testing.d.ts +2 -2
  11. package/dist/testing/test-client.d.ts +1 -1
  12. package/dist/testing/websocket-testing.d.ts +1 -1
  13. package/package.json +2 -3
  14. package/src/auth.ts +0 -489
  15. package/src/cache/lru-cache.ts +0 -457
  16. package/src/cache/middleware-memoization.ts +0 -531
  17. package/src/cache/route-cache-warmer.ts +0 -486
  18. package/src/cache/sqlite-cache.ts +0 -783
  19. package/src/cache/streaming-cache.ts +0 -572
  20. package/src/cli/colors.ts +0 -29
  21. package/src/cli/index.ts +0 -287
  22. package/src/cli/middleware.ts +0 -291
  23. package/src/cli/openapi.ts +0 -407
  24. package/src/cli/router.ts +0 -188
  25. package/src/cli/routes.ts +0 -265
  26. package/src/cli/utils.ts +0 -531
  27. package/src/cli.ts +0 -5
  28. package/src/config.ts +0 -322
  29. package/src/container/container.ts +0 -786
  30. package/src/container/contextual-binding.ts +0 -606
  31. package/src/container/decorators.ts +0 -368
  32. package/src/container/index.ts +0 -49
  33. package/src/container/service-provider.ts +0 -596
  34. package/src/development/hot-reload.ts +0 -673
  35. package/src/development/index.ts +0 -499
  36. package/src/development/performance-profiler.ts +0 -717
  37. package/src/development/route-debugger.ts +0 -527
  38. package/src/development/route-inspector.ts +0 -749
  39. package/src/development/typescript-utilities.ts +0 -682
  40. package/src/docs.ts +0 -397
  41. package/src/errors/circuit-breaker.ts +0 -733
  42. package/src/errors/error-handler.ts +0 -569
  43. package/src/errors/error-reporting.ts +0 -672
  44. package/src/errors/exceptions.ts +0 -536
  45. package/src/errors/graceful-degradation.ts +0 -623
  46. package/src/errors/index.ts +0 -21
  47. package/src/errors/router-errors.ts +0 -632
  48. package/src/file-serving/static-files.ts +0 -718
  49. package/src/index.ts +0 -66
  50. package/src/middleware/auth.ts +0 -220
  51. package/src/middleware/content_security_policy.ts +0 -215
  52. package/src/middleware/cors.ts +0 -142
  53. package/src/middleware/csrf.ts +0 -166
  54. package/src/middleware/ddos_protection.ts +0 -279
  55. package/src/middleware/file_security.ts +0 -191
  56. package/src/middleware/file_upload.ts +0 -275
  57. package/src/middleware/helmet.ts +0 -268
  58. package/src/middleware/index.ts +0 -117
  59. package/src/middleware/input_validation.ts +0 -453
  60. package/src/middleware/json_body.ts +0 -37
  61. package/src/middleware/performance_alerting.ts +0 -540
  62. package/src/middleware/performance_dashboard.ts +0 -661
  63. package/src/middleware/performance_monitor.ts +0 -945
  64. package/src/middleware/pipeline.ts +0 -489
  65. package/src/middleware/rate_limit.ts +0 -251
  66. package/src/middleware/request_id.ts +0 -36
  67. package/src/middleware/request_signing.ts +0 -638
  68. package/src/middleware/request_tracer.ts +0 -653
  69. package/src/middleware/response_cache.ts +0 -778
  70. package/src/middleware/security.ts +0 -482
  71. package/src/middleware/security_suite.ts +0 -257
  72. package/src/middleware/session.ts +0 -91
  73. package/src/model-binding/index.ts +0 -18
  74. package/src/model-binding/model-middleware.ts +0 -425
  75. package/src/model-binding/model-registry.ts +0 -550
  76. package/src/model-binding.ts +0 -370
  77. package/src/model-resolver-factory.ts +0 -106
  78. package/src/observability/correlation.ts +0 -691
  79. package/src/observability/health-checks.ts +0 -729
  80. package/src/observability/index.ts +0 -184
  81. package/src/observability/integration.ts +0 -548
  82. package/src/observability/metrics.ts +0 -753
  83. package/src/observability/tracing.ts +0 -638
  84. package/src/optimization/bun-utilities.ts +0 -778
  85. package/src/query-builder-integration.ts +0 -137
  86. package/src/request/context.ts +0 -109
  87. package/src/request/enhanced-request.ts +0 -876
  88. package/src/request/macros.ts +0 -822
  89. package/src/response/macros.ts +0 -665
  90. package/src/response/response-factory.ts +0 -596
  91. package/src/router/api-routes.ts +0 -243
  92. package/src/router/file-based-routing.ts +0 -697
  93. package/src/router/file-streaming.ts +0 -383
  94. package/src/router/fluent-routing.ts +0 -866
  95. package/src/router/group-organization.ts +0 -229
  96. package/src/router/handler-resolver.ts +0 -327
  97. package/src/router/http-methods.ts +0 -407
  98. package/src/router/index.ts +0 -193
  99. package/src/router/middleware-groups.ts +0 -222
  100. package/src/router/middleware-integration.ts +0 -399
  101. package/src/router/middleware.ts +0 -234
  102. package/src/router/model-binding.ts +0 -215
  103. package/src/router/optimized-route-matching.ts +0 -302
  104. package/src/router/route-building.ts +0 -221
  105. package/src/router/route-compiler.ts +0 -691
  106. package/src/router/route-matching.ts +0 -368
  107. package/src/router/route-trie.ts +0 -450
  108. package/src/router/router.ts +0 -1616
  109. package/src/router/server.ts +0 -684
  110. package/src/router/validation-integration.ts +0 -449
  111. package/src/router/view-rendering.ts +0 -233
  112. package/src/router/websocket.ts +0 -100
  113. package/src/routing/route-caching.ts +0 -402
  114. package/src/routing/route-throttling.ts +0 -469
  115. package/src/routing/subdomain-routing.ts +0 -492
  116. package/src/session/database-store.ts +0 -109
  117. package/src/session/file-store.ts +0 -148
  118. package/src/session/index.ts +0 -244
  119. package/src/session/memory-store.ts +0 -88
  120. package/src/session/redis-store.ts +0 -93
  121. package/src/streaming/index.ts +0 -17
  122. package/src/streaming/sse-handler.ts +0 -482
  123. package/src/streaming/stream-handler.ts +0 -552
  124. package/src/testing/auth-testing.ts +0 -448
  125. package/src/testing/file-upload-testing.ts +0 -543
  126. package/src/testing/index.ts +0 -10
  127. package/src/testing/middleware-testing.ts +0 -322
  128. package/src/testing/model-binding-testing.ts +0 -645
  129. package/src/testing/performance-testing.ts +0 -738
  130. package/src/testing/test-client.ts +0 -310
  131. package/src/testing/test-request.ts +0 -315
  132. package/src/testing/test-response.ts +0 -332
  133. package/src/testing/types.ts +0 -224
  134. package/src/testing/websocket-testing.ts +0 -590
  135. package/src/types/controller-types.ts +0 -385
  136. package/src/types/core.ts +0 -683
  137. package/src/types/middleware-types.ts +0 -422
  138. package/src/types/request-response-augmentation.ts +0 -489
  139. package/src/types/route-inference.ts +0 -372
  140. package/src/types.ts +0 -2123
  141. package/src/url.ts +0 -131
  142. package/src/utils/index.ts +0 -1
  143. package/src/utils/query-preservation.ts +0 -201
  144. package/src/utils.ts +0 -395
  145. package/src/validation/validator.ts +0 -688
  146. 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 }