@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
@@ -1,21 +1,17 @@
1
- import type { BaseEndpointConfig } from '@navios/common'
2
1
  import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
3
2
  import type { ZodTypeProvider } from 'fastify-type-provider-zod'
4
- import type { AnyZodObject } from 'zod'
5
3
 
6
- import { NaviosException } from '@navios/common'
7
-
8
- import { ZodArray } from 'zod'
9
-
10
- import type { EndpointMetadata, ModuleMetadata } from '../metadata/index.mjs'
4
+ import type { HandlerAdapterInterface } from '../adapters/index.mjs'
5
+ import type { ModuleMetadata } from '../metadata/index.mjs'
11
6
  import type { ClassType } from '../service-locator/index.mjs'
12
7
 
13
8
  import { Logger } from '../logger/index.mjs'
14
- import { EndpointType, extractControllerMetadata } from '../metadata/index.mjs'
9
+ import { extractControllerMetadata } from '../metadata/index.mjs'
15
10
  import {
16
11
  getServiceLocator,
17
12
  inject,
18
13
  Injectable,
14
+ InjectionToken,
19
15
  syncInject,
20
16
  } from '../service-locator/index.mjs'
21
17
  import { ExecutionContextToken, Reply, Request } from '../tokens/index.mjs'
@@ -29,32 +25,51 @@ export class ControllerAdapterService {
29
25
  context: ControllerAdapterService.name,
30
26
  })
31
27
 
32
- setupController(
28
+ async setupController(
33
29
  controller: ClassType,
34
30
  instance: FastifyInstance,
35
31
  moduleMetadata: ModuleMetadata,
36
- ): void {
32
+ ) {
37
33
  const controllerMetadata = extractControllerMetadata(controller)
38
34
  for (const endpoint of controllerMetadata.endpoints) {
39
- const { classMethod, url, httpMethod } = endpoint
35
+ const { classMethod, url, httpMethod, adapterToken } = endpoint
40
36
 
41
- if (!url) {
37
+ if (!url || !adapterToken) {
42
38
  throw new Error(
43
39
  `[Navios] Malformed Endpoint ${controller.name}:${classMethod}`,
44
40
  )
45
41
  }
42
+ const adapter = await inject(
43
+ adapterToken as InjectionToken<HandlerAdapterInterface>,
44
+ )
46
45
  const executionContext = new ExecutionContext(
47
46
  moduleMetadata,
48
47
  controllerMetadata,
49
48
  endpoint,
50
49
  )
51
- instance.withTypeProvider<ZodTypeProvider>().route({
52
- method: httpMethod,
53
- url: url.replaceAll('$', ':'),
54
- schema: this.provideSchemaForConfig(endpoint),
55
- preHandler: this.providePreHandler(executionContext),
56
- handler: this.provideHandler(controller, executionContext, endpoint),
57
- })
50
+ const hasSchema = adapter.hasSchema?.(endpoint) ?? false
51
+ if (hasSchema) {
52
+ instance.withTypeProvider<ZodTypeProvider>().route({
53
+ method: httpMethod,
54
+ url: url.replaceAll('$', ':'),
55
+ schema: adapter.provideSchema?.(endpoint) ?? {},
56
+ preHandler: this.providePreHandler(executionContext),
57
+ handler: this.wrapHandler(
58
+ executionContext,
59
+ adapter.provideHandler(controller, executionContext, endpoint),
60
+ ),
61
+ })
62
+ } else {
63
+ instance.route({
64
+ method: httpMethod,
65
+ url: url.replaceAll('$', ':'),
66
+ preHandler: this.providePreHandler(executionContext),
67
+ handler: this.wrapHandler(
68
+ executionContext,
69
+ adapter.provideHandler(controller, executionContext, endpoint),
70
+ ),
71
+ })
72
+ }
58
73
 
59
74
  this.logger.debug(
60
75
  `Registered ${httpMethod} ${url} for ${controller.name}:${classMethod}`,
@@ -65,239 +80,43 @@ export class ControllerAdapterService {
65
80
  providePreHandler(executionContext: ExecutionContext) {
66
81
  const guards = this.guardRunner.makeContext(executionContext)
67
82
  return guards.size > 0
68
- ? async (request: FastifyRequest, reply: FastifyReply) => {
69
- getServiceLocator().registerInstance(Request, request)
70
- getServiceLocator().registerInstance(Reply, reply)
71
- getServiceLocator().registerInstance(
72
- ExecutionContextToken,
73
- executionContext,
74
- )
75
- executionContext.provideRequest(request)
76
- executionContext.provideReply(reply)
77
- let canActivate = true
78
- try {
83
+ ? this.wrapHandler(
84
+ executionContext,
85
+ async (request: FastifyRequest, reply: FastifyReply) => {
86
+ let canActivate = true
79
87
  canActivate = await this.guardRunner.runGuards(
80
88
  guards,
81
89
  executionContext,
82
90
  )
83
- } finally {
84
- getServiceLocator().removeInstance(Request)
85
- getServiceLocator().removeInstance(Reply)
86
- getServiceLocator().removeInstance(ExecutionContextToken)
87
- }
88
- if (!canActivate) {
89
- return reply
90
- }
91
- }
92
- : undefined
93
- }
94
-
95
- private provideSchemaForConfig(endpointMetadata: EndpointMetadata) {
96
- if (!endpointMetadata.config) {
97
- this.logger.warn(`No config found for endpoint ${endpointMetadata.url}`)
98
- return {}
99
- }
100
- const { querySchema, requestSchema, responseSchema } =
101
- endpointMetadata.config as BaseEndpointConfig
102
- const schema: Record<string, any> = {}
103
- if (querySchema) {
104
- schema.querystring = querySchema
105
- }
106
- if (requestSchema && endpointMetadata.type !== EndpointType.Multipart) {
107
- schema.body = requestSchema
108
- }
109
- if (responseSchema) {
110
- schema.response = {
111
- 200: responseSchema,
112
- }
113
- }
114
-
115
- return schema
116
- }
117
-
118
- private provideHandler(
119
- controller: ClassType,
120
- executionContext: ExecutionContext,
121
- endpointMetadata: EndpointMetadata,
122
- ): (request: FastifyRequest, reply: FastifyReply) => Promise<void> {
123
- switch (endpointMetadata.type) {
124
- case EndpointType.Unknown:
125
- this.logger.error(
126
- `Unknown endpoint type ${endpointMetadata.type} for ${controller.name}:${endpointMetadata.classMethod}`,
127
- )
128
- throw new NaviosException('Unknown endpoint type')
129
- case EndpointType.Endpoint:
130
- return this.provideHandlerForConfig(
131
- controller,
132
- executionContext,
133
- endpointMetadata,
134
- )
135
- case EndpointType.Stream:
136
- return this.provideHandlerForStream(
137
- controller,
138
- executionContext,
139
- endpointMetadata,
140
- )
141
- case EndpointType.Multipart:
142
- return this.provideHandlerForMultipart(
143
- controller,
144
- executionContext,
145
- endpointMetadata,
91
+ if (!canActivate) {
92
+ return reply
93
+ }
94
+ },
146
95
  )
147
- case EndpointType.Handler:
148
- this.logger.error('Not implemented yet')
149
- throw new NaviosException('Not implemented yet')
150
- }
151
- }
152
-
153
- private provideHandlerForConfig(
154
- controller: ClassType,
155
- executionContext: ExecutionContext,
156
- endpointMetadata: EndpointMetadata,
157
- ): (request: FastifyRequest, reply: FastifyReply) => Promise<void> {
158
- return async (request, reply) => {
159
- getServiceLocator().registerInstance(Request, request)
160
- getServiceLocator().registerInstance(Reply, reply)
161
- getServiceLocator().registerInstance(
162
- ExecutionContextToken,
163
- executionContext,
164
- )
165
- executionContext.provideRequest(request)
166
- executionContext.provideReply(reply)
167
- const controllerInstance = await inject(controller)
168
- try {
169
- const { query, params, body } = request
170
- const argument: Record<string, any> = {}
171
- if (query && Object.keys(query).length > 0) {
172
- argument.params = query
173
- }
174
- if (params && Object.keys(params).length > 0) {
175
- argument.urlParams = params
176
- }
177
- if (body) {
178
- argument.data = body
179
- }
180
- const result =
181
- await controllerInstance[endpointMetadata.classMethod](argument)
182
- reply
183
- .status(endpointMetadata.successStatusCode)
184
- .headers(endpointMetadata.headers)
185
- .send(result)
186
- } finally {
187
- getServiceLocator().removeInstance(Request)
188
- getServiceLocator().removeInstance(Reply)
189
- getServiceLocator().removeInstance(ExecutionContextToken)
190
- }
191
- }
192
- }
193
-
194
- private provideHandlerForStream(
195
- controller: ClassType,
196
- executionContext: ExecutionContext,
197
- endpointMetadata: EndpointMetadata,
198
- ): (request: FastifyRequest, reply: FastifyReply) => Promise<void> {
199
- return async (request, reply) => {
200
- getServiceLocator().registerInstance(Request, request)
201
- getServiceLocator().registerInstance(Reply, reply)
202
- getServiceLocator().registerInstance(
203
- ExecutionContextToken,
204
- executionContext,
205
- )
206
- executionContext.provideRequest(request)
207
- executionContext.provideReply(reply)
208
- const controllerInstance = await inject(controller)
209
- try {
210
- const { query, params, body } = request
211
- const argument: Record<string, any> = {}
212
- if (query && Object.keys(query).length > 0) {
213
- argument.params = query
214
- }
215
- if (params && Object.keys(params).length > 0) {
216
- argument.urlParams = params
217
- }
218
- if (body) {
219
- argument.data = body
220
- }
221
-
222
- await controllerInstance[endpointMetadata.classMethod](argument, reply)
223
- } finally {
224
- getServiceLocator().removeInstance(Request)
225
- getServiceLocator().removeInstance(Reply)
226
- getServiceLocator().removeInstance(ExecutionContextToken)
227
- }
228
- }
96
+ : undefined
229
97
  }
230
98
 
231
- private provideHandlerForMultipart(
232
- controller: ClassType,
99
+ private wrapHandler(
233
100
  executionContext: ExecutionContext,
234
- endpointMetadata: EndpointMetadata,
235
- ): (request: FastifyRequest, reply: FastifyReply) => Promise<void> {
236
- const config = endpointMetadata.config as BaseEndpointConfig
237
- const requestSchema = config.requestSchema as unknown as AnyZodObject
238
- const shape = requestSchema._def.shape()
239
- return async (request, reply) => {
240
- getServiceLocator().registerInstance(Request, request)
241
- getServiceLocator().registerInstance(Reply, reply)
242
- getServiceLocator().registerInstance(
243
- ExecutionContextToken,
244
- executionContext,
245
- )
101
+ handler: (request: FastifyRequest, reply: FastifyReply) => Promise<void>,
102
+ ) {
103
+ const locator = getServiceLocator()
104
+ return async (request: FastifyRequest, reply: FastifyReply) => {
105
+ locator.registerInstance(Request, request)
106
+ locator.registerInstance(Reply, reply)
107
+ locator.registerInstance(ExecutionContextToken, executionContext)
246
108
  executionContext.provideRequest(request)
247
109
  executionContext.provideReply(reply)
248
- const controllerInstance = await inject(controller)
249
110
  try {
250
- const parts = request.parts()
251
- const { query, params } = request
252
- const argument: Record<string, any> = {}
253
- if (query && Object.keys(query).length > 0) {
254
- argument.params = query
255
- }
256
- if (params && Object.keys(params).length > 0) {
257
- argument.urlParams = params
258
- }
259
- const req: Record<string, any> = {}
260
- for await (const part of parts) {
261
- if (!shape[part.fieldname]) {
262
- throw new NaviosException(
263
- `Invalid field name ${part.fieldname} for multipart request`,
264
- )
265
- }
266
- const schema = shape[part.fieldname]
267
- if (part.type === 'file') {
268
- const file = new File([await part.toBuffer()], part.filename, {
269
- type: part.mimetype,
270
- })
271
- if (schema instanceof ZodArray) {
272
- if (!req[part.fieldname]) {
273
- req[part.fieldname] = []
274
- }
275
- req[part.fieldname].push(file)
276
- } else {
277
- req[part.fieldname] = file
278
- }
279
- } else {
280
- if (schema instanceof ZodArray) {
281
- if (!req[part.fieldname]) {
282
- req[part.fieldname] = []
283
- }
284
- req[part.fieldname].push(part.value)
285
- } else {
286
- req[part.fieldname] = part.value
287
- }
288
- }
289
- }
290
- argument.data = requestSchema.parse(req)
291
- const result =
292
- await controllerInstance[endpointMetadata.classMethod](argument)
293
- reply
294
- .status(endpointMetadata.successStatusCode)
295
- .headers(endpointMetadata.headers)
296
- .send(result)
111
+ return await handler(request, reply)
297
112
  } finally {
298
- getServiceLocator().removeInstance(Request)
299
- getServiceLocator().removeInstance(Reply)
300
- getServiceLocator().removeInstance(ExecutionContextToken)
113
+ Promise.all([
114
+ locator.removeInstance(Request),
115
+ locator.removeInstance(Reply),
116
+ locator.removeInstance(ExecutionContextToken),
117
+ ]).catch((err) => {
118
+ this.logger.warn(`Error removing instances: ${err}`)
119
+ })
301
120
  }
302
121
  }
303
122
  }
@@ -2,7 +2,7 @@ import type { FastifyReply, FastifyRequest } from 'fastify'
2
2
 
3
3
  import type {
4
4
  ControllerMetadata,
5
- EndpointMetadata,
5
+ HandlerMetadata,
6
6
  ModuleMetadata,
7
7
  } from '../metadata/index.mjs'
8
8
 
@@ -12,7 +12,7 @@ export class ExecutionContext {
12
12
  constructor(
13
13
  private readonly module: ModuleMetadata,
14
14
  private readonly controller: ControllerMetadata,
15
- private readonly handler: EndpointMetadata,
15
+ private readonly handler: HandlerMetadata,
16
16
  ) {}
17
17
  getModule(): ModuleMetadata {
18
18
  return this.module
@@ -22,7 +22,7 @@ export class ExecutionContext {
22
22
  return this.controller
23
23
  }
24
24
 
25
- getHandler(): EndpointMetadata {
25
+ getHandler(): HandlerMetadata {
26
26
  return this.handler
27
27
  }
28
28
 
@@ -47,6 +47,7 @@ export class ExecutionContext {
47
47
  provideRequest(request: FastifyRequest): void {
48
48
  this.request = request
49
49
  }
50
+
50
51
  provideReply(reply: FastifyReply): void {
51
52
  this.reply = reply
52
53
  }