@navios/core 0.1.13 → 0.1.15

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 (36) hide show
  1. package/dist/_tsup-dts-rollup.d.mts +133 -49
  2. package/dist/_tsup-dts-rollup.d.ts +133 -49
  3. package/dist/index.d.mts +8 -2
  4. package/dist/index.d.ts +8 -2
  5. package/dist/index.js +1184 -1090
  6. package/dist/index.mjs +1179 -1090
  7. package/package.json +1 -1
  8. package/src/adapters/endpoint-adapter.service.mts +75 -0
  9. package/src/adapters/handler-adapter.interface.mts +21 -0
  10. package/src/adapters/index.mts +4 -0
  11. package/src/adapters/multipart-adapter.service.mts +130 -0
  12. package/src/adapters/stream-adapter.service.mts +95 -0
  13. package/src/attribute.factory.mts +13 -13
  14. package/src/config/config.provider.mts +8 -2
  15. package/src/decorators/controller.decorator.mts +0 -2
  16. package/src/decorators/endpoint.decorator.mts +7 -3
  17. package/src/decorators/header.decorator.mts +1 -6
  18. package/src/decorators/http-code.decorator.mts +1 -6
  19. package/src/decorators/module.decorator.mts +13 -15
  20. package/src/decorators/multipart.decorator.mts +7 -3
  21. package/src/decorators/stream.decorator.mts +7 -3
  22. package/src/index.mts +1 -0
  23. package/src/logger/console-logger.service.mts +41 -3
  24. package/src/logger/logger.service.mts +0 -1
  25. package/src/metadata/controller.metadata.mts +3 -3
  26. package/src/metadata/{endpoint.metadata.mts → handler.metadata.mts} +17 -24
  27. package/src/metadata/index.mts +1 -1
  28. package/src/navios.application.mts +3 -4
  29. package/src/service-locator/__tests__/injection-token.spec.mts +10 -5
  30. package/src/service-locator/decorators/injectable.decorator.mts +53 -4
  31. package/src/service-locator/inject.mts +14 -0
  32. package/src/service-locator/interfaces/factory.interface.mts +9 -1
  33. package/src/service-locator/service-locator.mts +1 -0
  34. package/src/service-locator/sync-injector.mts +14 -0
  35. package/src/services/controller-adapter.service.mts +59 -240
  36. package/src/services/execution-context.mts +4 -3
@@ -5,7 +5,8 @@ import { inspect } from 'util'
5
5
  import type { LogLevel } from './log-levels.mjs'
6
6
  import type { LoggerService } from './logger-service.interface.mjs'
7
7
 
8
- import { Injectable } from '../service-locator/index.mjs'
8
+ import { getServiceLocator, Injectable } from '../service-locator/index.mjs'
9
+ import { Request } from '../tokens/index.mjs'
9
10
  import {
10
11
  clc,
11
12
  isFunction,
@@ -36,6 +37,10 @@ export interface ConsoleLoggerOptions {
36
37
  * Note: This option is not used when `json` is enabled.
37
38
  */
38
39
  prefix?: string
40
+ /**
41
+ * If enabled, will add a request ID to the log message.
42
+ */
43
+ requestId?: boolean
39
44
  /**
40
45
  * If enabled, will print the log message in JSON format.
41
46
  */
@@ -128,6 +133,10 @@ export class ConsoleLogger implements LoggerService {
128
133
  * The context of the logger (can be set manually or automatically inferred).
129
134
  */
130
135
  protected context?: string
136
+ /**
137
+ * Request ID (if enabled).
138
+ */
139
+ protected requestId: string | null = null
131
140
  /**
132
141
  * The original context of the logger (set in the constructor).
133
142
  */
@@ -168,6 +177,24 @@ export class ConsoleLogger implements LoggerService {
168
177
  this.context = context
169
178
  this.originalContext = context
170
179
  }
180
+ if (opts?.requestId) {
181
+ const locator = getServiceLocator()
182
+ locator
183
+ .getEventBus()
184
+ .on(locator.getInstanceIdentifier(Request, undefined), 'create', () => {
185
+ const request = locator.getSyncInstance(Request, undefined)
186
+ this.requestId = request?.id ?? null
187
+ })
188
+ locator
189
+ .getEventBus()
190
+ .on(
191
+ locator.getInstanceIdentifier(Request, undefined),
192
+ 'destroy',
193
+ () => {
194
+ this.requestId = null
195
+ },
196
+ )
197
+ }
171
198
  }
172
199
 
173
200
  /**
@@ -358,6 +385,7 @@ export class ConsoleLogger implements LoggerService {
358
385
  message: unknown
359
386
  context?: string
360
387
  stack?: unknown
388
+ requestId?: string
361
389
  }
362
390
 
363
391
  const logObject: JsonLogObject = {
@@ -374,6 +402,9 @@ export class ConsoleLogger implements LoggerService {
374
402
  if (options.errorStack) {
375
403
  logObject.stack = options.errorStack
376
404
  }
405
+ if (this.options.requestId && this.requestId) {
406
+ logObject.requestId = this.requestId
407
+ }
377
408
 
378
409
  const formattedMessage =
379
410
  !this.options.colors && this.inspectOptions.compact === true
@@ -383,7 +414,7 @@ export class ConsoleLogger implements LoggerService {
383
414
  }
384
415
 
385
416
  protected formatPid(pid: number) {
386
- return `[${this.options.prefix}] ${pid} - `
417
+ return `[${this.options.prefix}] ${pid} - `
387
418
  }
388
419
 
389
420
  protected formatContext(context: string): string {
@@ -406,7 +437,14 @@ export class ConsoleLogger implements LoggerService {
406
437
  const output = this.stringifyMessage(message, logLevel)
407
438
  pidMessage = this.colorize(pidMessage, logLevel)
408
439
  formattedLogLevel = this.colorize(formattedLogLevel, logLevel)
409
- return `${pidMessage}${this.getTimestamp()} ${formattedLogLevel} ${contextMessage}${output}${timestampDiff}\n`
440
+ return `${pidMessage}${this.getRequestId()}${this.getTimestamp()} ${formattedLogLevel} ${contextMessage}${output}${timestampDiff}\n`
441
+ }
442
+
443
+ protected getRequestId() {
444
+ if (this.options.requestId && this.requestId) {
445
+ return `(${this.colorize(this.requestId, 'log')}) `
446
+ }
447
+ return ''
410
448
  }
411
449
 
412
450
  protected stringifyMessage(message: unknown, logLevel: LogLevel): string {
@@ -16,7 +16,6 @@ const dateTimeFormatter = new Intl.DateTimeFormat(undefined, {
16
16
  month: '2-digit',
17
17
  })
18
18
 
19
- // @ts-expect-error We don't need to support this in the current version
20
19
  @Injectable()
21
20
  export class LoggerInstance implements LoggerService {
22
21
  protected static staticInstanceRef?: LoggerService = DEFAULT_LOGGER
@@ -4,14 +4,14 @@ import type {
4
4
  ClassTypeWithInstance,
5
5
  InjectionToken,
6
6
  } from '../service-locator/index.mjs'
7
- import type { EndpointMetadata } from './endpoint.metadata.mjs'
7
+ import type { HandlerMetadata } from './handler.metadata.mjs'
8
8
 
9
- import { getAllEndpointMetadata } from './endpoint.metadata.mjs'
9
+ import { getAllEndpointMetadata } from './handler.metadata.mjs'
10
10
 
11
11
  export const ControllerMetadataKey = Symbol('ControllerMetadataKey')
12
12
 
13
13
  export interface ControllerMetadata {
14
- endpoints: Set<EndpointMetadata>
14
+ endpoints: Set<HandlerMetadata>
15
15
  guards: Set<
16
16
  ClassTypeWithInstance<CanActivate> | InjectionToken<CanActivate, undefined>
17
17
  >
@@ -1,10 +1,7 @@
1
- import type {
2
- BaseEndpointConfig,
3
- BaseStreamConfig,
4
- HttpMethod,
5
- } from '@navios/common'
1
+ import type { HttpMethod } from '@navios/common'
6
2
  import type { HttpHeader } from 'fastify/types/utils.js'
7
3
 
4
+ import type { HandlerAdapterInterface } from '../adapters/index.mjs'
8
5
  import type { CanActivate } from '../interfaces/index.mjs'
9
6
  import type {
10
7
  ClassTypeWithInstance,
@@ -13,22 +10,17 @@ import type {
13
10
 
14
11
  export const EndpointMetadataKey = Symbol('EndpointMetadataKey')
15
12
 
16
- export enum EndpointType {
17
- Unknown = 'unknown',
18
- Endpoint = 'endpoint',
19
- Stream = 'stream',
20
- Multipart = 'multipart',
21
- Handler = 'handler',
22
- }
23
-
24
- export interface EndpointMetadata {
13
+ export interface HandlerMetadata<Config = null> {
25
14
  classMethod: string
26
15
  url: string
27
16
  successStatusCode: number
28
- type: EndpointType
17
+ adapterToken:
18
+ | InjectionToken<HandlerAdapterInterface, undefined>
19
+ | ClassTypeWithInstance<HandlerAdapterInterface>
20
+ | null
29
21
  headers: Partial<Record<HttpHeader, number | string | string[] | undefined>>
30
22
  httpMethod: HttpMethod
31
- config: BaseEndpointConfig | BaseStreamConfig | null
23
+ config: Config
32
24
  guards: Set<
33
25
  ClassTypeWithInstance<CanActivate> | InjectionToken<CanActivate, undefined>
34
26
  >
@@ -37,25 +29,25 @@ export interface EndpointMetadata {
37
29
 
38
30
  export function getAllEndpointMetadata(
39
31
  context: ClassMethodDecoratorContext | ClassDecoratorContext,
40
- ): Set<EndpointMetadata> {
32
+ ): Set<HandlerMetadata<any>> {
41
33
  if (context.metadata) {
42
34
  const metadata = context.metadata[EndpointMetadataKey] as
43
- | Set<EndpointMetadata>
35
+ | Set<HandlerMetadata>
44
36
  | undefined
45
37
  if (metadata) {
46
38
  return metadata
47
39
  } else {
48
- context.metadata[EndpointMetadataKey] = new Set<EndpointMetadata>()
49
- return context.metadata[EndpointMetadataKey] as Set<EndpointMetadata>
40
+ context.metadata[EndpointMetadataKey] = new Set<HandlerMetadata<any>>()
41
+ return context.metadata[EndpointMetadataKey] as Set<HandlerMetadata<any>>
50
42
  }
51
43
  }
52
44
  throw new Error('[Navios] Wrong environment.')
53
45
  }
54
46
 
55
- export function getEndpointMetadata(
47
+ export function getEndpointMetadata<Config = any>(
56
48
  target: Function,
57
49
  context: ClassMethodDecoratorContext,
58
- ): EndpointMetadata {
50
+ ): HandlerMetadata<Config> {
59
51
  if (context.metadata) {
60
52
  const metadata = getAllEndpointMetadata(context)
61
53
  if (metadata) {
@@ -65,13 +57,14 @@ export function getEndpointMetadata(
65
57
  if (endpointMetadata) {
66
58
  return endpointMetadata
67
59
  } else {
68
- const newMetadata: EndpointMetadata = {
60
+ const newMetadata: HandlerMetadata<Config> = {
69
61
  classMethod: target.name,
70
62
  url: '',
71
63
  successStatusCode: 200,
64
+ adapterToken: null,
72
65
  headers: {},
73
- type: EndpointType.Unknown,
74
66
  httpMethod: 'GET',
67
+ // @ts-expect-error We are using a generic type here
75
68
  config: null,
76
69
  guards: new Set<
77
70
  | ClassTypeWithInstance<CanActivate>
@@ -1,4 +1,4 @@
1
1
  export * from './controller.metadata.mjs'
2
- export * from './endpoint.metadata.mjs'
2
+ export * from './handler.metadata.mjs'
3
3
  export * from './injectable.metadata.mjs'
4
4
  export * from './module.metadata.mjs'
@@ -149,7 +149,7 @@ export class NaviosApplication {
149
149
  message: 'Not Found',
150
150
  error: 'NotFound',
151
151
  }
152
- this.logger.error(`Route not found: ${req.url}`)
152
+ this.logger.error(`Route not found: [${req.method}] ${req.url}`)
153
153
  return reply.status(404).send(response)
154
154
  })
155
155
  }
@@ -178,15 +178,14 @@ export class NaviosApplication {
178
178
  }
179
179
  promises.push(
180
180
  this.server!.register(
181
- (instance, opts, done) => {
181
+ async (instance, opts) => {
182
182
  for (const controller of moduleMetadata.controllers) {
183
- this.controllerAdapter.setupController(
183
+ await this.controllerAdapter.setupController(
184
184
  controller,
185
185
  instance,
186
186
  moduleMetadata,
187
187
  )
188
188
  }
189
- done()
190
189
  },
191
190
  {
192
191
  prefix: this.globalPrefix ?? '',
@@ -1,6 +1,11 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
  import { z } from 'zod'
3
3
 
4
+ import type {
5
+ Factory,
6
+ FactoryWithArgs,
7
+ } from '../interfaces/factory.interface.mjs'
8
+
4
9
  import { Injectable, InjectableType } from '../decorators/index.mjs'
5
10
  import { inject } from '../inject.mjs'
6
11
  import { InjectionToken } from '../injection-token.mjs'
@@ -39,13 +44,13 @@ describe('InjectToken', () => {
39
44
  })
40
45
 
41
46
  it('should work with factory', async () => {
42
- const token = InjectionToken.create('Test')
47
+ const token = InjectionToken.create<string>('Test')
43
48
  @Injectable({
44
49
  token,
45
50
  type: InjectableType.Factory,
46
51
  })
47
- class Test {
48
- create() {
52
+ class Test implements Factory<string> {
53
+ async create() {
49
54
  return 'foo'
50
55
  }
51
56
  }
@@ -64,8 +69,8 @@ describe('InjectToken', () => {
64
69
  token,
65
70
  type: InjectableType.Factory,
66
71
  })
67
- class Test {
68
- create(ctx: any, args: { test: string }) {
72
+ class Test implements FactoryWithArgs<string, typeof schema> {
73
+ async create(ctx: any, args: { test: string }) {
69
74
  return args.test
70
75
  }
71
76
  }
@@ -1,6 +1,12 @@
1
+ import type { AnyZodObject } from 'zod'
2
+
1
3
  import { NaviosException } from '@navios/common'
2
4
 
3
- import type { ClassType } from '../injection-token.mjs'
5
+ import type { ClassType, ClassTypeWithInstance } from '../injection-token.mjs'
6
+ import type {
7
+ Factory,
8
+ FactoryWithArgs,
9
+ } from '../interfaces/factory.interface.mjs'
4
10
 
5
11
  import { InjectableScope } from '../enums/index.mjs'
6
12
  import { InjectionToken } from '../injection-token.mjs'
@@ -18,14 +24,55 @@ export interface InjectableOptions {
18
24
  token?: InjectionToken<any, any>
19
25
  }
20
26
 
21
- export const InjectableTokenMeta = Symbol('InjectableTokenMeta')
27
+ export const InjectableTokenMeta = Symbol.for('InjectableTokenMeta')
22
28
 
29
+ export function Injectable(): <T extends ClassType>(
30
+ target: T,
31
+ context: ClassDecoratorContext,
32
+ ) => T & { [InjectableTokenMeta]: InjectionToken<InstanceType<T>, undefined> }
33
+ export function Injectable<T extends ClassType>(options: {
34
+ scope?: InjectableScope
35
+ token: InjectionToken<T, undefined>
36
+ }): (
37
+ target: T,
38
+ context: ClassDecoratorContext,
39
+ ) => T & {
40
+ [InjectableTokenMeta]: InjectionToken<InstanceType<T>, undefined>
41
+ }
42
+ export function Injectable<R>(options: {
43
+ scope?: InjectableScope
44
+ type: InjectableType.Factory
45
+ }): <T extends ClassTypeWithInstance<Factory<R>>>(
46
+ target: T,
47
+ context: ClassDecoratorContext,
48
+ ) => T & { [InjectableTokenMeta]: InjectionToken<R, undefined> }
49
+ export function Injectable<R, S extends AnyZodObject>(options: {
50
+ scope?: InjectableScope
51
+ type: InjectableType.Factory
52
+ token: InjectionToken<R, S>
53
+ }): <T extends ClassTypeWithInstance<FactoryWithArgs<R, S>>>(
54
+ target: T,
55
+ context: ClassDecoratorContext,
56
+ ) => T & { [InjectableTokenMeta]: InjectionToken<R, S> }
57
+ export function Injectable<R>(options: {
58
+ scope?: InjectableScope
59
+ type: InjectableType.Factory
60
+ token: InjectionToken<R, undefined>
61
+ }): <T extends ClassTypeWithInstance<Factory<R>>>(
62
+ target: T,
63
+ context: ClassDecoratorContext,
64
+ ) => T & { [InjectableTokenMeta]: InjectionToken<R, undefined> }
23
65
  export function Injectable({
24
66
  scope = InjectableScope.Singleton,
25
67
  type = InjectableType.Class,
26
68
  token,
27
69
  }: InjectableOptions = {}) {
28
- return (target: ClassType, context: ClassDecoratorContext) => {
70
+ return <T extends ClassType>(
71
+ target: T,
72
+ context: ClassDecoratorContext,
73
+ ): T & {
74
+ [InjectableTokenMeta]: InjectionToken<any, any>
75
+ } => {
29
76
  if (context.kind !== 'class') {
30
77
  throw new Error(
31
78
  '[ServiceLocator] @Injectable decorator can only be used on classes.',
@@ -59,6 +106,8 @@ export function Injectable({
59
106
  // @ts-expect-error
60
107
  target[InjectableTokenMeta] = injectableToken
61
108
 
62
- return target
109
+ return target as T & {
110
+ [InjectableTokenMeta]: InjectionToken<any, any>
111
+ }
63
112
  }
64
113
  }
@@ -7,6 +7,20 @@ import { InjectionToken } from './injection-token.mjs'
7
7
  import { getServiceLocator } from './injector.mjs'
8
8
 
9
9
  export function inject<T extends ClassType>(token: T): Promise<InstanceType<T>>
10
+ // Not supported by TypeScript yet
11
+ // export function inject<
12
+ // R,
13
+ // T extends ClassType & {
14
+ // [InjectableTokenMeta]: InjectionToken<R, undefined>
15
+ // },
16
+ // >(token: T): Promise<R>
17
+ // export function inject<
18
+ // R,
19
+ // S extends AnyZodObject,
20
+ // T extends ClassType & {
21
+ // [InjectableTokenMeta]: InjectionToken<R, S>
22
+ // },
23
+ // >(token: T, args: z.input<S>): Promise<R>
10
24
  export function inject<T, S extends AnyZodObject>(
11
25
  token: InjectionToken<T, S>,
12
26
  args: z.input<S>,
@@ -1,3 +1,11 @@
1
+ import type { AnyZodObject } from 'zod'
2
+
3
+ import { z } from 'zod'
4
+
1
5
  export interface Factory<T> {
2
- create(ctx: any): Promise<T>
6
+ create(ctx?: any): Promise<T> | T
7
+ }
8
+
9
+ export interface FactoryWithArgs<T, A extends AnyZodObject> {
10
+ create(ctx: any, args: z.output<A>): Promise<T> | T
3
11
  }
@@ -65,6 +65,7 @@ export class ServiceLocator {
65
65
  destroyPromise: null,
66
66
  creationPromise: null,
67
67
  })
68
+ this.eventBus.emit(instanceName, 'create')
68
69
  }
69
70
 
70
71
  public removeInstance<Instance>(token: InjectionToken<Instance, undefined>) {
@@ -9,6 +9,20 @@ import { getServiceLocator } from './injector.mjs'
9
9
  let promiseCollector: null | ((promise: Promise<any>) => void) = null
10
10
 
11
11
  export function syncInject<T extends ClassType>(token: T): InstanceType<T>
12
+ // Not supported by TypeScript yet
13
+ // export function syncInject<
14
+ // R,
15
+ // T extends ClassType & {
16
+ // [InjectableTokenMeta]: InjectionToken<R, undefined>
17
+ // },
18
+ // >(token: T): R
19
+ // export function syncInject<
20
+ // R,
21
+ // S extends AnyZodObject,
22
+ // T extends ClassType & {
23
+ // [InjectableTokenMeta]: InjectionToken<R, S>
24
+ // },
25
+ // >(token: T, args: z.input<S>): R
12
26
  export function syncInject<T, S extends AnyZodObject>(
13
27
  token: InjectionToken<T, S>,
14
28
  args: z.input<S>,