@navios/core 1.0.0-alpha.2 → 1.0.0-alpha.4

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 (93) hide show
  1. package/CHANGELOG.md +90 -0
  2. package/lib/{index-BJjk2X1S.d.mts → index-6S7veHKD.d.mts} +845 -294
  3. package/lib/index-6S7veHKD.d.mts.map +1 -0
  4. package/lib/{index-DZ6NU03y.d.cts → index-r0i2txmg.d.cts} +845 -294
  5. package/lib/index-r0i2txmg.d.cts.map +1 -0
  6. package/lib/index.cjs +4420 -84
  7. package/lib/index.cjs.map +1 -0
  8. package/lib/index.d.cts +2 -2
  9. package/lib/index.d.mts +2 -2
  10. package/lib/index.mjs +4328 -3
  11. package/lib/index.mjs.map +1 -0
  12. package/lib/legacy-compat/index.cjs +41 -126
  13. package/lib/legacy-compat/index.cjs.map +1 -1
  14. package/lib/legacy-compat/index.d.cts +4 -60
  15. package/lib/legacy-compat/index.d.cts.map +1 -1
  16. package/lib/legacy-compat/index.d.mts +4 -60
  17. package/lib/legacy-compat/index.d.mts.map +1 -1
  18. package/lib/legacy-compat/index.mjs +14 -119
  19. package/lib/legacy-compat/index.mjs.map +1 -1
  20. package/lib/navios.factory-BanZIvtR.cjs +4134 -0
  21. package/lib/navios.factory-BanZIvtR.cjs.map +1 -0
  22. package/lib/navios.factory-C75yZCoD.mjs +3831 -0
  23. package/lib/navios.factory-C75yZCoD.mjs.map +1 -0
  24. package/lib/testing/index.cjs +3 -3
  25. package/lib/testing/index.cjs.map +1 -1
  26. package/lib/testing/index.d.cts +1 -1
  27. package/lib/testing/index.d.mts +1 -1
  28. package/lib/testing/index.mjs +2 -2
  29. package/lib/tokens-4J9sredA.mjs +100 -0
  30. package/lib/tokens-4J9sredA.mjs.map +1 -0
  31. package/lib/tokens-BuXXB01L.cjs +196 -0
  32. package/lib/tokens-BuXXB01L.cjs.map +1 -0
  33. package/lib/{use-guards.decorator-Be_QUx6b.mjs → use-guards.decorator-BecoQSmE.mjs} +3 -70
  34. package/lib/use-guards.decorator-BecoQSmE.mjs.map +1 -0
  35. package/lib/{use-guards.decorator-B6tghdxM.cjs → use-guards.decorator-DgD-kxF5.cjs} +7 -158
  36. package/lib/use-guards.decorator-DgD-kxF5.cjs.map +1 -0
  37. package/package.json +4 -4
  38. package/src/__tests__/attribute.factory.spec.mts +300 -0
  39. package/src/__tests__/console-logger.service.spec.mts +312 -0
  40. package/src/__tests__/guard-runner.service.spec.mts +399 -0
  41. package/src/__tests__/logger.service.spec.mts +147 -0
  42. package/src/__tests__/responders.spec.mts +6 -5
  43. package/src/factories/adapter.factory.mts +20 -0
  44. package/src/factories/endpoint-adapter.factory.mts +1 -1
  45. package/src/factories/http-adapter.factory.mts +1 -1
  46. package/src/factories/index.mts +1 -0
  47. package/src/factories/multipart-adapter.factory.mts +1 -1
  48. package/src/factories/reply.factory.mts +1 -1
  49. package/src/factories/request.factory.mts +1 -1
  50. package/src/factories/stream-adapter.factory.mts +1 -1
  51. package/src/factories/xml-stream-adapter.factory.mts +1 -1
  52. package/src/index.mts +1 -0
  53. package/src/interfaces/abstract-adapter.interface.mts +32 -0
  54. package/src/interfaces/abstract-http-adapter.interface.mts +27 -20
  55. package/src/interfaces/abstract-http-handler-adapter.interface.mts +86 -2
  56. package/src/interfaces/adapter-environment.interface.mts +74 -0
  57. package/src/interfaces/index.mts +2 -0
  58. package/src/interfaces/plugin.interface.mts +50 -16
  59. package/src/legacy-compat/attribute.factory.mts +2 -2
  60. package/src/legacy-compat/decorators/controller.decorator.mts +1 -1
  61. package/src/legacy-compat/decorators/endpoint.decorator.mts +1 -1
  62. package/src/legacy-compat/decorators/header.decorator.mts +2 -1
  63. package/src/legacy-compat/decorators/http-code.decorator.mts +2 -1
  64. package/src/legacy-compat/decorators/index.mts +2 -2
  65. package/src/legacy-compat/decorators/module.decorator.mts +1 -1
  66. package/src/legacy-compat/decorators/multipart.decorator.mts +1 -1
  67. package/src/legacy-compat/decorators/stream.decorator.mts +1 -1
  68. package/src/legacy-compat/decorators/use-guards.decorator.mts +1 -1
  69. package/src/legacy-compat/index.mts +10 -5
  70. package/src/logger/console-logger.service.mts +97 -7
  71. package/src/metadata/module.metadata.mts +43 -0
  72. package/src/navios.application.mts +172 -60
  73. package/src/navios.environment.mts +22 -12
  74. package/src/navios.factory.mts +31 -10
  75. package/src/services/abstract-handler-adapter.service.mts +366 -0
  76. package/src/services/index.mts +1 -0
  77. package/src/services/module-loader.service.mts +1 -0
  78. package/src/tokens/adapter.token.mts +6 -0
  79. package/src/tokens/http-adapter.token.mts +1 -1
  80. package/src/tokens/index.mts +1 -0
  81. package/src/utils/adapter-supports.util.mts +47 -0
  82. package/src/utils/index.mts +1 -0
  83. package/lib/index-BJjk2X1S.d.mts.map +0 -1
  84. package/lib/index-DZ6NU03y.d.cts.map +0 -1
  85. package/lib/src-C46ePe3d.cjs +0 -8022
  86. package/lib/src-C46ePe3d.cjs.map +0 -1
  87. package/lib/src-K2k0riYJ.mjs +0 -7587
  88. package/lib/src-K2k0riYJ.mjs.map +0 -1
  89. package/lib/use-guards.decorator-B6tghdxM.cjs.map +0 -1
  90. package/lib/use-guards.decorator-Be_QUx6b.mjs.map +0 -1
  91. package/src/legacy-compat/context-compat.mts +0 -95
  92. package/src/legacy-compat/decorators/factory.decorator.mts +0 -37
  93. package/src/legacy-compat/decorators/injectable.decorator.mts +0 -41
@@ -30,15 +30,46 @@ export interface ConsoleLoggerOptions {
30
30
  */
31
31
  logLevels?: LogLevel[]
32
32
  /**
33
- * If enabled, will print timestamp (time difference) between current and previous log message.
33
+ * If enabled, will print timestamp difference between current and previous log message.
34
34
  * Note: This option is not used when `json` is enabled.
35
+ * @default false
35
36
  */
36
- timestamp?: boolean
37
+ showTimeDiff?: boolean
37
38
  /**
38
39
  * A prefix to be used for each log message.
39
40
  * Note: This option is not used when `json` is enabled.
40
41
  */
41
42
  prefix?: string
43
+ /**
44
+ * If true, will print the process ID in the log message.
45
+ * Note: This option is not used when `json` is enabled.
46
+ * @default true
47
+ */
48
+ showPid?: boolean
49
+ /**
50
+ * If true, will print the log level in the log message.
51
+ * Note: This option is not used when `json` is enabled.
52
+ * @default true
53
+ */
54
+ showLogLevel?: boolean
55
+ /**
56
+ * If true, will print the prefix/app name in the log message.
57
+ * Note: This option is not used when `json` is enabled.
58
+ * @default true
59
+ */
60
+ showPrefix?: boolean
61
+ /**
62
+ * If true, will print the context in the log message.
63
+ * Note: This option is not used when `json` is enabled.
64
+ * @default true
65
+ */
66
+ showContext?: boolean
67
+ /**
68
+ * If true, will print the absolute timestamp in the log message.
69
+ * Note: This option is not used when `json` is enabled.
70
+ * @default true
71
+ */
72
+ showTimestamp?: boolean
42
73
  /**
43
74
  * If enabled, will add a request ID to the log message.
44
75
  */
@@ -129,6 +160,31 @@ const dateTimeFormatter = new Intl.DateTimeFormat(undefined, {
129
160
  token: LoggerOutput,
130
161
  })
131
162
  export class ConsoleLogger implements LoggerService {
163
+ /**
164
+ * Creates a new ConsoleLogger instance with the given options.
165
+ * This is a convenience method that instantiates and sets up the logger in one call.
166
+ */
167
+ static create(): ConsoleLogger
168
+ static create(context: string): ConsoleLogger
169
+ static create(options: ConsoleLoggerOptions): ConsoleLogger
170
+ static create(context: string, options: ConsoleLoggerOptions): ConsoleLogger
171
+ static create(
172
+ contextOrOptions?: string | ConsoleLoggerOptions,
173
+ options?: ConsoleLoggerOptions,
174
+ ): ConsoleLogger {
175
+ const logger = new ConsoleLogger()
176
+ if (contextOrOptions !== undefined) {
177
+ if (typeof contextOrOptions === 'string') {
178
+ logger.setup(contextOrOptions, options ?? {})
179
+ } else {
180
+ logger.setup(contextOrOptions)
181
+ }
182
+ } else {
183
+ logger.setup()
184
+ }
185
+ return logger
186
+ }
187
+
132
188
  /**
133
189
  * The options of the logger.
134
190
  */
@@ -412,11 +468,24 @@ export class ConsoleLogger implements LoggerService {
412
468
  }
413
469
 
414
470
  protected formatPid(pid: number) {
415
- return `[${this.options.prefix}] ${pid} - `
471
+ const showPrefix = this.options.showPrefix ?? true
472
+ const showPid = this.options.showPid ?? true
473
+
474
+ if (!showPrefix && !showPid) {
475
+ return ''
476
+ }
477
+
478
+ const prefix = showPrefix ? `[${this.options.prefix}]` : ''
479
+ const pidPart = showPid ? `${pid}` : ''
480
+ const separator = showPrefix && showPid ? ' ' : ''
481
+ const suffix = showPrefix || showPid ? ' - ' : ''
482
+
483
+ return `${prefix}${separator}${pidPart}${suffix}`
416
484
  }
417
485
 
418
486
  protected formatContext(context: string): string {
419
- if (!context) {
487
+ const showContext = this.options.showContext ?? true
488
+ if (!context || !showContext) {
420
489
  return ''
421
490
  }
422
491
 
@@ -434,9 +503,29 @@ export class ConsoleLogger implements LoggerService {
434
503
  requestId?: string,
435
504
  ) {
436
505
  const output = this.stringifyMessage(message, logLevel)
506
+ const showLogLevel = this.options.showLogLevel ?? true
507
+ const showTimestamp = this.options.showTimestamp ?? true
508
+
437
509
  pidMessage = this.colorize(pidMessage, logLevel)
438
- formattedLogLevel = this.colorize(formattedLogLevel, logLevel)
439
- return `${pidMessage}${this.getRequestId(requestId)}${this.getTimestamp()} ${formattedLogLevel} ${contextMessage}${output}${timestampDiff}\n`
510
+ formattedLogLevel = showLogLevel
511
+ ? this.colorize(formattedLogLevel, logLevel)
512
+ : ''
513
+
514
+ const timestamp = showTimestamp ? this.getTimestamp() : ''
515
+ const requestIdPart = this.getRequestId(requestId)
516
+
517
+ // Build the message parts, filtering out empty ones
518
+ const parts: string[] = []
519
+
520
+ if (pidMessage) parts.push(pidMessage.trimEnd())
521
+ if (requestIdPart) parts.push(requestIdPart.trimEnd())
522
+ if (timestamp) parts.push(timestamp)
523
+ if (formattedLogLevel) parts.push(formattedLogLevel)
524
+ if (contextMessage) parts.push(contextMessage.trimEnd())
525
+
526
+ const prefix = parts.length > 0 ? parts.join(' ') + ' ' : ''
527
+
528
+ return `${prefix}${output}${timestampDiff}\n`
440
529
  }
441
530
 
442
531
  protected getRequestId(requestId?: string) {
@@ -488,7 +577,8 @@ export class ConsoleLogger implements LoggerService {
488
577
  }
489
578
 
490
579
  protected updateAndGetTimestampDiff(): string {
491
- const includeTimestamp = this.lastTimestampAt && this.options?.timestamp
580
+ const showTimeDiff = this.options?.showTimeDiff ?? false
581
+ const includeTimestamp = this.lastTimestampAt && showTimeDiff
492
582
  const result = includeTimestamp
493
583
  ? this.formatTimestampDiff(Date.now() - this.lastTimestampAt!)
494
584
  : ''
@@ -16,6 +16,17 @@ export interface ModuleMetadata {
16
16
  >
17
17
  overrides: Set<ClassType>
18
18
  customAttributes: Map<string | symbol, any>
19
+ /**
20
+ * Extensible entries for adapter-specific data.
21
+ * Adapters can store custom metadata using symbol keys.
22
+ *
23
+ * @example
24
+ * ```typescript
25
+ * const CommandEntryKey = Symbol('CommandEntryKey')
26
+ * metadata.customEntries.set(CommandEntryKey, new Set([Command1, Command2]))
27
+ * ```
28
+ */
29
+ customEntries: Map<symbol, unknown>
19
30
  }
20
31
 
21
32
  export function getModuleMetadata(
@@ -38,6 +49,7 @@ export function getModuleMetadata(
38
49
  >(),
39
50
  overrides: new Set<ClassType>(),
40
51
  customAttributes: new Map<string | symbol, any>(),
52
+ customEntries: new Map<symbol, unknown>(),
41
53
  }
42
54
  context.metadata[ModuleMetadataKey] = newMetadata
43
55
  // @ts-expect-error We add a custom metadata key to the target
@@ -63,3 +75,34 @@ export function hasModuleMetadata(target: ClassType): boolean {
63
75
  // @ts-expect-error We add a custom metadata key to the target
64
76
  return !!target[ModuleMetadataKey]
65
77
  }
78
+
79
+ /**
80
+ * Type-safe helper to get or create a custom entry in module metadata.
81
+ * Adapters use this to store their own metadata in modules.
82
+ *
83
+ * @param metadata - The module metadata object
84
+ * @param key - Symbol key for the custom entry
85
+ * @param defaultValue - Factory function to create default value if entry doesn't exist
86
+ * @returns The existing or newly created entry value
87
+ *
88
+ * @example
89
+ * ```typescript
90
+ * const CommandEntryKey = Symbol('CommandEntryKey')
91
+ * const commands = getModuleCustomEntry<Set<ClassType>>(
92
+ * metadata,
93
+ * CommandEntryKey,
94
+ * () => new Set(),
95
+ * )
96
+ * commands.add(MyCommand)
97
+ * ```
98
+ */
99
+ export function getModuleCustomEntry<T>(
100
+ metadata: ModuleMetadata,
101
+ key: symbol,
102
+ defaultValue: () => T,
103
+ ): T {
104
+ if (!metadata.customEntries.has(key)) {
105
+ metadata.customEntries.set(key, defaultValue())
106
+ }
107
+ return metadata.customEntries.get(key) as T
108
+ }
@@ -1,10 +1,26 @@
1
- import type { ClassTypeWithInstance, Registry } from '@navios/di'
1
+ import type {
2
+ ClassType,
3
+ ClassTypeWithArgument,
4
+ ClassTypeWithInstance,
5
+ InjectionTokenSchemaType,
6
+ Registry,
7
+ } from '@navios/di'
8
+ import type { z } from 'zod/v4'
2
9
 
3
- import { Container, inject, Injectable } from '@navios/di'
10
+ import {
11
+ BoundInjectionToken,
12
+ Container,
13
+ FactoryInjectionToken,
14
+ inject,
15
+ Injectable,
16
+ InjectionToken,
17
+ } from '@navios/di'
4
18
 
5
19
  import type {
6
- AbstractHttpAdapterInterface,
7
- AbstractHttpListenOptions,
20
+ AbstractAdapterInterface,
21
+ AdapterEnvironment,
22
+ DefaultAdapterEnvironment,
23
+ HttpAdapterEnvironment,
8
24
  NaviosModule,
9
25
  PluginContext,
10
26
  PluginDefinition,
@@ -12,10 +28,11 @@ import type {
12
28
  import type { LoggerService, LogLevel } from './logger/index.mjs'
13
29
  import type { NaviosEnvironmentOptions } from './navios.environment.mjs'
14
30
 
15
- import { HttpAdapterToken } from './index.mjs'
16
31
  import { Logger } from './logger/index.mjs'
17
32
  import { NaviosEnvironment } from './navios.environment.mjs'
18
33
  import { ModuleLoaderService } from './services/index.mjs'
34
+ import { AdapterToken } from './tokens/index.mjs'
35
+ import { assertAdapterSupports } from './utils/index.mjs'
19
36
 
20
37
  /**
21
38
  * Options for configuring the Navios application context.
@@ -44,14 +61,14 @@ export interface NaviosApplicationOptions {
44
61
  container?: Container
45
62
 
46
63
  /**
47
- * HTTP adapter environment(s) to use for the application.
64
+ * Adapter environment(s) to use for the application.
48
65
  * Can be a single adapter or an array of adapters.
49
66
  *
50
67
  * @example
51
68
  * ```typescript
52
69
  * adapter: defineFastifyEnvironment()
53
70
  * // or
54
- * adapter: [defineFastifyEnvironment(), defineBunEnvironment()]
71
+ * adapter: [defineFastifyEnvironment()]
55
72
  * ```
56
73
  */
57
74
  adapter: NaviosEnvironmentOptions | NaviosEnvironmentOptions[]
@@ -75,7 +92,7 @@ export interface NaviosApplicationOptions {
75
92
  * Main application class for Navios.
76
93
  *
77
94
  * This class represents a Navios application instance and provides methods
78
- * for initializing, configuring, and managing the HTTP server.
95
+ * for initializing, configuring, and managing the application lifecycle.
79
96
  *
80
97
  * @example
81
98
  * ```typescript
@@ -90,10 +107,12 @@ export interface NaviosApplicationOptions {
90
107
  * ```
91
108
  */
92
109
  @Injectable()
93
- export class NaviosApplication {
110
+ export class NaviosApplication<
111
+ Environment extends AdapterEnvironment = DefaultAdapterEnvironment,
112
+ > {
94
113
  private environment = inject(NaviosEnvironment)
95
114
  private moduleLoader = inject(ModuleLoaderService)
96
- private httpApplication: AbstractHttpAdapterInterface<any> | null = null
115
+ private adapter: Environment['adapter'] | null = null
97
116
  private logger = inject(Logger, {
98
117
  context: NaviosApplication.name,
99
118
  })
@@ -103,7 +122,7 @@ export class NaviosApplication {
103
122
  private options: NaviosApplicationOptions = {
104
123
  adapter: [],
105
124
  }
106
- private plugins: PluginDefinition<any>[] = []
125
+ private plugins: PluginDefinition<any, any>[] = []
107
126
 
108
127
  /**
109
128
  * Indicates whether the application has been initialized.
@@ -127,8 +146,10 @@ export class NaviosApplication {
127
146
  ) {
128
147
  this.appModule = appModule
129
148
  this.options = options
130
- if (this.environment.hasHttpSetup()) {
131
- this.httpApplication = await this.container.get(HttpAdapterToken)
149
+ if (this.environment.hasAdapterSetup()) {
150
+ this.adapter = (await this.container.get(
151
+ AdapterToken,
152
+ )) as Environment['adapter']
132
153
  }
133
154
  }
134
155
 
@@ -141,6 +162,19 @@ export class NaviosApplication {
141
162
  return this.container
142
163
  }
143
164
 
165
+ /**
166
+ * Returns the current adapter instance.
167
+ *
168
+ * @returns The adapter instance
169
+ * @throws Error if adapter is not initialized
170
+ */
171
+ getAdapter(): Environment['adapter'] {
172
+ if (!this.adapter) {
173
+ throw new Error('Adapter not initialized')
174
+ }
175
+ return this.adapter
176
+ }
177
+
144
178
  /**
145
179
  * Registers a plugin to be initialized after modules are loaded.
146
180
  *
@@ -159,7 +193,9 @@ export class NaviosApplication {
159
193
  * }))
160
194
  * ```
161
195
  */
162
- usePlugin<TOptions>(definition: PluginDefinition<TOptions>): this {
196
+ usePlugin<TOptions, TAdapter extends AbstractAdapterInterface>(
197
+ definition: PluginDefinition<TOptions, TAdapter>,
198
+ ): this {
163
199
  this.plugins.push(definition)
164
200
  return this
165
201
  }
@@ -169,7 +205,7 @@ export class NaviosApplication {
169
205
  *
170
206
  * This method:
171
207
  * - Loads all modules and their dependencies
172
- * - Sets up the HTTP server if an adapter is configured
208
+ * - Sets up the adapter if one is configured
173
209
  * - Calls onModuleInit hooks on all modules
174
210
  * - Initializes registered plugins
175
211
  * - Marks the application as initialized
@@ -192,13 +228,16 @@ export class NaviosApplication {
192
228
  throw new Error('App module is not set. Call setAppModule() first.')
193
229
  }
194
230
  await this.moduleLoader.loadModules(this.appModule)
195
- if (this.environment.hasHttpSetup()) {
196
- await this.httpApplication?.setupHttpServer(this.options)
231
+
232
+ if (this.environment.hasAdapterSetup() && this.adapter) {
233
+ await this.adapter.setupAdapter(this.options)
197
234
  }
235
+
198
236
  await this.initPlugins()
199
237
  await this.initModules()
200
- if (this.environment.hasHttpSetup()) {
201
- await this.httpApplication?.ready()
238
+
239
+ if (this.adapter) {
240
+ await this.adapter.ready()
202
241
  }
203
242
 
204
243
  this.isInitialized = true
@@ -207,23 +246,22 @@ export class NaviosApplication {
207
246
 
208
247
  private async initModules() {
209
248
  const modules = this.moduleLoader.getAllModules()
210
- await this.httpApplication?.onModulesInit(modules)
249
+ if (this.adapter) {
250
+ await this.adapter.onModulesInit(modules)
251
+ }
211
252
  }
212
253
 
213
254
  private async initPlugins() {
214
255
  if (this.plugins.length === 0) return
215
256
 
216
- let server: any = null
217
- try {
218
- server = this.httpApplication?.getServer() ?? null
219
- } catch {
220
- // ignore
257
+ if (!this.adapter) {
258
+ throw new Error('Cannot initialize plugins without an adapter')
221
259
  }
260
+
222
261
  const context: PluginContext = {
223
262
  modules: this.moduleLoader.getAllModules(),
224
- server,
263
+ adapter: this.adapter,
225
264
  container: this.container,
226
- globalPrefix: this.httpApplication?.getGlobalPrefix() ?? '',
227
265
  moduleLoader: this.moduleLoader,
228
266
  }
229
267
 
@@ -233,11 +271,79 @@ export class NaviosApplication {
233
271
  }
234
272
  }
235
273
 
274
+ /**
275
+ * Gets a service instance from the dependency injection container.
276
+ *
277
+ * This is a shorthand for `app.getContainer().get(token)`.
278
+ *
279
+ * @param token - The injection token or class to resolve
280
+ * @returns Promise resolving to the service instance
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * const userService = await app.get(UserService)
285
+ * const config = await app.get(ConfigToken)
286
+ * ```
287
+ */
288
+ get<T extends ClassType>(token: T): Promise<InstanceType<T>>
289
+ get<T extends ClassTypeWithArgument<R>, R>(
290
+ token: T,
291
+ args: R,
292
+ ): Promise<InstanceType<T>>
293
+ get<T, S extends InjectionTokenSchemaType>(
294
+ token: InjectionToken<T, S>,
295
+ args: z.input<S>,
296
+ ): Promise<T>
297
+ get<T, S extends InjectionTokenSchemaType, R extends boolean>(
298
+ token: InjectionToken<T, S, R>,
299
+ ): Promise<T>
300
+ get<T>(token: InjectionToken<T, undefined>): Promise<T>
301
+ get<T>(token: BoundInjectionToken<T, any>): Promise<T>
302
+ get<T>(token: FactoryInjectionToken<T, any>): Promise<T>
303
+ async get(
304
+ token:
305
+ | ClassType
306
+ | InjectionToken<any>
307
+ | BoundInjectionToken<any, any>
308
+ | FactoryInjectionToken<any, any>,
309
+ args?: unknown,
310
+ ): Promise<any> {
311
+ return this.container.get(token as any, args)
312
+ }
313
+
314
+ /**
315
+ * Configures the adapter with additional options before initialization.
316
+ *
317
+ * This method allows setting adapter-specific configuration options
318
+ * before the adapter is initialized. Must be called before `init()`.
319
+ *
320
+ * @param options - Adapter-specific configuration options
321
+ * @returns this for method chaining
322
+ * @throws Error if called after init() or if adapter doesn't support configure
323
+ *
324
+ * @example
325
+ * ```typescript
326
+ * // With Fastify adapter
327
+ * app.configure({ trustProxy: true, logger: true })
328
+ *
329
+ * // With Bun adapter
330
+ * app.configure({ development: true })
331
+ * ```
332
+ */
333
+ configure(options: Partial<Environment['options']>): this {
334
+ if (this.isInitialized) {
335
+ throw new Error('configure() must be called before init()')
336
+ }
337
+ assertAdapterSupports(this.adapter, 'configure')
338
+ this.adapter.configure(options)
339
+ return this
340
+ }
341
+
236
342
  /**
237
343
  * Enables CORS (Cross-Origin Resource Sharing) for the application.
238
344
  *
239
345
  * @param options - CORS configuration options (adapter-specific)
240
- * @throws Error if HTTP application is not set
346
+ * @throws Error if adapter doesn't support enableCors
241
347
  *
242
348
  * @example
243
349
  * ```typescript
@@ -248,18 +354,20 @@ export class NaviosApplication {
248
354
  * })
249
355
  * ```
250
356
  */
251
- enableCors(options: any) {
252
- if (!this.httpApplication) {
253
- throw new Error('HTTP application is not set')
254
- }
255
- this.httpApplication.enableCors(options)
357
+ enableCors(
358
+ options: Environment extends HttpAdapterEnvironment
359
+ ? Environment['corsOptions']
360
+ : never,
361
+ ): void {
362
+ assertAdapterSupports(this.adapter, 'enableCors')
363
+ this.adapter.enableCors(options)
256
364
  }
257
365
 
258
366
  /**
259
367
  * Enables multipart/form-data support for file uploads.
260
368
  *
261
369
  * @param options - Multipart configuration options (adapter-specific)
262
- * @throws Error if HTTP application is not set
370
+ * @throws Error if adapter doesn't support enableMultipart
263
371
  *
264
372
  * @example
265
373
  * ```typescript
@@ -270,18 +378,20 @@ export class NaviosApplication {
270
378
  * })
271
379
  * ```
272
380
  */
273
- enableMultipart(options: any) {
274
- if (!this.httpApplication) {
275
- throw new Error('HTTP application is not set')
276
- }
277
- this.httpApplication.enableMultipart(options)
381
+ enableMultipart(
382
+ options: Environment extends HttpAdapterEnvironment
383
+ ? Environment['multipartOptions']
384
+ : never,
385
+ ): void {
386
+ assertAdapterSupports(this.adapter, 'enableMultipart')
387
+ this.adapter.enableMultipart(options)
278
388
  }
279
389
 
280
390
  /**
281
391
  * Sets a global prefix for all routes.
282
392
  *
283
393
  * @param prefix - The prefix to prepend to all route URLs (e.g., '/api')
284
- * @throws Error if HTTP application is not set
394
+ * @throws Error if adapter doesn't support setGlobalPrefix
285
395
  *
286
396
  * @example
287
397
  * ```typescript
@@ -289,11 +399,9 @@ export class NaviosApplication {
289
399
  * // All routes will be prefixed with /api/v1
290
400
  * ```
291
401
  */
292
- setGlobalPrefix(prefix: string) {
293
- if (!this.httpApplication) {
294
- throw new Error('HTTP application is not set')
295
- }
296
- this.httpApplication.setGlobalPrefix(prefix)
402
+ setGlobalPrefix(prefix: string): void {
403
+ assertAdapterSupports(this.adapter, 'setGlobalPrefix')
404
+ this.adapter.setGlobalPrefix(prefix)
297
405
  }
298
406
 
299
407
  /**
@@ -304,7 +412,7 @@ export class NaviosApplication {
304
412
  * - Bun adapter: Returns Bun.Server
305
413
  *
306
414
  * @returns The HTTP server instance
307
- * @throws Error if HTTP application is not set
415
+ * @throws Error if adapter doesn't support getServer
308
416
  *
309
417
  * @example
310
418
  * ```typescript
@@ -312,40 +420,44 @@ export class NaviosApplication {
312
420
  * // Use adapter-specific server methods
313
421
  * ```
314
422
  */
315
- getServer() {
316
- if (!this.httpApplication) {
317
- throw new Error('HTTP application is not set')
318
- }
319
- return this.httpApplication.getServer()
423
+ getServer(): Environment extends HttpAdapterEnvironment
424
+ ? Environment['server']
425
+ : never {
426
+ assertAdapterSupports(this.adapter, 'getServer')
427
+ return this.adapter.getServer() as Environment extends HttpAdapterEnvironment
428
+ ? Environment['server']
429
+ : never
320
430
  }
321
431
 
322
432
  /**
323
433
  * Starts the HTTP server and begins listening for requests.
324
434
  *
325
435
  * @param options - Listen options (port, host, etc.)
326
- * @throws Error if HTTP application is not set
436
+ * @throws Error if adapter doesn't support listen
327
437
  *
328
438
  * @example
329
439
  * ```typescript
330
440
  * await app.listen({ port: 3000, host: '0.0.0.0' })
331
441
  * ```
332
442
  */
333
- async listen(options: AbstractHttpListenOptions) {
334
- if (!this.httpApplication) {
335
- throw new Error('HTTP application is not set')
336
- }
337
- await this.httpApplication.listen(options)
443
+ async listen(
444
+ options: Environment extends HttpAdapterEnvironment
445
+ ? Environment['listenOptions']
446
+ : never,
447
+ ): Promise<string> {
448
+ assertAdapterSupports(this.adapter, 'listen')
449
+ return this.adapter.listen(options) as Promise<string>
338
450
  }
339
451
 
340
452
  /**
341
453
  * Disposes of application resources.
342
454
  *
343
- * Cleans up the HTTP server and module loader.
455
+ * Cleans up the adapter and module loader.
344
456
  * This method is called automatically by `close()`.
345
457
  */
346
458
  async dispose() {
347
- if (this.httpApplication) {
348
- await this.httpApplication.dispose()
459
+ if (this.adapter) {
460
+ await this.adapter.dispose()
349
461
  }
350
462
  if (this.moduleLoader) {
351
463
  this.moduleLoader.dispose()
@@ -2,31 +2,41 @@ import type { AnyInjectableType, InjectionToken } from '@navios/di'
2
2
 
3
3
  import { Injectable } from '@navios/di'
4
4
 
5
+ import { AdapterToken } from './tokens/index.mjs'
6
+
5
7
  export interface NaviosEnvironmentOptions {
6
- // Future options can be added here
7
- httpTokens?: Map<InjectionToken<any, undefined>, AnyInjectableType>
8
+ tokens?: Map<InjectionToken<any, undefined>, AnyInjectableType>
8
9
  }
9
10
 
10
11
  @Injectable()
11
12
  export class NaviosEnvironment {
12
- private httpTokens = new Map<
13
- InjectionToken<any, undefined>,
14
- AnyInjectableType
15
- >()
13
+ private adapterConfigured = false
14
+ private tokens = new Map<InjectionToken<any, undefined>, AnyInjectableType>()
16
15
 
17
- setupHttpEnvironment(
16
+ setupEnvironment(
18
17
  tokens: Map<InjectionToken<any, undefined>, AnyInjectableType>,
19
18
  ) {
19
+ const hasAdapterToken = tokens.has(AdapterToken)
20
+ if (hasAdapterToken && this.adapterConfigured) {
21
+ throw new Error(
22
+ 'Adapter already configured. Only one adapter per application.',
23
+ )
24
+ }
25
+
20
26
  for (const [token, value] of tokens) {
21
- this.httpTokens.set(token, value)
27
+ this.tokens.set(token, value)
28
+ }
29
+
30
+ if (hasAdapterToken) {
31
+ this.adapterConfigured = true
22
32
  }
23
33
  }
24
34
 
25
- getHttpToken(token: InjectionToken<any, undefined>) {
26
- return this.httpTokens.get(token)
35
+ getToken(token: InjectionToken<any, undefined>) {
36
+ return this.tokens.get(token)
27
37
  }
28
38
 
29
- hasHttpSetup() {
30
- return this.httpTokens.size > 0
39
+ hasAdapterSetup() {
40
+ return this.adapterConfigured
31
41
  }
32
42
  }