@fluojs/runtime 1.0.0-beta.6 → 1.0.0-beta.7
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/node/internal-node-request.d.ts +106 -0
- package/dist/node/internal-node-request.d.ts.map +1 -1
- package/dist/node/internal-node-request.js +195 -21
- package/dist/node/internal-node.d.ts +2 -1
- package/dist/node/internal-node.d.ts.map +1 -1
- package/dist/node/internal-node.js +2 -2
- package/dist/web.d.ts.map +1 -1
- package/dist/web.js +50 -22
- package/package.json +2 -2
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import type { IncomingHttpHeaders, IncomingMessage, ServerResponse } from 'node:http';
|
|
2
2
|
import { PayloadTooLargeException, type FrameworkRequest } from '@fluojs/http';
|
|
3
3
|
import { type MultipartOptions } from '../multipart.js';
|
|
4
|
+
type MemoizedValue<T> = () => T;
|
|
5
|
+
type QueryRecord = Record<string, string | string[] | undefined>;
|
|
6
|
+
/**
|
|
7
|
+
* Options for creating a deferred framework request shell from a Node-backed adapter.
|
|
8
|
+
*/
|
|
9
|
+
export interface DeferredFrameworkRequestShellOptions<RawRequest> {
|
|
10
|
+
cookieHeader?: string | string[] | undefined;
|
|
11
|
+
headers?: FrameworkRequest['headers'];
|
|
12
|
+
headersFactory?: () => FrameworkRequest['headers'];
|
|
13
|
+
materializeBody?: () => Promise<void>;
|
|
14
|
+
method?: string;
|
|
15
|
+
path: string;
|
|
16
|
+
query?: QueryRecord;
|
|
17
|
+
queryFactory?: () => QueryRecord;
|
|
18
|
+
raw: RawRequest;
|
|
19
|
+
signal: AbortSignal;
|
|
20
|
+
url: string;
|
|
21
|
+
}
|
|
4
22
|
/**
|
|
5
23
|
* HTTP payload-size error that closes the underlying Node request stream after the response commits.
|
|
6
24
|
*/
|
|
@@ -31,6 +49,13 @@ export declare function createFrameworkRequest(request: IncomingMessage, signal:
|
|
|
31
49
|
* @returns The framework request shell with metadata snapshotted and body materialization deferred.
|
|
32
50
|
*/
|
|
33
51
|
export declare function createDeferredFrameworkRequest(request: IncomingMessage, signal: AbortSignal, multipartOptions?: MultipartOptions, maxBodySize?: number, preserveRawBody?: boolean): FrameworkRequest;
|
|
52
|
+
/**
|
|
53
|
+
* Creates a framework request shell from already-snapshotted Node adapter metadata.
|
|
54
|
+
*
|
|
55
|
+
* @param options - Raw request, metadata factories, and deferred body materialization hooks.
|
|
56
|
+
* @returns A framework request with lazy headers, cookies, query values, and optional body materialization.
|
|
57
|
+
*/
|
|
58
|
+
export declare function createDeferredFrameworkRequestShell<RawRequest>({ cookieHeader, headers, headersFactory, materializeBody, method, path, query, queryFactory, raw, signal, url, }: DeferredFrameworkRequestShellOptions<RawRequest>): FrameworkRequest;
|
|
34
59
|
/**
|
|
35
60
|
* Materializes a deferred Node framework request body exactly once.
|
|
36
61
|
*
|
|
@@ -38,6 +63,20 @@ export declare function createDeferredFrameworkRequest(request: IncomingMessage,
|
|
|
38
63
|
* @returns A promise that settles after body, rawBody, and files fields are populated when applicable.
|
|
39
64
|
*/
|
|
40
65
|
export declare function materializeFrameworkRequestBody(request: FrameworkRequest): Promise<void>;
|
|
66
|
+
/**
|
|
67
|
+
* Creates a synchronous memoized value resolver.
|
|
68
|
+
*
|
|
69
|
+
* @param factory - Function that computes the value on first access.
|
|
70
|
+
* @returns A stable resolver that returns the cached value after the first call.
|
|
71
|
+
*/
|
|
72
|
+
export declare function createMemoizedValue<T>(factory: () => T): MemoizedValue<T>;
|
|
73
|
+
/**
|
|
74
|
+
* Creates an async memoized side-effect resolver.
|
|
75
|
+
*
|
|
76
|
+
* @param factory - Async function to run at most once.
|
|
77
|
+
* @returns A resolver that returns the same in-flight or completed promise for every call.
|
|
78
|
+
*/
|
|
79
|
+
export declare function createMemoizedAsyncValue(factory: () => Promise<void>): () => Promise<void>;
|
|
41
80
|
/**
|
|
42
81
|
* Creates an abort signal that fires when the Node response closes unexpectedly.
|
|
43
82
|
*
|
|
@@ -52,4 +91,71 @@ export declare function createRequestSignal(response: ServerResponse): AbortSign
|
|
|
52
91
|
* @returns The request identifier when present.
|
|
53
92
|
*/
|
|
54
93
|
export declare function resolveRequestIdFromHeaders(headers: IncomingHttpHeaders): string | undefined;
|
|
94
|
+
/**
|
|
95
|
+
* Parses a raw URL search string into the framework query shape.
|
|
96
|
+
*
|
|
97
|
+
* @param search - Raw search string, with or without a leading question mark.
|
|
98
|
+
* @returns Query values where repeated keys become string arrays.
|
|
99
|
+
*/
|
|
100
|
+
export declare function parseQueryParamsFromSearch(search: string): Record<string, string | string[]>;
|
|
101
|
+
/**
|
|
102
|
+
* Snapshots host-parsed query values when they already match framework semantics.
|
|
103
|
+
*
|
|
104
|
+
* @param query - Host query object exposed by a Node-backed adapter.
|
|
105
|
+
* @returns A cloned query record when all values are strings or string arrays; otherwise `undefined` for raw URL fallback.
|
|
106
|
+
*/
|
|
107
|
+
export declare function snapshotSimpleQueryRecord(query: unknown): QueryRecord | undefined;
|
|
108
|
+
/**
|
|
109
|
+
* Clones Node request headers into the framework header record shape.
|
|
110
|
+
*
|
|
111
|
+
* @param headers - Raw Node incoming headers.
|
|
112
|
+
* @returns A shallow header snapshot with array values cloned.
|
|
113
|
+
*/
|
|
114
|
+
export declare function cloneRequestHeaders(headers: IncomingHttpHeaders): FrameworkRequest['headers'];
|
|
115
|
+
/**
|
|
116
|
+
* Clones a single Node header value when it is array-backed.
|
|
117
|
+
*
|
|
118
|
+
* @param value - Header value to snapshot.
|
|
119
|
+
* @returns The original scalar value or a cloned array value.
|
|
120
|
+
*/
|
|
121
|
+
export declare function cloneHeaderValue<T extends string | string[] | undefined>(value: T): T;
|
|
122
|
+
/**
|
|
123
|
+
* Reads the primary value from a Node header value.
|
|
124
|
+
*
|
|
125
|
+
* @param headerValue - Header value that may contain multiple entries.
|
|
126
|
+
* @returns The first header value when present.
|
|
127
|
+
*/
|
|
128
|
+
export declare function readPrimaryHeaderValue(headerValue: string | string[] | undefined): string | undefined;
|
|
129
|
+
/**
|
|
130
|
+
* Normalizes a Node content-type header to its primary media type.
|
|
131
|
+
*
|
|
132
|
+
* @param headerValue - Raw content-type header value.
|
|
133
|
+
* @returns Lowercase primary media type without parameters, or `undefined` when absent.
|
|
134
|
+
*/
|
|
135
|
+
export declare function normalizePrimaryContentType(headerValue: string | string[] | undefined): string | undefined;
|
|
136
|
+
/**
|
|
137
|
+
* Parses a Node cookie header into framework cookie values.
|
|
138
|
+
*
|
|
139
|
+
* @param cookieHeader - Raw cookie header value or values.
|
|
140
|
+
* @returns Cookie name/value pairs with percent-decoded values when possible.
|
|
141
|
+
*/
|
|
142
|
+
export declare function parseCookieHeader(cookieHeader: string | string[] | undefined): Record<string, string>;
|
|
143
|
+
/**
|
|
144
|
+
* Splits a raw Node request URL into path and search components.
|
|
145
|
+
*
|
|
146
|
+
* @param rawUrl - Raw request URL, absolute URL, or undefined value from Node.
|
|
147
|
+
* @returns The pathname and search string used by framework request matching and query parsing.
|
|
148
|
+
*/
|
|
149
|
+
export declare function splitRawRequestUrl(rawUrl: string | undefined): {
|
|
150
|
+
path: string;
|
|
151
|
+
search: string;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Resolves a raw Node request URL into an absolute URL string.
|
|
155
|
+
*
|
|
156
|
+
* @param rawUrl - Raw request URL, absolute URL, or undefined value from Node.
|
|
157
|
+
* @returns An absolute URL suitable for Web-standard parsers.
|
|
158
|
+
*/
|
|
159
|
+
export declare function resolveAbsoluteRequestUrl(rawUrl: string | undefined): string;
|
|
160
|
+
export {};
|
|
55
161
|
//# sourceMappingURL=internal-node-request.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal-node-request.d.ts","sourceRoot":"","sources":["../../src/node/internal-node-request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,mBAAmB,EACnB,eAAe,EACf,cAAc,EACf,MAAM,WAAW,CAAC;AAInB,OAAO,EAEL,wBAAwB,EACxB,KAAK,gBAAgB,EACtB,MAAM,cAAc,CAAC;AAEtB,OAAO,EAEL,KAAK,gBAAgB,EAEtB,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"internal-node-request.d.ts","sourceRoot":"","sources":["../../src/node/internal-node-request.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,6 +2,11 @@ import { Readable } from 'node:stream';
|
|
|
2
2
|
import { URL } from 'node:url';
|
|
3
3
|
import { BadRequestException, PayloadTooLargeException } from '@fluojs/http';
|
|
4
4
|
import { parseMultipart } from '../multipart.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Options for creating a deferred framework request shell from a Node-backed adapter.
|
|
8
|
+
*/
|
|
9
|
+
|
|
5
10
|
/**
|
|
6
11
|
* HTTP payload-size error that closes the underlying Node request stream after the response commits.
|
|
7
12
|
*/
|
|
@@ -50,21 +55,19 @@ export async function createFrameworkRequest(request, signal, multipartOptions,
|
|
|
50
55
|
* @returns The framework request shell with metadata snapshotted and body materialization deferred.
|
|
51
56
|
*/
|
|
52
57
|
export function createDeferredFrameworkRequest(request, signal, multipartOptions, maxBodySize = 1 * 1024 * 1024, preserveRawBody = false) {
|
|
53
|
-
const
|
|
58
|
+
const rawUrl = request.url ?? '/';
|
|
59
|
+
const urlParts = splitRawRequestUrl(rawUrl);
|
|
54
60
|
const headers = cloneRequestHeaders(request.headers);
|
|
55
|
-
const cookieHeader = cloneHeaderValue(headers.cookie);
|
|
56
|
-
const searchParams = new URLSearchParams(url.searchParams);
|
|
57
|
-
const cookies = createMemoizedValue(() => parseCookieHeader(cookieHeader));
|
|
58
|
-
const query = createMemoizedValue(() => parseQueryParams(searchParams));
|
|
59
61
|
const contentType = normalizePrimaryContentType(headers['content-type']);
|
|
60
62
|
const isMultipart = contentType === 'multipart/form-data';
|
|
63
|
+
let frameworkRequest;
|
|
61
64
|
const materializeBody = createMemoizedAsyncValue(async () => {
|
|
62
65
|
if (isMultipart) {
|
|
63
66
|
const result = await parseMultipart({
|
|
64
67
|
body: Readable.toWeb(request),
|
|
65
68
|
headers,
|
|
66
69
|
method: request.method,
|
|
67
|
-
url:
|
|
70
|
+
url: resolveAbsoluteRequestUrl(rawUrl)
|
|
68
71
|
}, {
|
|
69
72
|
...multipartOptions,
|
|
70
73
|
maxTotalSize: multipartOptions?.maxTotalSize ?? maxBodySize
|
|
@@ -83,22 +86,62 @@ export function createDeferredFrameworkRequest(request, signal, multipartOptions
|
|
|
83
86
|
frameworkRequest.rawBody = bodyResult.rawBody;
|
|
84
87
|
}
|
|
85
88
|
});
|
|
89
|
+
frameworkRequest = createDeferredFrameworkRequestShell({
|
|
90
|
+
cookieHeader: cloneHeaderValue(headers.cookie),
|
|
91
|
+
headers,
|
|
92
|
+
materializeBody,
|
|
93
|
+
method: request.method,
|
|
94
|
+
path: urlParts.path,
|
|
95
|
+
queryFactory: () => parseQueryParamsFromSearch(urlParts.search),
|
|
96
|
+
raw: request,
|
|
97
|
+
signal,
|
|
98
|
+
url: urlParts.path + urlParts.search
|
|
99
|
+
});
|
|
100
|
+
return frameworkRequest;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Creates a framework request shell from already-snapshotted Node adapter metadata.
|
|
105
|
+
*
|
|
106
|
+
* @param options - Raw request, metadata factories, and deferred body materialization hooks.
|
|
107
|
+
* @returns A framework request with lazy headers, cookies, query values, and optional body materialization.
|
|
108
|
+
*/
|
|
109
|
+
export function createDeferredFrameworkRequestShell({
|
|
110
|
+
cookieHeader,
|
|
111
|
+
headers,
|
|
112
|
+
headersFactory,
|
|
113
|
+
materializeBody,
|
|
114
|
+
method,
|
|
115
|
+
path,
|
|
116
|
+
query,
|
|
117
|
+
queryFactory,
|
|
118
|
+
raw,
|
|
119
|
+
signal,
|
|
120
|
+
url
|
|
121
|
+
}) {
|
|
122
|
+
const resolveHeaders = headersFactory ? createMemoizedValue(headersFactory) : () => headers ?? {};
|
|
123
|
+
const resolveCookies = createMemoizedValue(() => parseCookieHeader(cookieHeader ?? resolveHeaders().cookie));
|
|
124
|
+
const resolveQuery = createMemoizedValue(() => query ?? queryFactory?.() ?? {});
|
|
86
125
|
const frameworkRequest = {
|
|
87
126
|
get cookies() {
|
|
88
|
-
return
|
|
127
|
+
return resolveCookies();
|
|
89
128
|
},
|
|
90
|
-
headers
|
|
91
|
-
|
|
129
|
+
get headers() {
|
|
130
|
+
return resolveHeaders();
|
|
131
|
+
},
|
|
132
|
+
method: method ?? 'GET',
|
|
92
133
|
params: {},
|
|
93
|
-
path
|
|
134
|
+
path,
|
|
94
135
|
get query() {
|
|
95
|
-
return
|
|
136
|
+
return resolveQuery();
|
|
96
137
|
},
|
|
97
|
-
raw
|
|
138
|
+
raw,
|
|
98
139
|
signal,
|
|
99
|
-
url
|
|
100
|
-
materializeBody
|
|
140
|
+
url
|
|
101
141
|
};
|
|
142
|
+
if (materializeBody) {
|
|
143
|
+
frameworkRequest.materializeBody = materializeBody;
|
|
144
|
+
}
|
|
102
145
|
return frameworkRequest;
|
|
103
146
|
}
|
|
104
147
|
function hasNodeRequestBody(request) {
|
|
@@ -125,7 +168,14 @@ export async function materializeFrameworkRequestBody(request) {
|
|
|
125
168
|
await request.materializeBody?.();
|
|
126
169
|
delete request.materializeBody;
|
|
127
170
|
}
|
|
128
|
-
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Creates a synchronous memoized value resolver.
|
|
174
|
+
*
|
|
175
|
+
* @param factory - Function that computes the value on first access.
|
|
176
|
+
* @returns A stable resolver that returns the cached value after the first call.
|
|
177
|
+
*/
|
|
178
|
+
export function createMemoizedValue(factory) {
|
|
129
179
|
let initialized = false;
|
|
130
180
|
let value;
|
|
131
181
|
return () => {
|
|
@@ -136,7 +186,14 @@ function createMemoizedValue(factory) {
|
|
|
136
186
|
return value;
|
|
137
187
|
};
|
|
138
188
|
}
|
|
139
|
-
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Creates an async memoized side-effect resolver.
|
|
192
|
+
*
|
|
193
|
+
* @param factory - Async function to run at most once.
|
|
194
|
+
* @returns A resolver that returns the same in-flight or completed promise for every call.
|
|
195
|
+
*/
|
|
196
|
+
export function createMemoizedAsyncValue(factory) {
|
|
140
197
|
let promise;
|
|
141
198
|
return () => {
|
|
142
199
|
promise ??= factory();
|
|
@@ -175,6 +232,16 @@ export function resolveRequestIdFromHeaders(headers) {
|
|
|
175
232
|
const requestId = headers['x-request-id'] ?? headers['x-correlation-id'];
|
|
176
233
|
return Array.isArray(requestId) ? requestId[0] : requestId;
|
|
177
234
|
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Parses a raw URL search string into the framework query shape.
|
|
238
|
+
*
|
|
239
|
+
* @param search - Raw search string, with or without a leading question mark.
|
|
240
|
+
* @returns Query values where repeated keys become string arrays.
|
|
241
|
+
*/
|
|
242
|
+
export function parseQueryParamsFromSearch(search) {
|
|
243
|
+
return parseQueryParams(new URLSearchParams(search));
|
|
244
|
+
}
|
|
178
245
|
function parseQueryParams(searchParams) {
|
|
179
246
|
const query = {};
|
|
180
247
|
for (const [key, value] of searchParams.entries()) {
|
|
@@ -191,20 +258,73 @@ function parseQueryParams(searchParams) {
|
|
|
191
258
|
}
|
|
192
259
|
return query;
|
|
193
260
|
}
|
|
194
|
-
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Snapshots host-parsed query values when they already match framework semantics.
|
|
264
|
+
*
|
|
265
|
+
* @param query - Host query object exposed by a Node-backed adapter.
|
|
266
|
+
* @returns A cloned query record when all values are strings or string arrays; otherwise `undefined` for raw URL fallback.
|
|
267
|
+
*/
|
|
268
|
+
export function snapshotSimpleQueryRecord(query) {
|
|
269
|
+
if (typeof query !== 'object' || query === null) {
|
|
270
|
+
return undefined;
|
|
271
|
+
}
|
|
272
|
+
const snapshot = {};
|
|
273
|
+
for (const [key, value] of Object.entries(query)) {
|
|
274
|
+
if (typeof value === 'string') {
|
|
275
|
+
snapshot[key] = value;
|
|
276
|
+
continue;
|
|
277
|
+
}
|
|
278
|
+
if (Array.isArray(value) && value.every(item => typeof item === 'string')) {
|
|
279
|
+
snapshot[key] = [...value];
|
|
280
|
+
continue;
|
|
281
|
+
}
|
|
282
|
+
return undefined;
|
|
283
|
+
}
|
|
284
|
+
return snapshot;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/**
|
|
288
|
+
* Clones Node request headers into the framework header record shape.
|
|
289
|
+
*
|
|
290
|
+
* @param headers - Raw Node incoming headers.
|
|
291
|
+
* @returns A shallow header snapshot with array values cloned.
|
|
292
|
+
*/
|
|
293
|
+
export function cloneRequestHeaders(headers) {
|
|
195
294
|
const clonedEntries = Object.entries(headers).map(([name, value]) => [name, cloneHeaderValue(value)]);
|
|
196
295
|
return Object.fromEntries(clonedEntries);
|
|
197
296
|
}
|
|
198
|
-
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Clones a single Node header value when it is array-backed.
|
|
300
|
+
*
|
|
301
|
+
* @param value - Header value to snapshot.
|
|
302
|
+
* @returns The original scalar value or a cloned array value.
|
|
303
|
+
*/
|
|
304
|
+
export function cloneHeaderValue(value) {
|
|
199
305
|
return Array.isArray(value) ? [...value] : value;
|
|
200
306
|
}
|
|
201
|
-
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Reads the primary value from a Node header value.
|
|
310
|
+
*
|
|
311
|
+
* @param headerValue - Header value that may contain multiple entries.
|
|
312
|
+
* @returns The first header value when present.
|
|
313
|
+
*/
|
|
314
|
+
export function readPrimaryHeaderValue(headerValue) {
|
|
202
315
|
if (Array.isArray(headerValue)) {
|
|
203
316
|
return headerValue[0];
|
|
204
317
|
}
|
|
205
318
|
return headerValue;
|
|
206
319
|
}
|
|
207
|
-
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Normalizes a Node content-type header to its primary media type.
|
|
323
|
+
*
|
|
324
|
+
* @param headerValue - Raw content-type header value.
|
|
325
|
+
* @returns Lowercase primary media type without parameters, or `undefined` when absent.
|
|
326
|
+
*/
|
|
327
|
+
export function normalizePrimaryContentType(headerValue) {
|
|
208
328
|
const primaryHeaderValue = readPrimaryHeaderValue(headerValue);
|
|
209
329
|
if (typeof primaryHeaderValue !== 'string') {
|
|
210
330
|
return undefined;
|
|
@@ -220,7 +340,14 @@ function decodeCookieValue(raw) {
|
|
|
220
340
|
return raw;
|
|
221
341
|
}
|
|
222
342
|
}
|
|
223
|
-
|
|
343
|
+
|
|
344
|
+
/**
|
|
345
|
+
* Parses a Node cookie header into framework cookie values.
|
|
346
|
+
*
|
|
347
|
+
* @param cookieHeader - Raw cookie header value or values.
|
|
348
|
+
* @returns Cookie name/value pairs with percent-decoded values when possible.
|
|
349
|
+
*/
|
|
350
|
+
export function parseCookieHeader(cookieHeader) {
|
|
224
351
|
const normalizedCookieHeader = Array.isArray(cookieHeader) ? cookieHeader.join('; ') : cookieHeader;
|
|
225
352
|
if (!normalizedCookieHeader) {
|
|
226
353
|
return {};
|
|
@@ -272,4 +399,51 @@ async function readRequestBody(request, contentType, maxBodySize = 1 * 1024 * 10
|
|
|
272
399
|
body: bodyText,
|
|
273
400
|
rawBody: preserveRawBody ? rawBody : undefined
|
|
274
401
|
};
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
/**
|
|
405
|
+
* Splits a raw Node request URL into path and search components.
|
|
406
|
+
*
|
|
407
|
+
* @param rawUrl - Raw request URL, absolute URL, or undefined value from Node.
|
|
408
|
+
* @returns The pathname and search string used by framework request matching and query parsing.
|
|
409
|
+
*/
|
|
410
|
+
export function splitRawRequestUrl(rawUrl) {
|
|
411
|
+
const resolvedRawUrl = rawUrl ?? '/';
|
|
412
|
+
if (resolvedRawUrl.startsWith('http://') || resolvedRawUrl.startsWith('https://')) {
|
|
413
|
+
const url = new URL(resolvedRawUrl);
|
|
414
|
+
return {
|
|
415
|
+
path: url.pathname,
|
|
416
|
+
search: url.search
|
|
417
|
+
};
|
|
418
|
+
}
|
|
419
|
+
const queryStart = resolvedRawUrl.indexOf('?');
|
|
420
|
+
const hashStart = resolvedRawUrl.indexOf('#');
|
|
421
|
+
const pathEndCandidates = [queryStart, hashStart].filter(index => index >= 0);
|
|
422
|
+
const pathEnd = pathEndCandidates.length > 0 ? Math.min(...pathEndCandidates) : resolvedRawUrl.length;
|
|
423
|
+
const path = resolvedRawUrl.slice(0, pathEnd) || '/';
|
|
424
|
+
if (queryStart === -1) {
|
|
425
|
+
return {
|
|
426
|
+
path,
|
|
427
|
+
search: ''
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
const searchEnd = hashStart >= 0 && hashStart > queryStart ? hashStart : resolvedRawUrl.length;
|
|
431
|
+
return {
|
|
432
|
+
path,
|
|
433
|
+
search: resolvedRawUrl.slice(queryStart, searchEnd)
|
|
434
|
+
};
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/**
|
|
438
|
+
* Resolves a raw Node request URL into an absolute URL string.
|
|
439
|
+
*
|
|
440
|
+
* @param rawUrl - Raw request URL, absolute URL, or undefined value from Node.
|
|
441
|
+
* @returns An absolute URL suitable for Web-standard parsers.
|
|
442
|
+
*/
|
|
443
|
+
export function resolveAbsoluteRequestUrl(rawUrl) {
|
|
444
|
+
const resolvedRawUrl = rawUrl ?? '/';
|
|
445
|
+
if (resolvedRawUrl.startsWith('http://') || resolvedRawUrl.startsWith('https://')) {
|
|
446
|
+
return resolvedRawUrl;
|
|
447
|
+
}
|
|
448
|
+
return new URL(resolvedRawUrl, 'http://localhost').toString();
|
|
275
449
|
}
|
|
@@ -2,6 +2,7 @@ import { createServer as createHttpServer } from 'node:http';
|
|
|
2
2
|
import { createServer as createHttpsServer, type ServerOptions as HttpsServerOptions } from 'node:https';
|
|
3
3
|
import { type CorsOptions, type Dispatcher, type HttpApplicationAdapter, type MiddlewareLike, type SecurityHeadersOptions } from '@fluojs/http';
|
|
4
4
|
import { createNodeResponseCompression, compressNodeResponse } from './internal-node-compression.js';
|
|
5
|
+
import { cloneHeaderValue, cloneRequestHeaders, createDeferredFrameworkRequestShell, createMemoizedAsyncValue, createMemoizedValue, normalizePrimaryContentType, parseCookieHeader, parseQueryParamsFromSearch, createRequestSignal, readPrimaryHeaderValue, resolveAbsoluteRequestUrl, resolveRequestIdFromHeaders, snapshotSimpleQueryRecord, splitRawRequestUrl } from './internal-node-request.js';
|
|
5
6
|
import { createNodeShutdownSignalRegistration, defaultNodeShutdownSignals, registerShutdownSignals } from './internal-node-shutdown.js';
|
|
6
7
|
import type { MultipartOptions, UploadedFile } from '../multipart.js';
|
|
7
8
|
import type { Application, ApplicationLogger, CreateApplicationOptions, ModuleType } from '../types.js';
|
|
@@ -112,5 +113,5 @@ export declare function bootstrapNodeApplication(rootModule: ModuleType, options
|
|
|
112
113
|
* @returns The run node application result.
|
|
113
114
|
*/
|
|
114
115
|
export declare function runNodeApplication(rootModule: ModuleType, options: RunNodeApplicationOptions): Promise<Application>;
|
|
115
|
-
export { compressNodeResponse, createNodeResponseCompression, createNodeShutdownSignalRegistration, defaultNodeShutdownSignals, registerShutdownSignals, };
|
|
116
|
+
export { cloneHeaderValue, cloneRequestHeaders, compressNodeResponse, createDeferredFrameworkRequestShell, createMemoizedAsyncValue, createMemoizedValue, createRequestSignal, createNodeResponseCompression, createNodeShutdownSignalRegistration, defaultNodeShutdownSignals, normalizePrimaryContentType, parseCookieHeader, parseQueryParamsFromSearch, readPrimaryHeaderValue, registerShutdownSignals, resolveAbsoluteRequestUrl, resolveRequestIdFromHeaders, snapshotSimpleQueryRecord, splitRawRequestUrl, };
|
|
116
117
|
//# sourceMappingURL=internal-node.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"internal-node.d.ts","sourceRoot":"","sources":["../../src/node/internal-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,gBAAgB,EAA6C,MAAM,WAAW,CAAC;AACxG,OAAO,EAAE,YAAY,IAAI,iBAAiB,EAAE,KAAK,aAAa,IAAI,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAGzG,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,sBAAsB,EAC5B,MAAM,cAAc,CAAC;AAMtB,OAAO,EACL,6BAA6B,EAC7B,oBAAoB,EACrB,MAAM,gCAAgC,CAAC;
|
|
1
|
+
{"version":3,"file":"internal-node.d.ts","sourceRoot":"","sources":["../../src/node/internal-node.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,7 +3,7 @@ import { createServer as createHttpsServer } from 'node:https';
|
|
|
3
3
|
import { createServerBackedHttpAdapterRealtimeCapability } from '@fluojs/http';
|
|
4
4
|
import { bootstrapHttpAdapterApplication, runHttpAdapterApplication } from '../http-adapter-shared.js';
|
|
5
5
|
import { createNodeResponseCompression, compressNodeResponse } from './internal-node-compression.js';
|
|
6
|
-
import { createDeferredFrameworkRequest, NodeRequestPayloadTooLargeException, createRequestSignal, materializeFrameworkRequestBody, resolveRequestIdFromHeaders } from './internal-node-request.js';
|
|
6
|
+
import { cloneHeaderValue, cloneRequestHeaders, createDeferredFrameworkRequestShell, createDeferredFrameworkRequest, createMemoizedAsyncValue, createMemoizedValue, NodeRequestPayloadTooLargeException, normalizePrimaryContentType, parseCookieHeader, parseQueryParamsFromSearch, createRequestSignal, materializeFrameworkRequestBody, readPrimaryHeaderValue, resolveAbsoluteRequestUrl, resolveRequestIdFromHeaders, snapshotSimpleQueryRecord, splitRawRequestUrl } from './internal-node-request.js';
|
|
7
7
|
import { createFrameworkResponse, writeNodeAdapterErrorResponse } from './internal-node-response.js';
|
|
8
8
|
import { createNodeShutdownSignalRegistration, defaultNodeShutdownSignals, registerShutdownSignals } from './internal-node-shutdown.js';
|
|
9
9
|
import { dispatchWithRequestResponseFactory } from '../adapters/request-response-factory.js';
|
|
@@ -156,7 +156,7 @@ export async function runNodeApplication(rootModule, options) {
|
|
|
156
156
|
shutdownRegistration: createNodeShutdownSignalRegistration(options.shutdownSignals ?? defaultNodeShutdownSignals())
|
|
157
157
|
}, adapter);
|
|
158
158
|
}
|
|
159
|
-
export { compressNodeResponse, createNodeResponseCompression, createNodeShutdownSignalRegistration, defaultNodeShutdownSignals, registerShutdownSignals };
|
|
159
|
+
export { cloneHeaderValue, cloneRequestHeaders, compressNodeResponse, createDeferredFrameworkRequestShell, createMemoizedAsyncValue, createMemoizedValue, createRequestSignal, createNodeResponseCompression, createNodeShutdownSignalRegistration, defaultNodeShutdownSignals, normalizePrimaryContentType, parseCookieHeader, parseQueryParamsFromSearch, readPrimaryHeaderValue, registerShutdownSignals, resolveAbsoluteRequestUrl, resolveRequestIdFromHeaders, snapshotSimpleQueryRecord, splitRawRequestUrl };
|
|
160
160
|
function createNodeServer(httpsOptions, handler) {
|
|
161
161
|
return httpsOptions ? createHttpsServer(httpsOptions, handler) : createHttpServer(handler);
|
|
162
162
|
}
|
package/dist/web.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAMtB,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,wCAAwC,CAAC;AAEhD,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,gBAAgB;QACxB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,EAAE,UAAU,CAAC;KACtB;CACF;AAOD;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,sCAAsC;IACvF,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACzF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D,UAAU,IAAI,QAAQ,CAAC;CACxB;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"web.d.ts","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,cAAc,CAAC;AAMtB,OAAO,EAEL,KAAK,gBAAgB,EACrB,KAAK,YAAY,EAClB,MAAM,gBAAgB,CAAC;AACxB,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,wCAAwC,CAAC;AAEhD,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,gBAAgB;QACxB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,EAAE,UAAU,CAAC;KACtB;CACF;AAOD;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,yBAA0B,SAAQ,sCAAsC;IACvF,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC;;;;OAIG;IACH,OAAO,CAAC,EAAE,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,oBAAoB,CAAC,CAAC;IACzF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAqB,SAAQ,iBAAiB;IAC7D,UAAU,IAAI,QAAQ,CAAC;CACxB;AAED,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAgNhD;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,sCAA2C,GACnD,sBAAsB,CAAC,OAAO,EAAE,WAAW,GAAG,SAAS,EAAE,oBAAoB,CAAC,CA6BhF;AAED;;;;;GAKG;AACH,wBAAsB,kBAAkB,CAAC,EACvC,UAAU,EACV,yBAAiG,EACjG,OAAO,EACP,OAAO,EACP,GAAG,OAAO,EACX,EAAE,yBAAyB,GAAG,OAAO,CAAC,QAAQ,CAAC,CAU/C;AAED;;;;;;;;;GASG;AACH,wBAAsB,yBAAyB,CAC7C,OAAO,EAAE,OAAO,EAChB,MAAM,EAAE,WAAW,EACnB,gBAAgB,CAAC,EAAE,gBAAgB,EACnC,WAAW,SAAwB,EACnC,eAAe,UAAQ,GACtB,OAAO,CAAC,gBAAgB,CAAC,CAW3B"}
|
package/dist/web.js
CHANGED
|
@@ -146,8 +146,7 @@ class MutableWebFrameworkResponse {
|
|
|
146
146
|
headers: toResponseHeaders(this.headers),
|
|
147
147
|
status: this.statusCode ?? 200
|
|
148
148
|
};
|
|
149
|
-
const
|
|
150
|
-
const nativeResponseBody = isResponseBodyForbidden(init.status) ? undefined : responseBody ?? '';
|
|
149
|
+
const nativeResponseBody = isResponseBodyForbidden(init.status) ? undefined : this.responseBody === undefined ? '' : this.responseBody;
|
|
151
150
|
this.finalizedResponse = this.streamActive ? new Response(this.getOrCreateResponseStream().readable, init) : new Response(nativeResponseBody, init);
|
|
152
151
|
this.raw = this.finalizedResponse;
|
|
153
152
|
this.committed = true;
|
|
@@ -244,23 +243,21 @@ export async function createWebFrameworkRequest(request, signal, multipartOption
|
|
|
244
243
|
*/
|
|
245
244
|
function createDeferredWebFrameworkRequest(request, signal, multipartOptions, maxBodySize = DEFAULT_MAX_BODY_SIZE, preserveRawBody = false) {
|
|
246
245
|
const url = new URL(request.url);
|
|
247
|
-
const
|
|
246
|
+
const requestHeaders = new Headers(request.headers);
|
|
248
247
|
const method = request.method;
|
|
249
|
-
const
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
-
const
|
|
253
|
-
const query = createMemoizedValue(() => parseQueryParams(searchParams));
|
|
254
|
-
const contentType = request.headers.get('content-type') ?? undefined;
|
|
248
|
+
const headers = createMemoizedValue(() => cloneWebHeaders(requestHeaders));
|
|
249
|
+
const cookies = createMemoizedValue(() => parseCookieHeader(requestHeaders.get('cookie') ?? undefined));
|
|
250
|
+
const query = createMemoizedValue(() => parseQueryString(url.search));
|
|
251
|
+
const contentType = requestHeaders.get('content-type') ?? undefined;
|
|
255
252
|
const isMultipart = typeof contentType === 'string' && contentType.includes('multipart/form-data');
|
|
256
253
|
const materializeBody = createMemoizedAsyncValue(async () => {
|
|
257
254
|
if (isMultipart) {
|
|
258
255
|
const materializedRequest = request.clone();
|
|
259
256
|
const result = await parseMultipart({
|
|
260
257
|
body: materializedRequest.body,
|
|
261
|
-
headers:
|
|
258
|
+
headers: requestHeaders,
|
|
262
259
|
method,
|
|
263
|
-
url: url
|
|
260
|
+
url: request.url
|
|
264
261
|
}, {
|
|
265
262
|
...multipartOptions,
|
|
266
263
|
maxTotalSize: multipartOptions?.maxTotalSize ?? maxBodySize
|
|
@@ -340,25 +337,56 @@ function createMemoizedAsyncValue(factory) {
|
|
|
340
337
|
return promise;
|
|
341
338
|
};
|
|
342
339
|
}
|
|
343
|
-
function
|
|
340
|
+
function parseQueryString(search) {
|
|
344
341
|
const query = {};
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
342
|
+
if (search.length <= 1) {
|
|
343
|
+
return query;
|
|
344
|
+
}
|
|
345
|
+
let index = search.charCodeAt(0) === 63 ? 1 : 0;
|
|
346
|
+
while (index <= search.length) {
|
|
347
|
+
let nextDelimiter = search.indexOf('&', index);
|
|
348
|
+
if (nextDelimiter === -1) {
|
|
349
|
+
nextDelimiter = search.length;
|
|
350
350
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
351
|
+
const entry = search.slice(index, nextDelimiter);
|
|
352
|
+
if (entry.length > 0) {
|
|
353
|
+
const separatorIndex = entry.indexOf('=');
|
|
354
|
+
const rawKey = separatorIndex === -1 ? entry : entry.slice(0, separatorIndex);
|
|
355
|
+
const rawValue = separatorIndex === -1 ? '' : entry.slice(separatorIndex + 1);
|
|
356
|
+
const key = decodeQueryComponent(rawKey, 'key');
|
|
357
|
+
const value = decodeQueryComponent(rawValue, 'value');
|
|
358
|
+
const current = query[key];
|
|
359
|
+
if (current === undefined) {
|
|
360
|
+
query[key] = value;
|
|
361
|
+
} else if (Array.isArray(current)) {
|
|
362
|
+
current.push(value);
|
|
363
|
+
} else {
|
|
364
|
+
query[key] = [current, value];
|
|
365
|
+
}
|
|
354
366
|
}
|
|
355
|
-
|
|
367
|
+
index = nextDelimiter + 1;
|
|
356
368
|
}
|
|
357
369
|
return query;
|
|
358
370
|
}
|
|
371
|
+
function decodeQueryComponent(value, kind) {
|
|
372
|
+
const normalizedValue = value.includes('+') ? value.replaceAll('+', ' ') : value;
|
|
373
|
+
try {
|
|
374
|
+
return decodeURIComponent(normalizedValue);
|
|
375
|
+
} catch {
|
|
376
|
+
return decodeQueryComponentLikeUrlSearchParams(value, kind);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function decodeQueryComponentLikeUrlSearchParams(value, kind) {
|
|
380
|
+
if (kind === 'key') {
|
|
381
|
+
const params = new URLSearchParams(`${value}=`);
|
|
382
|
+
return params.keys().next().value ?? '';
|
|
383
|
+
}
|
|
384
|
+
const params = new URLSearchParams(`x=${value}`);
|
|
385
|
+
return params.get('x') ?? '';
|
|
386
|
+
}
|
|
359
387
|
function cloneWebHeaders(headers) {
|
|
360
388
|
const clonedHeaders = {};
|
|
361
|
-
for (const [name, value] of headers) {
|
|
389
|
+
for (const [name, value] of headers.entries()) {
|
|
362
390
|
clonedHeaders[name] = value;
|
|
363
391
|
}
|
|
364
392
|
return clonedHeaders;
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"module-graph",
|
|
10
10
|
"orchestration"
|
|
11
11
|
],
|
|
12
|
-
"version": "1.0.0-beta.
|
|
12
|
+
"version": "1.0.0-beta.7",
|
|
13
13
|
"private": false,
|
|
14
14
|
"license": "MIT",
|
|
15
15
|
"repository": {
|
|
@@ -70,7 +70,7 @@
|
|
|
70
70
|
"@fluojs/config": "^1.0.0-beta.3",
|
|
71
71
|
"@fluojs/core": "^1.0.0-beta.2",
|
|
72
72
|
"@fluojs/di": "^1.0.0-beta.5",
|
|
73
|
-
"@fluojs/http": "^1.0.0-beta.
|
|
73
|
+
"@fluojs/http": "^1.0.0-beta.5"
|
|
74
74
|
},
|
|
75
75
|
"devDependencies": {
|
|
76
76
|
"vitest": "^3.2.4",
|