fusion-framework 1.2.0 → 1.2.2
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,30 +134,43 @@ 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.2',
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
+
function isThenable(value) {
|
|
141
|
+
return value != null && typeof value.then === 'function'
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
async function awaitMaybe(value) {
|
|
145
|
+
// Nested thenables (middleware wrapping async handlers) — same idea as Python
|
|
146
|
+
// awaiting coroutines before treating the value as an HTTP body.
|
|
147
|
+
let current = value
|
|
148
|
+
for (let i = 0; i < 8 && isThenable(current); i++) {
|
|
149
|
+
current = await current
|
|
150
|
+
}
|
|
151
|
+
return current
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function mergeResponseHeaders(result, extra) {
|
|
155
|
+
if (!result || typeof result !== 'object') {
|
|
156
|
+
return { status: 200, body: result, headers: { ...extra } }
|
|
157
|
+
}
|
|
158
|
+
const headers = { ...extra, ...(result.headers || {}) }
|
|
159
|
+
return { ...result, headers }
|
|
160
|
+
}
|
|
161
|
+
|
|
140
162
|
function frameworkHeaders() {
|
|
141
163
|
const extra = header.fingerprint()
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
const
|
|
145
|
-
|
|
146
|
-
return value.then(apply)
|
|
147
|
-
}
|
|
148
|
-
if (!value || typeof value !== 'object') {
|
|
149
|
-
return { status: 200, body: value, headers: { ...extra } }
|
|
150
|
-
}
|
|
151
|
-
const headers = { ...extra, ...(value.headers || {}) }
|
|
152
|
-
return { ...value, headers }
|
|
153
|
-
}
|
|
154
|
-
return apply(result)
|
|
164
|
+
// Async so Promises from callNext are never stuffed into `body` as objects.
|
|
165
|
+
return async (request, callNext) => {
|
|
166
|
+
const result = await awaitMaybe(callNext(request))
|
|
167
|
+
return mergeResponseHeaders(result, extra)
|
|
155
168
|
}
|
|
156
169
|
}
|
|
157
170
|
|
|
158
171
|
class FusionBaseApi {
|
|
159
172
|
constructor(request) {
|
|
160
|
-
this.request = request
|
|
173
|
+
this.request = request && typeof request === 'object' ? request : emptyRequest()
|
|
161
174
|
}
|
|
162
175
|
|
|
163
176
|
get method() {
|
|
@@ -206,7 +219,39 @@ function resolveRoutePath(routePath, ApiClass) {
|
|
|
206
219
|
return native.resolveRoutePathJs(routePath, ApiClass.name)
|
|
207
220
|
}
|
|
208
221
|
|
|
222
|
+
function emptyRequest() {
|
|
223
|
+
return {
|
|
224
|
+
method: '',
|
|
225
|
+
path: '',
|
|
226
|
+
body: '',
|
|
227
|
+
headers: {},
|
|
228
|
+
params: {},
|
|
229
|
+
query: {},
|
|
230
|
+
state: {},
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* N-API threadsafe callbacks may be `(request)` (Fatal) or `(err, request)` (CalleeHandled).
|
|
236
|
+
* Always return a real request object so middleware never sees `null`.
|
|
237
|
+
*/
|
|
238
|
+
function nativeRequestArg(errOrRequest, maybeRequest) {
|
|
239
|
+
if (maybeRequest != null && typeof maybeRequest === 'object') {
|
|
240
|
+
return maybeRequest
|
|
241
|
+
}
|
|
242
|
+
if (errOrRequest instanceof Error) {
|
|
243
|
+
throw errOrRequest
|
|
244
|
+
}
|
|
245
|
+
if (errOrRequest != null && typeof errOrRequest === 'object') {
|
|
246
|
+
return errOrRequest
|
|
247
|
+
}
|
|
248
|
+
return emptyRequest()
|
|
249
|
+
}
|
|
250
|
+
|
|
209
251
|
function ensureState(request) {
|
|
252
|
+
if (!request || typeof request !== 'object') {
|
|
253
|
+
return {}
|
|
254
|
+
}
|
|
210
255
|
if (!request.state || typeof request.state !== 'object') {
|
|
211
256
|
request.state = {}
|
|
212
257
|
}
|
|
@@ -219,18 +264,14 @@ function isResponse(value) {
|
|
|
219
264
|
|
|
220
265
|
async function runMiddlewareChain(request, middlewares, handler) {
|
|
221
266
|
ensureState(request)
|
|
222
|
-
let index = 0
|
|
223
267
|
|
|
224
268
|
async function dispatch(i, req) {
|
|
225
269
|
if (i >= middlewares.length) {
|
|
226
|
-
return await handler(req)
|
|
270
|
+
return await awaitMaybe(handler(req))
|
|
227
271
|
}
|
|
228
272
|
const middleware = middlewares[i]
|
|
229
273
|
const callNext = (nextReq) => dispatch(i + 1, nextReq)
|
|
230
|
-
|
|
231
|
-
if (result && typeof result.then === 'function') {
|
|
232
|
-
result = await result
|
|
233
|
-
}
|
|
274
|
+
const result = await awaitMaybe(middleware(req, callNext))
|
|
234
275
|
if (isResponse(result)) return result
|
|
235
276
|
return result
|
|
236
277
|
}
|
|
@@ -595,11 +636,12 @@ class FusionApp {
|
|
|
595
636
|
for (const { path: routePath, ApiClass, middleware: routeMiddleware = [] } of registry) {
|
|
596
637
|
for (const methodName of HTTP_METHODS) {
|
|
597
638
|
if (!definesMethod(ApiClass, methodName)) continue
|
|
598
|
-
this.engine.route(methodName.toUpperCase(), routePath,
|
|
639
|
+
this.engine.route(methodName.toUpperCase(), routePath, (errOrRequest, maybeRequest) => {
|
|
640
|
+
const request = nativeRequestArg(errOrRequest, maybeRequest)
|
|
599
641
|
const chain = [...activeGlobalMiddleware, ...routeMiddleware]
|
|
600
642
|
const handler = async (req) => {
|
|
601
643
|
try {
|
|
602
|
-
const instance = new ApiClass(req)
|
|
644
|
+
const instance = new ApiClass(req || emptyRequest())
|
|
603
645
|
const fn = instance[methodName]
|
|
604
646
|
return await Promise.resolve(fn.call(instance))
|
|
605
647
|
} catch (err) {
|
|
@@ -664,12 +706,16 @@ class FusionApp {
|
|
|
664
706
|
}
|
|
665
707
|
}
|
|
666
708
|
|
|
667
|
-
|
|
668
|
-
this.engine.route('GET', prefix, async () => ({
|
|
709
|
+
const uiEnvelope = () => ({
|
|
669
710
|
status: 200,
|
|
670
711
|
body: swaggerUiHtml(swagger, `${prefix}/openapi.json`),
|
|
671
712
|
headers: { 'content-type': 'text/html' },
|
|
672
|
-
})
|
|
713
|
+
})
|
|
714
|
+
this.engine.route('GET', `${prefix}/openapi.json`, () => openapi)
|
|
715
|
+
this.engine.route('GET', prefix, uiEnvelope)
|
|
716
|
+
if (prefix !== '/') {
|
|
717
|
+
this.engine.route('GET', `${prefix}/`, uiEnvelope)
|
|
718
|
+
}
|
|
673
719
|
}
|
|
674
720
|
|
|
675
721
|
this.mounted = true
|