@navios/core 0.3.0 → 0.5.0

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 (96) hide show
  1. package/README.md +96 -3
  2. package/docs/README.md +310 -3
  3. package/docs/adapters.md +308 -0
  4. package/docs/application-setup.md +524 -0
  5. package/docs/attributes.md +689 -0
  6. package/docs/controllers.md +373 -0
  7. package/docs/endpoints.md +444 -0
  8. package/docs/exceptions.md +316 -0
  9. package/docs/guards.md +550 -0
  10. package/docs/modules.md +251 -0
  11. package/docs/quick-start.md +295 -0
  12. package/docs/services.md +428 -0
  13. package/docs/testing.md +704 -0
  14. package/lib/_tsup-dts-rollup.d.mts +313 -280
  15. package/lib/_tsup-dts-rollup.d.ts +313 -280
  16. package/lib/index.d.mts +47 -26
  17. package/lib/index.d.ts +47 -26
  18. package/lib/index.js +633 -1068
  19. package/lib/index.js.map +1 -1
  20. package/lib/index.mjs +632 -1061
  21. package/lib/index.mjs.map +1 -1
  22. package/package.json +11 -12
  23. package/project.json +17 -4
  24. package/src/__tests__/config.service.spec.mts +11 -9
  25. package/src/__tests__/controller.spec.mts +1 -2
  26. package/src/attribute.factory.mts +1 -1
  27. package/src/config/config.provider.mts +2 -2
  28. package/src/config/config.service.mts +4 -4
  29. package/src/decorators/controller.decorator.mts +1 -1
  30. package/src/decorators/endpoint.decorator.mts +9 -10
  31. package/src/decorators/header.decorator.mts +1 -1
  32. package/src/decorators/multipart.decorator.mts +5 -5
  33. package/src/decorators/stream.decorator.mts +5 -6
  34. package/src/factories/endpoint-adapter.factory.mts +21 -0
  35. package/src/factories/http-adapter.factory.mts +20 -0
  36. package/src/factories/index.mts +6 -0
  37. package/src/factories/multipart-adapter.factory.mts +21 -0
  38. package/src/factories/reply.factory.mts +21 -0
  39. package/src/factories/request.factory.mts +21 -0
  40. package/src/factories/stream-adapter.factory.mts +20 -0
  41. package/src/index.mts +1 -1
  42. package/src/interfaces/abstract-execution-context.inteface.mts +13 -0
  43. package/src/interfaces/abstract-http-adapter.interface.mts +20 -0
  44. package/src/interfaces/abstract-http-cors-options.interface.mts +59 -0
  45. package/src/interfaces/abstract-http-handler-adapter.interface.mts +13 -0
  46. package/src/interfaces/abstract-http-listen-options.interface.mts +4 -0
  47. package/src/interfaces/can-activate.mts +4 -2
  48. package/src/interfaces/http-header.mts +18 -0
  49. package/src/interfaces/index.mts +6 -0
  50. package/src/logger/console-logger.service.mts +28 -44
  51. package/src/logger/index.mts +1 -2
  52. package/src/logger/logger.service.mts +9 -128
  53. package/src/logger/logger.tokens.mts +21 -0
  54. package/src/metadata/handler.metadata.mts +7 -5
  55. package/src/navios.application.mts +65 -172
  56. package/src/navios.environment.mts +30 -0
  57. package/src/navios.factory.mts +53 -12
  58. package/src/services/guard-runner.service.mts +19 -9
  59. package/src/services/index.mts +0 -2
  60. package/src/services/module-loader.service.mts +4 -3
  61. package/src/tokens/endpoint-adapter.token.mts +8 -0
  62. package/src/tokens/execution-context.token.mts +2 -2
  63. package/src/tokens/http-adapter.token.mts +8 -0
  64. package/src/tokens/index.mts +4 -1
  65. package/src/tokens/multipart-adapter.token.mts +8 -0
  66. package/src/tokens/reply.token.mts +1 -5
  67. package/src/tokens/request.token.mts +1 -7
  68. package/src/tokens/stream-adapter.token.mts +8 -0
  69. package/tsconfig.json +6 -1
  70. package/tsconfig.lib.json +8 -0
  71. package/tsconfig.spec.json +12 -0
  72. package/tsup.config.mts +1 -0
  73. package/docs/recipes/prisma.md +0 -60
  74. package/examples/simple-test/api/index.mts +0 -64
  75. package/examples/simple-test/config/config.service.mts +0 -14
  76. package/examples/simple-test/config/configuration.mts +0 -7
  77. package/examples/simple-test/index.mts +0 -16
  78. package/examples/simple-test/src/acl/acl-modern.guard.mts +0 -15
  79. package/examples/simple-test/src/acl/acl.guard.mts +0 -14
  80. package/examples/simple-test/src/acl/app.guard.mts +0 -27
  81. package/examples/simple-test/src/acl/one-more.guard.mts +0 -15
  82. package/examples/simple-test/src/acl/public.attribute.mts +0 -21
  83. package/examples/simple-test/src/app.module.mts +0 -9
  84. package/examples/simple-test/src/user/user.controller.mts +0 -72
  85. package/examples/simple-test/src/user/user.module.mts +0 -14
  86. package/examples/simple-test/src/user/user.service.mts +0 -14
  87. package/src/adapters/endpoint-adapter.service.mts +0 -72
  88. package/src/adapters/handler-adapter.interface.mts +0 -21
  89. package/src/adapters/index.mts +0 -4
  90. package/src/adapters/multipart-adapter.service.mts +0 -131
  91. package/src/adapters/stream-adapter.service.mts +0 -91
  92. package/src/logger/logger.factory.mts +0 -36
  93. package/src/logger/pino-wrapper.mts +0 -64
  94. package/src/services/controller-adapter.service.mts +0 -124
  95. package/src/services/execution-context.mts +0 -54
  96. package/src/tokens/application.token.mts +0 -9
@@ -1,72 +0,0 @@
1
- import type {
2
- EndpointParams,
3
- EndpointResult,
4
- MultipartParams,
5
- } from '../../../../src/index.mjs'
6
-
7
- import {
8
- Controller,
9
- Endpoint,
10
- Logger,
11
- Multipart,
12
- syncInject,
13
- UseGuards,
14
- } from '../../../../src/index.mjs'
15
- import {
16
- discriminatorEndpoint,
17
- multipartEndpoint,
18
- patchUserEndpoint,
19
- userEndpoint,
20
- } from '../../api/index.mjs'
21
- import { AclGuard } from '../acl/acl.guard.mjs'
22
- import { OneMoreGuard } from '../acl/one-more.guard.mjs'
23
- import { Public } from '../acl/public.attribute.mjs'
24
- import { UserService } from './user.service.mjs'
25
-
26
- @UseGuards(AclGuard)
27
- @Controller()
28
- export class UserController {
29
- userService = syncInject(UserService)
30
- logger = syncInject(Logger, {
31
- context: UserController.name,
32
- })
33
-
34
- @Public()
35
- @UseGuards(OneMoreGuard)
36
- @Endpoint(userEndpoint)
37
- async me(params: EndpointParams<typeof userEndpoint>) {
38
- this.logger.log(params)
39
- return this.userService.getUser()
40
- }
41
-
42
- @Endpoint(patchUserEndpoint)
43
- async patchMe(params: EndpointParams<typeof patchUserEndpoint>) {
44
- this.logger.log(params)
45
- return {
46
- ...this.userService.getUser(),
47
- ...params.data,
48
- }
49
- }
50
-
51
- @Endpoint(discriminatorEndpoint)
52
- async discriminator(
53
- params: EndpointParams<typeof discriminatorEndpoint>,
54
- ): EndpointResult<typeof discriminatorEndpoint> {
55
- this.logger.log(params)
56
- return {
57
- success: true,
58
- data: {
59
- id: '123',
60
- name: 'John Doe',
61
- email: 'test@example.com',
62
- },
63
- }
64
- }
65
-
66
- @Multipart(multipartEndpoint)
67
- async multipart(params: MultipartParams<typeof multipartEndpoint>) {
68
- this.logger.log(params)
69
- // params.data.
70
- return {}
71
- }
72
- }
@@ -1,14 +0,0 @@
1
- import { Logger, Module, syncInject } from '../../../../src/index.mjs'
2
- import { AclModernGuard } from '../acl/acl-modern.guard.mjs'
3
- import { UserController } from './user.controller.mjs'
4
-
5
- @Module({
6
- controllers: [UserController],
7
- guards: [AclModernGuard],
8
- })
9
- export class UserModule {
10
- logger = syncInject(Logger)
11
- onModuleInit() {
12
- this.logger.debug('Inside UserModule.onModuleInit')
13
- }
14
- }
@@ -1,14 +0,0 @@
1
- import { randomUUID } from 'node:crypto'
2
-
3
- import { Injectable } from '../../../../src/index.mjs'
4
-
5
- @Injectable()
6
- export class UserService {
7
- getUser() {
8
- return {
9
- id: randomUUID() as string,
10
- name: 'John Doe',
11
- email: 'test@example.com',
12
- }
13
- }
14
- }
@@ -1,72 +0,0 @@
1
- import type { BaseEndpointConfig } from '@navios/builder'
2
- import type { ClassType } from '@navios/di'
3
- import type { FastifyReply, FastifyRequest } from 'fastify'
4
-
5
- import { inject, Injectable, InjectionToken } from '@navios/di'
6
-
7
- import type { HandlerMetadata } from '../metadata/index.mjs'
8
- import type { ExecutionContext } from '../services/index.mjs'
9
-
10
- import { StreamAdapterService } from './stream-adapter.service.mjs'
11
-
12
- export const EndpointAdapterToken =
13
- InjectionToken.create<EndpointAdapterService>(
14
- Symbol.for('EndpointAdapterService'),
15
- )
16
-
17
- @Injectable({
18
- token: EndpointAdapterToken,
19
- })
20
- export class EndpointAdapterService extends StreamAdapterService {
21
- override hasSchema(
22
- handlerMetadata: HandlerMetadata<BaseEndpointConfig>,
23
- ): boolean {
24
- const config = handlerMetadata.config
25
- return super.hasSchema(handlerMetadata) || !!config.responseSchema
26
- }
27
-
28
- override provideSchema(
29
- handlerMetadata: HandlerMetadata<BaseEndpointConfig>,
30
- ): Record<string, any> {
31
- const config = handlerMetadata.config
32
- const schema = super.provideSchema(handlerMetadata)
33
- if (config.responseSchema) {
34
- schema.response = {
35
- 200: config.responseSchema,
36
- }
37
- }
38
-
39
- return schema
40
- }
41
-
42
- override provideHandler(
43
- controller: ClassType,
44
- executionContext: ExecutionContext,
45
- handlerMetadata: HandlerMetadata<BaseEndpointConfig>,
46
- ): (request: FastifyRequest, reply: FastifyReply) => Promise<any> {
47
- const getters = this.prepareArguments(handlerMetadata)
48
- const formatArguments = async (request: FastifyRequest) => {
49
- const argument: Record<string, any> = {}
50
- const promises: Promise<void>[] = []
51
- for (const getter of getters) {
52
- const res = getter(argument, request)
53
- if (res instanceof Promise) {
54
- promises.push(res)
55
- }
56
- }
57
- await Promise.all(promises)
58
- return argument
59
- }
60
-
61
- return async function (request, reply) {
62
- const controllerInstance = await inject(controller)
63
- const argument = await formatArguments(request)
64
- const result =
65
- await controllerInstance[handlerMetadata.classMethod](argument)
66
- reply
67
- .status(handlerMetadata.successStatusCode)
68
- .headers(handlerMetadata.headers)
69
- .send(result)
70
- }
71
- }
72
- }
@@ -1,21 +0,0 @@
1
- import type { ClassType } from '@navios/di'
2
- import type { FastifyReply, FastifyRequest } from 'fastify'
3
-
4
- import type { HandlerMetadata } from '../metadata/index.mjs'
5
- import type { ExecutionContext } from '../services/index.mjs'
6
-
7
- export interface HandlerAdapterInterface {
8
- provideSchema?: (handlerMetadata: HandlerMetadata<any>) => Record<string, any>
9
- hasSchema?: (handlerMetadata: HandlerMetadata<any>) => boolean
10
- prepareArguments?: (
11
- handlerMetadata: HandlerMetadata<any>,
12
- ) => ((
13
- target: Record<string, any>,
14
- request: FastifyRequest,
15
- ) => Promise<void> | void)[]
16
- provideHandler: (
17
- controller: ClassType,
18
- executionContext: ExecutionContext,
19
- handlerMetadata: HandlerMetadata<any>,
20
- ) => (request: FastifyRequest, reply: FastifyReply) => Promise<any>
21
- }
@@ -1,4 +0,0 @@
1
- export * from './endpoint-adapter.service.mjs'
2
- export * from './handler-adapter.interface.mjs'
3
- export * from './multipart-adapter.service.mjs'
4
- export * from './stream-adapter.service.mjs'
@@ -1,131 +0,0 @@
1
- import type { MultipartFile, MultipartValue } from '@fastify/multipart'
2
- import type { BaseEndpointConfig } from '@navios/builder'
3
- import type { FastifyRequest } from 'fastify'
4
- import type { AnyZodObject, ZodRawShape } from 'zod'
5
-
6
- import { Injectable, InjectionToken } from '@navios/di'
7
-
8
- import { ZodArray, ZodObject, ZodOptional } from 'zod'
9
-
10
- import type { HandlerMetadata } from '../metadata/index.mjs'
11
-
12
- import { EndpointAdapterService } from './endpoint-adapter.service.mjs'
13
-
14
- export const MultipartAdapterToken =
15
- InjectionToken.create<MultipartAdapterService>(
16
- Symbol.for('MultipartAdapterService'),
17
- )
18
-
19
- @Injectable({
20
- token: MultipartAdapterToken,
21
- })
22
- export class MultipartAdapterService extends EndpointAdapterService {
23
- prepareArguments(
24
- handlerMetadata: HandlerMetadata<BaseEndpointConfig>,
25
- ): ((target: Record<string, any>, request: FastifyRequest) => void)[] {
26
- const config = handlerMetadata.config
27
- const getters: ((
28
- target: Record<string, any>,
29
- request: FastifyRequest,
30
- ) => void | Promise<void>)[] = []
31
- if (config.querySchema) {
32
- getters.push((target, request) => {
33
- target.params = request.query
34
- })
35
- }
36
- if (config.url.includes('$')) {
37
- getters.push((target, request) => {
38
- target.urlParams = request.params
39
- })
40
- }
41
- const requestSchema = config.requestSchema as unknown as AnyZodObject
42
- const shape = requestSchema._def.shape()
43
- const structure = this.analyzeSchema(shape)
44
- getters.push(async (target, request) => {
45
- const req: Record<string, any> = {}
46
- for await (const part of request.parts()) {
47
- await this.populateRequest(structure, part, req)
48
- }
49
- target.data = requestSchema.parse(req)
50
- })
51
-
52
- return getters
53
- }
54
-
55
- private async populateRequest(
56
- structure: {
57
- [p: string]: { isArray: boolean; isOptional: boolean; isObject: boolean }
58
- },
59
- part: MultipartFile | MultipartValue<unknown>,
60
- req: Record<string, any>,
61
- ) {
62
- const { isArray, isObject } = structure[part.fieldname] ?? {}
63
- if (isArray && !req[part.fieldname]) {
64
- req[part.fieldname] = []
65
- }
66
- let value
67
- if (part.type === 'file') {
68
- value = new File([await part.toBuffer()], part.filename, {
69
- type: part.mimetype,
70
- })
71
- } else {
72
- value = part.value
73
- if (isObject && typeof value === 'string') {
74
- value = JSON.parse(value)
75
- }
76
- }
77
-
78
- if (isArray) {
79
- req[part.fieldname].push(value)
80
- } else {
81
- req[part.fieldname] = value
82
- }
83
- }
84
-
85
- private analyzeSchema(shape: ZodRawShape) {
86
- return Object.keys(shape).reduce(
87
- (target, key) => {
88
- let schema = shape[key]
89
- const isOptional = schema instanceof ZodOptional
90
- if (isOptional) {
91
- schema = (schema as ZodOptional<any>).unwrap()
92
- }
93
- const isArray = schema instanceof ZodArray
94
- if (isArray) {
95
- schema = (schema as ZodArray<any>).element
96
- }
97
- const isObject = schema instanceof ZodObject
98
- return {
99
- ...target,
100
- [key]: {
101
- isArray,
102
- isOptional,
103
- isObject,
104
- },
105
- }
106
- },
107
- {} as Record<
108
- string,
109
- { isArray: boolean; isOptional: boolean; isObject: boolean }
110
- >,
111
- )
112
- }
113
-
114
- override provideSchema(
115
- handlerMetadata: HandlerMetadata<BaseEndpointConfig>,
116
- ): Record<string, any> {
117
- const schema: Record<string, any> = {}
118
- const { querySchema, responseSchema } = handlerMetadata.config
119
-
120
- if (querySchema) {
121
- schema.querystring = querySchema
122
- }
123
- if (responseSchema) {
124
- schema.response = {
125
- 200: responseSchema,
126
- }
127
- }
128
-
129
- return schema
130
- }
131
- }
@@ -1,91 +0,0 @@
1
- import type { BaseStreamConfig } from '@navios/builder'
2
- import type { ClassType } from '@navios/di'
3
- import type { FastifyReply, FastifyRequest } from 'fastify'
4
-
5
- import { inject, Injectable, InjectionToken } from '@navios/di'
6
-
7
- import type { HandlerMetadata } from '../metadata/index.mjs'
8
- import type { ExecutionContext } from '../services/index.mjs'
9
- import type { HandlerAdapterInterface } from './handler-adapter.interface.mjs'
10
-
11
- export const StreamAdapterToken = InjectionToken.create<StreamAdapterService>(
12
- Symbol.for('StreamAdapterService'),
13
- )
14
-
15
- @Injectable({
16
- token: StreamAdapterToken,
17
- })
18
- export class StreamAdapterService implements HandlerAdapterInterface {
19
- hasSchema(handlerMetadata: HandlerMetadata<BaseStreamConfig>): boolean {
20
- const config = handlerMetadata.config
21
- return !!config.requestSchema || !!config.querySchema
22
- }
23
-
24
- prepareArguments(handlerMetadata: HandlerMetadata<BaseStreamConfig>) {
25
- const config = handlerMetadata.config
26
- const getters: ((
27
- target: Record<string, any>,
28
- request: FastifyRequest,
29
- ) => void | Promise<void>)[] = []
30
- if (config.querySchema) {
31
- getters.push((target, request) => {
32
- target.params = request.query
33
- })
34
- }
35
- if (config.requestSchema) {
36
- getters.push((target, request) => {
37
- target.data = request.body
38
- })
39
- }
40
- if (config.url.includes('$')) {
41
- getters.push((target, request) => {
42
- target.urlParams = request.params
43
- })
44
- }
45
-
46
- return getters
47
- }
48
-
49
- provideHandler(
50
- controller: ClassType,
51
- executionContext: ExecutionContext,
52
- handlerMetadata: HandlerMetadata<BaseStreamConfig>,
53
- ): (request: FastifyRequest, reply: FastifyReply) => Promise<any> {
54
- const getters = this.prepareArguments(handlerMetadata)
55
- const formatArguments = async (request: FastifyRequest) => {
56
- const argument: Record<string, any> = {}
57
- const promises: Promise<void>[] = []
58
- for (const getter of getters) {
59
- const res = getter(argument, request)
60
- if (res instanceof Promise) {
61
- promises.push(res)
62
- }
63
- }
64
- await Promise.all(promises)
65
- return argument
66
- }
67
-
68
- return async function (request: FastifyRequest, reply: FastifyReply) {
69
- const controllerInstance = await inject(controller)
70
- const argument = await formatArguments(request)
71
-
72
- await controllerInstance[handlerMetadata.classMethod](argument, reply)
73
- }
74
- }
75
-
76
- provideSchema(
77
- handlerMetadata: HandlerMetadata<BaseStreamConfig>,
78
- ): Record<string, any> {
79
- const schema: Record<string, any> = {}
80
- const { querySchema, requestSchema } = handlerMetadata.config
81
-
82
- if (querySchema) {
83
- schema.querystring = querySchema
84
- }
85
- if (requestSchema) {
86
- schema.body = requestSchema
87
- }
88
-
89
- return schema
90
- }
91
- }
@@ -1,36 +0,0 @@
1
- import { Injectable, InjectableType, InjectionToken } from '@navios/di'
2
-
3
- import { z } from 'zod'
4
-
5
- import type { LoggerService } from './logger-service.interface.mjs'
6
-
7
- import { LoggerInstance } from './logger.service.mjs'
8
-
9
- export const LoggerInjectionToken = 'LoggerInjectionToken'
10
-
11
- export const LoggerOptions = z
12
- .object({
13
- context: z.string().optional(),
14
- options: z
15
- .object({
16
- timestamp: z.boolean().optional(),
17
- })
18
- .optional(),
19
- })
20
- .optional()
21
-
22
- export const Logger = InjectionToken.create<
23
- LoggerInstance,
24
- typeof LoggerOptions
25
- >(LoggerInjectionToken, LoggerOptions)
26
-
27
- @Injectable({
28
- type: InjectableType.Factory,
29
- token: Logger,
30
- })
31
- export class LoggerFactory {
32
- create(ctx: any, args: z.infer<typeof LoggerOptions>) {
33
- // @ts-expect-error We don't need to support this in the current version
34
- return new LoggerInstance(args?.context, args?.options)
35
- }
36
- }
@@ -1,64 +0,0 @@
1
- import type { LoggerService } from './logger-service.interface.mjs'
2
-
3
- import { LoggerInstance } from './logger.service.mjs'
4
-
5
- export class PinoWrapper {
6
- constructor(protected readonly logger: LoggerService) {}
7
-
8
- fatal(message: any, ...optionalParams: any[]) {
9
- if (this.logger.fatal === undefined) {
10
- return this.error(message, ...optionalParams)
11
- }
12
- this.logger.fatal(message, ...optionalParams)
13
- }
14
-
15
- error(message: any, ...optionalParams: any[]) {
16
- this.logger.error(message, ...optionalParams)
17
- }
18
-
19
- warn(message: any, ...optionalParams: any[]) {
20
- this.logger.warn(message, ...optionalParams)
21
- }
22
-
23
- info() {
24
- // We don't want to populate the logs with the original fastify logs
25
- // this.logger.debug?.('INFO', message, ...optionalParams)
26
- }
27
-
28
- debug(message: any, ...optionalParams: any[]) {
29
- this.logger.debug?.(message, ...optionalParams)
30
- }
31
-
32
- trace(message: any, ...optionalParams: any[]) {
33
- this.logger.verbose?.(message, ...optionalParams)
34
- }
35
-
36
- silent() {
37
- // noop
38
- }
39
-
40
- child(options: any) {
41
- const keys = Object.keys(options)
42
- // @ts-expect-error We don't need to support this in the current version
43
- let newContext = this.logger['context'] ?? ''
44
- if (keys.length > 1) {
45
- // @ts-expect-error We don't need to support this in the current version
46
- newContext = `${this.logger['context'] ?? ''}:${JSON.stringify(options)}`
47
- }
48
- return new PinoWrapper(
49
- // @ts-expect-error We don't need to support this in the current version
50
- new LoggerInstance(newContext, this.logger['options']),
51
- )
52
- }
53
-
54
- get level(): any {
55
- if ('level' in this.logger && this.logger.level) {
56
- return this.logger.level
57
- }
58
- const levels = LoggerInstance['logLevels']
59
- if (levels) {
60
- return levels.find((level) => level !== 'verbose')
61
- }
62
- return 'warn'
63
- }
64
- }
@@ -1,124 +0,0 @@
1
- import type { ClassType } from '@navios/di'
2
- import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
3
- import type { ZodTypeProvider } from 'fastify-type-provider-zod'
4
-
5
- import {
6
- getGlobalServiceLocator,
7
- inject,
8
- Injectable,
9
- InjectionToken,
10
- syncInject,
11
- } from '@navios/di'
12
-
13
- import type { HandlerAdapterInterface } from '../adapters/index.mjs'
14
- import type { ModuleMetadata } from '../metadata/index.mjs'
15
-
16
- import { Logger } from '../logger/index.mjs'
17
- import { extractControllerMetadata } from '../metadata/index.mjs'
18
- import { ExecutionContextToken, Reply, Request } from '../tokens/index.mjs'
19
- import { ExecutionContext } from './execution-context.mjs'
20
- import { GuardRunnerService } from './guard-runner.service.mjs'
21
-
22
- @Injectable()
23
- export class ControllerAdapterService {
24
- guardRunner = syncInject(GuardRunnerService)
25
- private logger = syncInject(Logger, {
26
- context: ControllerAdapterService.name,
27
- })
28
-
29
- async setupController(
30
- controller: ClassType,
31
- instance: FastifyInstance,
32
- moduleMetadata: ModuleMetadata,
33
- ) {
34
- const controllerMetadata = extractControllerMetadata(controller)
35
- for (const endpoint of controllerMetadata.endpoints) {
36
- const { classMethod, url, httpMethod, adapterToken } = endpoint
37
-
38
- if (!url || !adapterToken) {
39
- throw new Error(
40
- `[Navios] Malformed Endpoint ${controller.name}:${classMethod}`,
41
- )
42
- }
43
- const adapter = await inject(
44
- adapterToken as InjectionToken<HandlerAdapterInterface>,
45
- )
46
- const executionContext = new ExecutionContext(
47
- moduleMetadata,
48
- controllerMetadata,
49
- endpoint,
50
- )
51
- const hasSchema = adapter.hasSchema?.(endpoint) ?? false
52
- if (hasSchema) {
53
- instance.withTypeProvider<ZodTypeProvider>().route({
54
- method: httpMethod,
55
- url: url.replaceAll('$', ':'),
56
- schema: adapter.provideSchema?.(endpoint) ?? {},
57
- preHandler: this.providePreHandler(executionContext),
58
- handler: this.wrapHandler(
59
- executionContext,
60
- adapter.provideHandler(controller, executionContext, endpoint),
61
- ),
62
- })
63
- } else {
64
- instance.route({
65
- method: httpMethod,
66
- url: url.replaceAll('$', ':'),
67
- preHandler: this.providePreHandler(executionContext),
68
- handler: this.wrapHandler(
69
- executionContext,
70
- adapter.provideHandler(controller, executionContext, endpoint),
71
- ),
72
- })
73
- }
74
-
75
- this.logger.debug(
76
- `Registered ${httpMethod} ${url} for ${controller.name}:${classMethod}`,
77
- )
78
- }
79
- }
80
-
81
- providePreHandler(executionContext: ExecutionContext) {
82
- const guards = this.guardRunner.makeContext(executionContext)
83
- return guards.size > 0
84
- ? this.wrapHandler(
85
- executionContext,
86
- async (request: FastifyRequest, reply: FastifyReply) => {
87
- let canActivate = true
88
- canActivate = await this.guardRunner.runGuards(
89
- guards,
90
- executionContext,
91
- )
92
- if (!canActivate) {
93
- return reply
94
- }
95
- },
96
- )
97
- : undefined
98
- }
99
-
100
- private wrapHandler(
101
- executionContext: ExecutionContext,
102
- handler: (request: FastifyRequest, reply: FastifyReply) => Promise<void>,
103
- ) {
104
- const locator = getGlobalServiceLocator()
105
- return async (request: FastifyRequest, reply: FastifyReply) => {
106
- locator.storeInstance(request, Request)
107
- locator.storeInstance(reply, Reply)
108
- locator.storeInstance(executionContext, ExecutionContextToken)
109
- executionContext.provideRequest(request)
110
- executionContext.provideReply(reply)
111
- try {
112
- return await handler(request, reply)
113
- } finally {
114
- Promise.all([
115
- locator.removeInstance(Request),
116
- locator.removeInstance(Reply),
117
- locator.removeInstance(ExecutionContextToken),
118
- ]).catch((err) => {
119
- this.logger.warn(`Error removing instances: ${err}`)
120
- })
121
- }
122
- }
123
- }
124
- }