@navios/core 0.1.9 → 0.1.10
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.
- package/dist/_tsup-dts-rollup.d.mts +27 -0
- package/dist/_tsup-dts-rollup.d.ts +27 -0
- package/dist/chunk-Z2AVZ4BT.mjs +65 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3297 -48
- package/dist/index.mjs +135 -48
- package/dist/multipart-23QO76VV.mjs +3120 -0
- package/package.json +4 -3
- package/src/decorators/index.mts +1 -0
- package/src/decorators/multipart.decorator.mts +100 -0
- package/src/metadata/endpoint.metadata.mts +1 -0
- package/src/navios.application.mts +30 -0
- package/src/services/controller-adapter.service.mts +84 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@navios/core",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Oleksandr Hanzha",
|
|
6
6
|
"email": "alex@granted.name"
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"main": "./dist/index.js",
|
|
16
16
|
"module": "./dist/index.mjs",
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@navios/common": "^0.1.
|
|
18
|
+
"@navios/common": "^0.1.3",
|
|
19
19
|
"zod": "^3.23.8"
|
|
20
20
|
},
|
|
21
21
|
"exports": {
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"./package.json": "./package.json"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
|
-
"@
|
|
35
|
+
"@fastify/multipart": "^9.0.3",
|
|
36
|
+
"@navios/common": "^0.1.3",
|
|
36
37
|
"tsx": "^4.19.4",
|
|
37
38
|
"typescript": "^5.8.3",
|
|
38
39
|
"zod": "^3.24.4"
|
package/src/decorators/index.mts
CHANGED
|
@@ -3,5 +3,6 @@ export * from './endpoint.decorator.mjs'
|
|
|
3
3
|
export * from './header.decorator.mjs'
|
|
4
4
|
export * from './http-code.decorator.mjs'
|
|
5
5
|
export * from './module.decorator.mjs'
|
|
6
|
+
export * from './multipart.decorator.mjs'
|
|
6
7
|
export * from './stream.decorator.mjs'
|
|
7
8
|
export * from './use-guards.decorator.mjs'
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BaseEndpointConfig,
|
|
3
|
+
EndpointFunctionArgs,
|
|
4
|
+
HttpMethod,
|
|
5
|
+
} from '@navios/common'
|
|
6
|
+
import type { AnyZodObject, z, ZodType } from 'zod'
|
|
7
|
+
|
|
8
|
+
import { ZodDiscriminatedUnion } from 'zod'
|
|
9
|
+
|
|
10
|
+
import { EndpointType, getEndpointMetadata } from '../metadata/index.mjs'
|
|
11
|
+
|
|
12
|
+
export type MultipartParams<
|
|
13
|
+
EndpointDeclaration extends {
|
|
14
|
+
config: BaseEndpointConfig<any, any, any, any, any>
|
|
15
|
+
},
|
|
16
|
+
Url extends string = EndpointDeclaration['config']['url'],
|
|
17
|
+
QuerySchema = EndpointDeclaration['config']['querySchema'],
|
|
18
|
+
> = QuerySchema extends AnyZodObject
|
|
19
|
+
? EndpointDeclaration['config']['requestSchema'] extends ZodType
|
|
20
|
+
? EndpointFunctionArgs<
|
|
21
|
+
Url,
|
|
22
|
+
QuerySchema,
|
|
23
|
+
EndpointDeclaration['config']['requestSchema']
|
|
24
|
+
>
|
|
25
|
+
: EndpointFunctionArgs<Url, QuerySchema, undefined>
|
|
26
|
+
: EndpointDeclaration['config']['requestSchema'] extends ZodType
|
|
27
|
+
? EndpointFunctionArgs<
|
|
28
|
+
Url,
|
|
29
|
+
undefined,
|
|
30
|
+
EndpointDeclaration['config']['requestSchema']
|
|
31
|
+
>
|
|
32
|
+
: EndpointFunctionArgs<Url, undefined, undefined>
|
|
33
|
+
|
|
34
|
+
export type MultipartResult<
|
|
35
|
+
EndpointDeclaration extends {
|
|
36
|
+
config: BaseEndpointConfig<any, any, any, any, any>
|
|
37
|
+
},
|
|
38
|
+
> =
|
|
39
|
+
EndpointDeclaration['config']['responseSchema'] extends ZodDiscriminatedUnion<
|
|
40
|
+
any,
|
|
41
|
+
infer Options
|
|
42
|
+
>
|
|
43
|
+
? Promise<z.input<Options[number]>>
|
|
44
|
+
: Promise<z.input<EndpointDeclaration['config']['responseSchema']>>
|
|
45
|
+
|
|
46
|
+
export function Multipart<
|
|
47
|
+
Method extends HttpMethod = HttpMethod,
|
|
48
|
+
Url extends string = string,
|
|
49
|
+
QuerySchema = undefined,
|
|
50
|
+
ResponseSchema extends ZodType = ZodType,
|
|
51
|
+
RequestSchema = ZodType,
|
|
52
|
+
>(endpoint: {
|
|
53
|
+
config: BaseEndpointConfig<
|
|
54
|
+
Method,
|
|
55
|
+
Url,
|
|
56
|
+
QuerySchema,
|
|
57
|
+
ResponseSchema,
|
|
58
|
+
RequestSchema
|
|
59
|
+
>
|
|
60
|
+
}) {
|
|
61
|
+
return (
|
|
62
|
+
target: (
|
|
63
|
+
params: QuerySchema extends AnyZodObject
|
|
64
|
+
? RequestSchema extends ZodType
|
|
65
|
+
? EndpointFunctionArgs<Url, QuerySchema, RequestSchema>
|
|
66
|
+
: EndpointFunctionArgs<Url, QuerySchema, undefined>
|
|
67
|
+
: RequestSchema extends ZodType
|
|
68
|
+
? EndpointFunctionArgs<Url, undefined, RequestSchema>
|
|
69
|
+
: EndpointFunctionArgs<Url, undefined, undefined>,
|
|
70
|
+
) => Promise<z.input<ResponseSchema>>,
|
|
71
|
+
context: ClassMethodDecoratorContext,
|
|
72
|
+
) => {
|
|
73
|
+
if (typeof target !== 'function') {
|
|
74
|
+
throw new Error(
|
|
75
|
+
'[Navios] Endpoint decorator can only be used on functions.',
|
|
76
|
+
)
|
|
77
|
+
}
|
|
78
|
+
if (context.kind !== 'method') {
|
|
79
|
+
throw new Error(
|
|
80
|
+
'[Navios] Endpoint decorator can only be used on methods.',
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
const config = endpoint.config
|
|
84
|
+
if (context.metadata) {
|
|
85
|
+
let endpointMetadata = getEndpointMetadata(target, context)
|
|
86
|
+
if (endpointMetadata.config && endpointMetadata.config.url) {
|
|
87
|
+
throw new Error(
|
|
88
|
+
`[Navios] Endpoint ${config.method} ${config.url} already exists. Please use a different method or url.`,
|
|
89
|
+
)
|
|
90
|
+
}
|
|
91
|
+
// @ts-expect-error We don't need to set correctly in the metadata
|
|
92
|
+
endpointMetadata.config = config
|
|
93
|
+
endpointMetadata.type = EndpointType.Multipart
|
|
94
|
+
endpointMetadata.classMethod = target.name
|
|
95
|
+
endpointMetadata.httpMethod = config.method
|
|
96
|
+
endpointMetadata.url = config.url
|
|
97
|
+
}
|
|
98
|
+
return target
|
|
99
|
+
}
|
|
100
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { FastifyCorsOptions } from '@fastify/cors'
|
|
2
|
+
import type { FastifyMultipartOptions } from '@fastify/multipart'
|
|
2
3
|
import type {
|
|
3
4
|
FastifyInstance,
|
|
4
5
|
FastifyListenOptions,
|
|
@@ -50,6 +51,7 @@ export class NaviosApplication {
|
|
|
50
51
|
})
|
|
51
52
|
private server: FastifyInstance | null = null
|
|
52
53
|
private corsOptions: FastifyCorsOptions | null = null
|
|
54
|
+
private multipartOptions: FastifyMultipartOptions | true | null = null
|
|
53
55
|
private globalPrefix: string | null = null
|
|
54
56
|
|
|
55
57
|
private appModule: ClassTypeWithInstance<NaviosModule> | null = null
|
|
@@ -81,6 +83,10 @@ export class NaviosApplication {
|
|
|
81
83
|
await this.server.register(cors, this.corsOptions)
|
|
82
84
|
}
|
|
83
85
|
|
|
86
|
+
if (this.multipartOptions) {
|
|
87
|
+
await this.configureMultipart(this.server, this.multipartOptions)
|
|
88
|
+
}
|
|
89
|
+
|
|
84
90
|
await this.initModules()
|
|
85
91
|
await this.server.ready()
|
|
86
92
|
|
|
@@ -147,6 +153,26 @@ export class NaviosApplication {
|
|
|
147
153
|
})
|
|
148
154
|
}
|
|
149
155
|
|
|
156
|
+
async configureMultipart(
|
|
157
|
+
server: FastifyInstance,
|
|
158
|
+
options: FastifyMultipartOptions | true,
|
|
159
|
+
): Promise<void> {
|
|
160
|
+
if (options) {
|
|
161
|
+
try {
|
|
162
|
+
const multipartModule = await import('@fastify/multipart')
|
|
163
|
+
await server.register(
|
|
164
|
+
multipartModule.default,
|
|
165
|
+
typeof options === 'object' ? options : {},
|
|
166
|
+
)
|
|
167
|
+
} catch (error) {
|
|
168
|
+
this.logger.error(
|
|
169
|
+
`@fastify/multipart is not installed. Please install it.`,
|
|
170
|
+
)
|
|
171
|
+
throw error
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
150
176
|
private async initModules() {
|
|
151
177
|
const modules = this.moduleLoader.getAllModules()
|
|
152
178
|
const promises: PromiseLike<any>[] = []
|
|
@@ -183,6 +209,10 @@ export class NaviosApplication {
|
|
|
183
209
|
this.corsOptions = options
|
|
184
210
|
}
|
|
185
211
|
|
|
212
|
+
enableMultipart(options: FastifyMultipartOptions) {
|
|
213
|
+
this.multipartOptions = options
|
|
214
|
+
}
|
|
215
|
+
|
|
186
216
|
setGlobalPrefix(prefix: string) {
|
|
187
217
|
this.globalPrefix = prefix
|
|
188
218
|
}
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import type { BaseEndpointConfig } from '@navios/common'
|
|
2
2
|
import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
|
|
3
3
|
import type { ZodTypeProvider } from 'fastify-type-provider-zod'
|
|
4
|
+
import type { AnyZodObject } from 'zod'
|
|
4
5
|
|
|
5
6
|
import { NaviosException } from '@navios/common'
|
|
6
7
|
|
|
8
|
+
import { ZodArray } from 'zod'
|
|
9
|
+
|
|
7
10
|
import type { EndpointMetadata, ModuleMetadata } from '../metadata/index.mjs'
|
|
8
11
|
import type { ClassType } from '../service-locator/index.mjs'
|
|
9
12
|
|
|
@@ -100,7 +103,7 @@ export class ControllerAdapterService {
|
|
|
100
103
|
if (querySchema) {
|
|
101
104
|
schema.querystring = querySchema
|
|
102
105
|
}
|
|
103
|
-
if (requestSchema) {
|
|
106
|
+
if (requestSchema && endpointMetadata.type !== EndpointType.Multipart) {
|
|
104
107
|
schema.body = requestSchema
|
|
105
108
|
}
|
|
106
109
|
if (responseSchema) {
|
|
@@ -135,6 +138,12 @@ export class ControllerAdapterService {
|
|
|
135
138
|
executionContext,
|
|
136
139
|
endpointMetadata,
|
|
137
140
|
)
|
|
141
|
+
case EndpointType.Multipart:
|
|
142
|
+
return this.provideHandlerForMultipart(
|
|
143
|
+
controller,
|
|
144
|
+
executionContext,
|
|
145
|
+
endpointMetadata,
|
|
146
|
+
)
|
|
138
147
|
case EndpointType.Handler:
|
|
139
148
|
this.logger.error('Not implemented yet')
|
|
140
149
|
throw new NaviosException('Not implemented yet')
|
|
@@ -218,4 +227,78 @@ export class ControllerAdapterService {
|
|
|
218
227
|
}
|
|
219
228
|
}
|
|
220
229
|
}
|
|
230
|
+
|
|
231
|
+
private provideHandlerForMultipart(
|
|
232
|
+
controller: ClassType,
|
|
233
|
+
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
|
+
)
|
|
246
|
+
executionContext.provideRequest(request)
|
|
247
|
+
executionContext.provideReply(reply)
|
|
248
|
+
const controllerInstance = await inject(controller)
|
|
249
|
+
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.body = 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)
|
|
297
|
+
} finally {
|
|
298
|
+
getServiceLocator().removeInstance(Request)
|
|
299
|
+
getServiceLocator().removeInstance(Reply)
|
|
300
|
+
getServiceLocator().removeInstance(ExecutionContextToken)
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
221
304
|
}
|