fusion-framework 1.2.3 → 1.2.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.
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/index.js
CHANGED
|
@@ -134,7 +134,7 @@ header.fingerprint = () =>
|
|
|
134
134
|
: {
|
|
135
135
|
'X-Powered-By': 'Fusion Framework',
|
|
136
136
|
'X-Framework': 'Fusion',
|
|
137
|
-
['X-Fusion-Version']: '1.2.
|
|
137
|
+
['X-Fusion-Version']: '1.2.4',
|
|
138
138
|
}
|
|
139
139
|
|
|
140
140
|
function isThenable(value) {
|
|
@@ -219,6 +219,121 @@ function resolveRoutePath(routePath, ApiClass) {
|
|
|
219
219
|
return native.resolveRoutePathJs(routePath, ApiClass.name)
|
|
220
220
|
}
|
|
221
221
|
|
|
222
|
+
function apiActionName(methodName) {
|
|
223
|
+
if (typeof native.apiActionNameJs === 'function') {
|
|
224
|
+
return native.apiActionNameJs(methodName)
|
|
225
|
+
}
|
|
226
|
+
let stem = methodName
|
|
227
|
+
if (methodName.endsWith('Action') && methodName.length > 6) stem = methodName.slice(0, -6)
|
|
228
|
+
else if (methodName.endsWith('ACTION') && methodName.length > 6) stem = methodName.slice(0, -6)
|
|
229
|
+
return stem.toLowerCase()
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function resolveMethodRoutePath(template, className, methodName) {
|
|
233
|
+
if (typeof native.resolveMethodRoutePathJs === 'function') {
|
|
234
|
+
return native.resolveMethodRoutePathJs(template, className, methodName)
|
|
235
|
+
}
|
|
236
|
+
return resolveRoutePath(template, { name: className }).replace(
|
|
237
|
+
/\[action\]/g,
|
|
238
|
+
apiActionName(methodName),
|
|
239
|
+
)
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function joinRoutePaths(base, segment) {
|
|
243
|
+
const left = String(base || '').replace(/\/+$/, '')
|
|
244
|
+
const right = String(segment || '').replace(/^\/+|\/+$/g, '')
|
|
245
|
+
if (!right) return left || '/'
|
|
246
|
+
if (!left) return `/${right}`
|
|
247
|
+
return `${left}/${right}`
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function resolveHandlerRoute(classBasePath, template, className, methodName) {
|
|
251
|
+
if (typeof native.resolveHandlerRouteJs === 'function') {
|
|
252
|
+
return native.resolveHandlerRouteJs(classBasePath, template, className, methodName)
|
|
253
|
+
}
|
|
254
|
+
const resolved = resolveMethodRoutePath(template, className, methodName)
|
|
255
|
+
if (String(template).startsWith('/')) {
|
|
256
|
+
return joinRoutePaths('', resolved.replace(/^\/+/, ''))
|
|
257
|
+
}
|
|
258
|
+
return joinRoutePaths(classBasePath, resolved)
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function httpRoute(method, route, options = {}) {
|
|
262
|
+
const meta = {
|
|
263
|
+
method: String(method).toLowerCase(),
|
|
264
|
+
template: route,
|
|
265
|
+
tags: Array.isArray(options.tags) ? options.tags : [],
|
|
266
|
+
desc: options.desc ?? null,
|
|
267
|
+
title: options.title ?? null,
|
|
268
|
+
deprecated: !!options.deprecated,
|
|
269
|
+
}
|
|
270
|
+
function wrap(fn) {
|
|
271
|
+
fn.__fusionHttpRoute = meta
|
|
272
|
+
return fn
|
|
273
|
+
}
|
|
274
|
+
return wrap
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function httpGet(route, options = {}) {
|
|
278
|
+
return httpRoute('get', route, options)
|
|
279
|
+
}
|
|
280
|
+
function httpPost(route, options = {}) {
|
|
281
|
+
return httpRoute('post', route, options)
|
|
282
|
+
}
|
|
283
|
+
function httpPut(route, options = {}) {
|
|
284
|
+
return httpRoute('put', route, options)
|
|
285
|
+
}
|
|
286
|
+
function httpPatch(route, options = {}) {
|
|
287
|
+
return httpRoute('patch', route, options)
|
|
288
|
+
}
|
|
289
|
+
function httpDelete(route, options = {}) {
|
|
290
|
+
return httpRoute('delete', route, options)
|
|
291
|
+
}
|
|
292
|
+
function httpHead(route, options = {}) {
|
|
293
|
+
return httpRoute('head', route, options)
|
|
294
|
+
}
|
|
295
|
+
function httpOptions(route, options = {}) {
|
|
296
|
+
return httpRoute('options', route, options)
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function collectRouteSlots(ApiClass, classBasePath, classSwagger) {
|
|
300
|
+
const slots = []
|
|
301
|
+
const custom = new Set()
|
|
302
|
+
const className = ApiClass.name
|
|
303
|
+
|
|
304
|
+
for (const key of Object.getOwnPropertyNames(ApiClass.prototype)) {
|
|
305
|
+
if (key === 'constructor' || key.startsWith('_')) continue
|
|
306
|
+
const fn = ApiClass.prototype[key]
|
|
307
|
+
if (typeof fn !== 'function' || !fn.__fusionHttpRoute) continue
|
|
308
|
+
custom.add(key)
|
|
309
|
+
const meta = fn.__fusionHttpRoute
|
|
310
|
+
slots.push({
|
|
311
|
+
path: resolveHandlerRoute(classBasePath, meta.template, className, key),
|
|
312
|
+
httpMethod: meta.method,
|
|
313
|
+
handlerMethod: key,
|
|
314
|
+
swagger: {
|
|
315
|
+
tags: meta.tags,
|
|
316
|
+
description: meta.desc,
|
|
317
|
+
title: meta.title,
|
|
318
|
+
deprecated: meta.deprecated,
|
|
319
|
+
},
|
|
320
|
+
})
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
for (const methodName of HTTP_METHODS) {
|
|
324
|
+
if (custom.has(methodName)) continue
|
|
325
|
+
if (!definesMethod(ApiClass, methodName)) continue
|
|
326
|
+
slots.push({
|
|
327
|
+
path: classBasePath,
|
|
328
|
+
httpMethod: methodName,
|
|
329
|
+
handlerMethod: methodName,
|
|
330
|
+
swagger: classSwagger,
|
|
331
|
+
})
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
return slots
|
|
335
|
+
}
|
|
336
|
+
|
|
222
337
|
function emptyRequest() {
|
|
223
338
|
return {
|
|
224
339
|
method: '',
|
|
@@ -372,17 +487,21 @@ function router(routePath, options = {}) {
|
|
|
372
487
|
)
|
|
373
488
|
}
|
|
374
489
|
|
|
490
|
+
const classSwagger = {
|
|
491
|
+
tags: Array.isArray(options.tags) ? options.tags : [],
|
|
492
|
+
description: options.desc ?? null,
|
|
493
|
+
title: options.title ?? null,
|
|
494
|
+
deprecated: !!options.deprecated,
|
|
495
|
+
}
|
|
496
|
+
|
|
375
497
|
registry.push({
|
|
376
498
|
path: resolved,
|
|
499
|
+
classBasePath: resolved,
|
|
377
500
|
ApiClass,
|
|
378
501
|
middleware: routeMiddleware,
|
|
379
|
-
swagger:
|
|
380
|
-
tags: Array.isArray(options.tags) ? options.tags : [],
|
|
381
|
-
description: options.desc ?? null,
|
|
382
|
-
title: options.title ?? null,
|
|
383
|
-
deprecated: !!options.deprecated,
|
|
384
|
-
},
|
|
502
|
+
swagger: classSwagger,
|
|
385
503
|
version_prefix: v,
|
|
504
|
+
slots: collectRouteSlots(ApiClass, resolved, classSwagger),
|
|
386
505
|
})
|
|
387
506
|
return ApiClass
|
|
388
507
|
}
|
|
@@ -612,18 +731,18 @@ function fillOpenApiPaths(openapi, versionFilter = null) {
|
|
|
612
731
|
|
|
613
732
|
for (const item of registry) {
|
|
614
733
|
if (!routeMatchesVersion(item, versionFilter)) continue
|
|
615
|
-
const {
|
|
616
|
-
const
|
|
617
|
-
const resolvedPath = p.startsWith('/') ? p : `/${p}`
|
|
618
|
-
|
|
619
|
-
if (!openapi.paths[resolvedPath]) openapi.paths[resolvedPath] = {}
|
|
734
|
+
const { ApiClass, swagger: routeSwagger } = item
|
|
735
|
+
const slots = item.slots || []
|
|
620
736
|
|
|
621
|
-
for (const
|
|
622
|
-
|
|
737
|
+
for (const slot of slots) {
|
|
738
|
+
const pathParams = parsePathParams(slot.path)
|
|
739
|
+
const resolvedPath = slot.path.startsWith('/') ? slot.path : `/${slot.path}`
|
|
740
|
+
const routeSwaggerEntry = slot.swagger || routeSwagger
|
|
623
741
|
|
|
624
|
-
|
|
625
|
-
const methodLower = String(methodName).toLowerCase()
|
|
742
|
+
if (!openapi.paths[resolvedPath]) openapi.paths[resolvedPath] = {}
|
|
626
743
|
|
|
744
|
+
const methodLower = String(slot.httpMethod).toLowerCase()
|
|
745
|
+
const methodUpper = methodLower.toUpperCase()
|
|
627
746
|
const params = pathParams.map((name) => ({
|
|
628
747
|
name,
|
|
629
748
|
in: 'path',
|
|
@@ -632,11 +751,11 @@ function fillOpenApiPaths(openapi, versionFilter = null) {
|
|
|
632
751
|
}))
|
|
633
752
|
|
|
634
753
|
openapi.paths[resolvedPath][methodLower] = {
|
|
635
|
-
tags:
|
|
636
|
-
summary:
|
|
637
|
-
description:
|
|
638
|
-
deprecated: !!
|
|
639
|
-
operationId: `${ApiClass.name}_${
|
|
754
|
+
tags: routeSwaggerEntry?.tags?.length ? routeSwaggerEntry.tags : [],
|
|
755
|
+
summary: routeSwaggerEntry?.title ?? `${ApiClass.name}.${slot.handlerMethod}`,
|
|
756
|
+
description: routeSwaggerEntry?.description ?? '',
|
|
757
|
+
deprecated: !!routeSwaggerEntry?.deprecated,
|
|
758
|
+
operationId: `${ApiClass.name}_${slot.handlerMethod}`,
|
|
640
759
|
parameters: params,
|
|
641
760
|
responses: { 200: { description: 'OK' } },
|
|
642
761
|
}
|
|
@@ -751,16 +870,16 @@ class FusionApp {
|
|
|
751
870
|
if (this.mounted) return
|
|
752
871
|
activeGlobalMiddleware = [...this._middleware]
|
|
753
872
|
|
|
754
|
-
for (const {
|
|
755
|
-
for (const
|
|
756
|
-
|
|
757
|
-
this.engine.route(
|
|
873
|
+
for (const { ApiClass, middleware: routeMiddleware = [], slots = [] } of registry) {
|
|
874
|
+
for (const slot of slots) {
|
|
875
|
+
const handlerMethod = slot.handlerMethod
|
|
876
|
+
this.engine.route(String(slot.httpMethod).toUpperCase(), slot.path, (errOrRequest, maybeRequest) => {
|
|
758
877
|
const request = nativeRequestArg(errOrRequest, maybeRequest)
|
|
759
878
|
const chain = [...activeGlobalMiddleware, ...routeMiddleware]
|
|
760
879
|
const handler = async (req) => {
|
|
761
880
|
try {
|
|
762
881
|
const instance = new ApiClass(req || emptyRequest())
|
|
763
|
-
const fn = instance[
|
|
882
|
+
const fn = instance[handlerMethod]
|
|
764
883
|
return await Promise.resolve(fn.call(instance))
|
|
765
884
|
} catch (err) {
|
|
766
885
|
if (err instanceof HTTPException) return err.toResponse()
|
|
@@ -852,8 +971,17 @@ module.exports = {
|
|
|
852
971
|
HTTPException,
|
|
853
972
|
router,
|
|
854
973
|
route,
|
|
974
|
+
httpGet,
|
|
975
|
+
httpPost,
|
|
976
|
+
httpPut,
|
|
977
|
+
httpPatch,
|
|
978
|
+
httpDelete,
|
|
979
|
+
httpHead,
|
|
980
|
+
httpOptions,
|
|
855
981
|
apiResourceName,
|
|
856
982
|
resolveRoutePath,
|
|
983
|
+
resolveHandlerRoute,
|
|
984
|
+
apiActionName,
|
|
857
985
|
configure,
|
|
858
986
|
getSettings,
|
|
859
987
|
settings,
|