@fluojs/platform-express 1.0.0-beta.4 → 1.0.0-beta.5
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/adapter.d.ts.map +1 -1
- package/dist/adapter.js +41 -94
- package/package.json +3 -3
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/adapter.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { createServer as createHttpServer } from 'node:http';
|
|
2
2
|
import { createServer as createHttpsServer } from 'node:https';
|
|
3
3
|
import { Readable } from 'node:stream';
|
|
4
|
-
import { URL } from 'node:url';
|
|
5
4
|
import express from 'express';
|
|
6
5
|
import { BadRequestException, createServerBackedHttpAdapterRealtimeCapability, createErrorResponse, HttpException, InternalServerErrorException, PayloadTooLargeException } from '@fluojs/http';
|
|
7
6
|
import { attachFrameworkRequestNativeRouteHandoff, bindRawRequestNativeRouteHandoff, consumeRawRequestNativeRouteHandoff, isRoutePathNormalizationSensitive } from '@fluojs/http/internal';
|
|
8
7
|
import { createNodeShutdownSignalRegistration, defaultNodeShutdownSignals } from '@fluojs/runtime/node';
|
|
8
|
+
import { cloneRequestHeaders, createDeferredFrameworkRequestShell, createMemoizedAsyncValue, createRequestSignal, normalizePrimaryContentType, parseQueryParamsFromSearch, resolveAbsoluteRequestUrl, resolveRequestIdFromHeaders, snapshotSimpleQueryRecord, splitRawRequestUrl } from '@fluojs/runtime/internal-node';
|
|
9
9
|
import { parseMultipart } from '@fluojs/runtime/web';
|
|
10
10
|
import { bootstrapHttpAdapterApplication, runHttpAdapterApplication } from '@fluojs/runtime/internal/http-adapter';
|
|
11
11
|
import { dispatchWithRequestResponseFactory } from '@fluojs/runtime/internal/request-response-factory';
|
|
@@ -131,7 +131,7 @@ export class ExpressHttpApplicationAdapter {
|
|
|
131
131
|
return;
|
|
132
132
|
}
|
|
133
133
|
const nativeMethod = request.method.toUpperCase();
|
|
134
|
-
const requestPath =
|
|
134
|
+
const requestPath = splitRawRequestUrl(request.originalUrl || request.url || '/').path;
|
|
135
135
|
const descriptor = route.descriptorsByMethod[nativeMethod];
|
|
136
136
|
const params = normalizeNativeRouteParams(request.params);
|
|
137
137
|
if (descriptor && !isRoutePathNormalizationSensitive(requestPath) && !hasNativeRouteParamSeparators(params)) {
|
|
@@ -228,6 +228,9 @@ function createExpressRequestResponseFactory(multipartOptions, maxBodySize = DEF
|
|
|
228
228
|
createResponse(response) {
|
|
229
229
|
return createFrameworkResponse(response);
|
|
230
230
|
},
|
|
231
|
+
async materializeRequest(request) {
|
|
232
|
+
await materializeFrameworkRequestBody(request);
|
|
233
|
+
},
|
|
231
234
|
resolveRequestId(request) {
|
|
232
235
|
return resolveRequestIdFromHeaders(request.headers);
|
|
233
236
|
},
|
|
@@ -374,43 +377,40 @@ function createFrameworkResponseStream(response) {
|
|
|
374
377
|
}
|
|
375
378
|
async function createFrameworkRequest(request, signal, multipartOptions, maxBodySize = DEFAULT_MAX_BODY_SIZE, preserveRawBody = false) {
|
|
376
379
|
const rawUrl = request.originalUrl || request.url || '/';
|
|
377
|
-
const
|
|
378
|
-
const headers = normalizeHeaders(request.headers);
|
|
379
|
-
const
|
|
380
|
-
const
|
|
381
|
-
|
|
382
|
-
let
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
380
|
+
const urlParts = splitRawRequestUrl(rawUrl);
|
|
381
|
+
const headers = normalizeHeaders(cloneRequestHeaders(request.headers));
|
|
382
|
+
const querySnapshot = snapshotSimpleQueryRecord(request.query);
|
|
383
|
+
const contentType = normalizePrimaryContentType(headers['content-type']);
|
|
384
|
+
const isMultipart = contentType === 'multipart/form-data';
|
|
385
|
+
let frameworkRequest;
|
|
386
|
+
const materializeBody = createMemoizedAsyncValue(async () => {
|
|
387
|
+
if (isMultipart) {
|
|
388
|
+
const parsed = await parseMultipartRequest(request, {
|
|
389
|
+
...multipartOptions,
|
|
390
|
+
maxTotalSize: multipartOptions?.maxTotalSize ?? maxBodySize
|
|
391
|
+
});
|
|
392
|
+
frameworkRequest.body = parsed.fields;
|
|
393
|
+
frameworkRequest.files = parsed.files;
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
392
396
|
const bodyResult = await readRequestBody(request, headers['content-type'], maxBodySize, preserveRawBody);
|
|
393
|
-
body = bodyResult.body;
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
397
|
+
frameworkRequest.body = bodyResult.body;
|
|
398
|
+
if (bodyResult.rawBody) {
|
|
399
|
+
frameworkRequest.rawBody = bodyResult.rawBody;
|
|
400
|
+
}
|
|
401
|
+
});
|
|
402
|
+
frameworkRequest = createDeferredFrameworkRequestShell({
|
|
403
|
+
cookieHeader: headers.cookie,
|
|
399
404
|
headers,
|
|
405
|
+
materializeBody,
|
|
400
406
|
method: request.method,
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
407
|
+
path: urlParts.path,
|
|
408
|
+
query: querySnapshot,
|
|
409
|
+
queryFactory: () => parseQueryParamsFromSearch(urlParts.search),
|
|
404
410
|
raw: request,
|
|
405
411
|
signal,
|
|
406
|
-
url:
|
|
407
|
-
};
|
|
408
|
-
if (files) {
|
|
409
|
-
frameworkRequest.files = files;
|
|
410
|
-
}
|
|
411
|
-
if (rawBody) {
|
|
412
|
-
frameworkRequest.rawBody = rawBody;
|
|
413
|
-
}
|
|
412
|
+
url: urlParts.path + urlParts.search
|
|
413
|
+
});
|
|
414
414
|
const nativeRouteHandoff = consumeRawRequestNativeRouteHandoff(request);
|
|
415
415
|
return nativeRouteHandoff ? attachFrameworkRequestNativeRouteHandoff(frameworkRequest, nativeRouteHandoff) : frameworkRequest;
|
|
416
416
|
}
|
|
@@ -446,7 +446,7 @@ async function parseMultipartRequest(request, options = {}) {
|
|
|
446
446
|
body: Readable.toWeb(request),
|
|
447
447
|
headers: normalizeHeaders(request.headers),
|
|
448
448
|
method: request.method,
|
|
449
|
-
url:
|
|
449
|
+
url: resolveAbsoluteRequestUrl(request.url)
|
|
450
450
|
}, options);
|
|
451
451
|
} catch (error) {
|
|
452
452
|
if (isExpressMultipartTooLargeError(error)) {
|
|
@@ -503,57 +503,6 @@ function normalizeHeaders(headers) {
|
|
|
503
503
|
}
|
|
504
504
|
return normalized;
|
|
505
505
|
}
|
|
506
|
-
function parseQueryParams(searchParams) {
|
|
507
|
-
const query = {};
|
|
508
|
-
for (const [key, value] of searchParams.entries()) {
|
|
509
|
-
const current = query[key];
|
|
510
|
-
if (current === undefined) {
|
|
511
|
-
query[key] = value;
|
|
512
|
-
continue;
|
|
513
|
-
}
|
|
514
|
-
if (Array.isArray(current)) {
|
|
515
|
-
current.push(value);
|
|
516
|
-
continue;
|
|
517
|
-
}
|
|
518
|
-
query[key] = [current, value];
|
|
519
|
-
}
|
|
520
|
-
return query;
|
|
521
|
-
}
|
|
522
|
-
function parseCookieHeader(cookieHeader) {
|
|
523
|
-
if (!cookieHeader) {
|
|
524
|
-
return {};
|
|
525
|
-
}
|
|
526
|
-
return Object.fromEntries(cookieHeader.split(';').map(pair => pair.trim()).filter(Boolean).map(pair => {
|
|
527
|
-
const index = pair.indexOf('=');
|
|
528
|
-
if (index === -1) {
|
|
529
|
-
return [pair.trim(), ''];
|
|
530
|
-
}
|
|
531
|
-
const rawValue = pair.slice(index + 1).trim();
|
|
532
|
-
try {
|
|
533
|
-
return [pair.slice(0, index).trim(), decodeURIComponent(rawValue)];
|
|
534
|
-
} catch {
|
|
535
|
-
return [pair.slice(0, index).trim(), rawValue];
|
|
536
|
-
}
|
|
537
|
-
}));
|
|
538
|
-
}
|
|
539
|
-
function createRequestSignal(response) {
|
|
540
|
-
const controller = new AbortController();
|
|
541
|
-
const abort = reason => {
|
|
542
|
-
if (!controller.signal.aborted) {
|
|
543
|
-
controller.abort(new Error(reason));
|
|
544
|
-
}
|
|
545
|
-
};
|
|
546
|
-
response.once('close', () => {
|
|
547
|
-
if (!response.writableEnded) {
|
|
548
|
-
abort('Response closed before response commit.');
|
|
549
|
-
}
|
|
550
|
-
});
|
|
551
|
-
return controller.signal;
|
|
552
|
-
}
|
|
553
|
-
function resolveRequestIdFromHeaders(headers) {
|
|
554
|
-
const requestId = headers['x-request-id'] ?? headers['x-correlation-id'];
|
|
555
|
-
return Array.isArray(requestId) ? requestId[0] : requestId;
|
|
556
|
-
}
|
|
557
506
|
function createExpressServer(httpsOptions, app) {
|
|
558
507
|
return httpsOptions ? createHttpsServer(httpsOptions, app) : createHttpServer(app);
|
|
559
508
|
}
|
|
@@ -724,8 +673,8 @@ async function readRequestBody(request, contentType, maxBodySize = DEFAULT_MAX_B
|
|
|
724
673
|
rawBody: preserveRawBody ? rawBody : undefined
|
|
725
674
|
};
|
|
726
675
|
}
|
|
727
|
-
const primaryContentType =
|
|
728
|
-
if (
|
|
676
|
+
const primaryContentType = normalizePrimaryContentType(contentType);
|
|
677
|
+
if (primaryContentType === 'application/json') {
|
|
729
678
|
try {
|
|
730
679
|
return {
|
|
731
680
|
body: JSON.parse(bodyText),
|
|
@@ -735,7 +684,7 @@ async function readRequestBody(request, contentType, maxBodySize = DEFAULT_MAX_B
|
|
|
735
684
|
throw new BadRequestException('Request body contains invalid JSON.');
|
|
736
685
|
}
|
|
737
686
|
}
|
|
738
|
-
if (
|
|
687
|
+
if (primaryContentType === 'application/x-www-form-urlencoded') {
|
|
739
688
|
return {
|
|
740
689
|
body: parseUrlEncodedBody(bodyText),
|
|
741
690
|
rawBody: preserveRawBody ? rawBody : undefined
|
|
@@ -754,11 +703,9 @@ function parseUrlEncodedBody(bodyText) {
|
|
|
754
703
|
}
|
|
755
704
|
return fields;
|
|
756
705
|
}
|
|
757
|
-
function
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
}
|
|
761
|
-
return headerValue;
|
|
706
|
+
async function materializeFrameworkRequestBody(request) {
|
|
707
|
+
await request.materializeBody?.();
|
|
708
|
+
delete request.materializeBody;
|
|
762
709
|
}
|
|
763
710
|
function setMultiValue(target, key, value) {
|
|
764
711
|
const existing = target[key];
|
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"platform",
|
|
9
9
|
"server"
|
|
10
10
|
],
|
|
11
|
-
"version": "1.0.0-beta.
|
|
11
|
+
"version": "1.0.0-beta.5",
|
|
12
12
|
"private": false,
|
|
13
13
|
"license": "MIT",
|
|
14
14
|
"repository": {
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
38
|
"express": "^5.1.0",
|
|
39
|
-
"@fluojs/http": "^1.0.0-beta.
|
|
40
|
-
"@fluojs/runtime": "^1.0.0-beta.
|
|
39
|
+
"@fluojs/http": "^1.0.0-beta.5",
|
|
40
|
+
"@fluojs/runtime": "^1.0.0-beta.7"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/express": "^5.0.3",
|