@fluojs/runtime 1.0.0-beta.1 → 1.0.0-beta.11

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.
Files changed (52) hide show
  1. package/README.ko.md +53 -11
  2. package/README.md +53 -11
  3. package/dist/adapters/request-response-factory.d.ts +9 -0
  4. package/dist/adapters/request-response-factory.d.ts.map +1 -1
  5. package/dist/adapters/request-response-factory.js +14 -0
  6. package/dist/bootstrap.d.ts.map +1 -1
  7. package/dist/bootstrap.js +327 -60
  8. package/dist/health/diagnostics.d.ts +38 -0
  9. package/dist/health/diagnostics.d.ts.map +1 -1
  10. package/dist/health/diagnostics.js +48 -0
  11. package/dist/health/health.d.ts +34 -0
  12. package/dist/health/health.d.ts.map +1 -1
  13. package/dist/health/health.js +54 -4
  14. package/dist/index.d.ts +2 -1
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +1 -1
  17. package/dist/logging/json-logger.d.ts +5 -0
  18. package/dist/logging/json-logger.d.ts.map +1 -1
  19. package/dist/logging/json-logger.js +6 -0
  20. package/dist/logging/logger.d.ts +35 -1
  21. package/dist/logging/logger.d.ts.map +1 -1
  22. package/dist/logging/logger.js +69 -5
  23. package/dist/module-graph.d.ts +16 -0
  24. package/dist/module-graph.d.ts.map +1 -1
  25. package/dist/module-graph.js +304 -8
  26. package/dist/node/internal-node-compression.d.ts +15 -0
  27. package/dist/node/internal-node-compression.d.ts.map +1 -1
  28. package/dist/node/internal-node-compression.js +16 -0
  29. package/dist/node/internal-node-request.d.ts +128 -0
  30. package/dist/node/internal-node-request.d.ts.map +1 -1
  31. package/dist/node/internal-node-request.js +321 -40
  32. package/dist/node/internal-node-response.d.ts +21 -1
  33. package/dist/node/internal-node-response.d.ts.map +1 -1
  34. package/dist/node/internal-node-response.js +42 -3
  35. package/dist/node/internal-node.d.ts +43 -6
  36. package/dist/node/internal-node.d.ts.map +1 -1
  37. package/dist/node/internal-node.js +65 -9
  38. package/dist/node/node-request.d.ts +1 -1
  39. package/dist/node/node-request.d.ts.map +1 -1
  40. package/dist/node/node-request.js +1 -1
  41. package/dist/platform-shell.d.ts +4 -0
  42. package/dist/platform-shell.d.ts.map +1 -1
  43. package/dist/platform-shell.js +72 -20
  44. package/dist/request-transaction.d.ts +28 -0
  45. package/dist/request-transaction.d.ts.map +1 -1
  46. package/dist/request-transaction.js +33 -0
  47. package/dist/types.d.ts +29 -0
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/web.d.ts +9 -1
  50. package/dist/web.d.ts.map +1 -1
  51. package/dist/web.js +207 -56
  52. package/package.json +6 -6
@@ -2,6 +2,14 @@ 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
+
10
+ /**
11
+ * HTTP payload-size error that closes the underlying Node request stream after the response commits.
12
+ */
5
13
  export class NodeRequestPayloadTooLargeException extends PayloadTooLargeException {
6
14
  constructor(request) {
7
15
  super('Request body exceeds the size limit.');
@@ -31,50 +39,190 @@ export class NodeRequestPayloadTooLargeException extends PayloadTooLargeExceptio
31
39
  * @returns The normalized framework request used by the dispatcher.
32
40
  */
33
41
  export async function createFrameworkRequest(request, signal, multipartOptions, maxBodySize = 1 * 1024 * 1024, preserveRawBody = false) {
34
- const url = new URL(request.url ?? '/', 'http://localhost');
42
+ const frameworkRequest = createDeferredFrameworkRequest(request, signal, multipartOptions, maxBodySize, preserveRawBody);
43
+ await materializeFrameworkRequestBody(frameworkRequest);
44
+ return frameworkRequest;
45
+ }
46
+
47
+ /**
48
+ * Creates the cheap Node framework request shell before consuming the body stream.
49
+ *
50
+ * @param request - Raw Node request carrying headers, URL, and body stream.
51
+ * @param signal - Abort signal tied to the response lifecycle.
52
+ * @param multipartOptions - Multipart parser options applied when materializing multipart requests.
53
+ * @param maxBodySize - Maximum allowed non-multipart body size in bytes.
54
+ * @param preserveRawBody - Whether materialization should retain raw request body bytes.
55
+ * @returns The framework request shell with metadata snapshotted and body materialization deferred.
56
+ */
57
+ export function createDeferredFrameworkRequest(request, signal, multipartOptions, maxBodySize = 1 * 1024 * 1024, preserveRawBody = false) {
58
+ const rawUrl = request.url ?? '/';
59
+ const urlParts = splitRawRequestUrl(rawUrl);
35
60
  const headers = cloneRequestHeaders(request.headers);
36
- const contentType = readPrimaryHeaderValue(headers['content-type']);
37
- const isMultipart = typeof contentType === 'string' && contentType.includes('multipart/form-data');
38
- let body;
39
- let files;
40
- let rawBody;
41
- if (isMultipart) {
42
- const result = await parseMultipart({
43
- body: Readable.toWeb(request),
44
- headers,
45
- method: request.method,
46
- url: url.toString()
47
- }, {
48
- ...multipartOptions,
49
- maxTotalSize: multipartOptions?.maxTotalSize ?? maxBodySize
50
- });
51
- body = result.fields;
52
- files = result.files;
53
- } else {
61
+ const contentType = normalizePrimaryContentType(headers['content-type']);
62
+ const isMultipart = contentType === 'multipart/form-data';
63
+ let frameworkRequest;
64
+ const materializeBody = createMemoizedAsyncValue(async () => {
65
+ if (isMultipart) {
66
+ const result = await parseMultipart({
67
+ body: Readable.toWeb(request),
68
+ headers,
69
+ method: request.method,
70
+ url: resolveAbsoluteRequestUrl(rawUrl)
71
+ }, {
72
+ ...multipartOptions,
73
+ maxTotalSize: multipartOptions?.maxTotalSize ?? maxBodySize
74
+ });
75
+ frameworkRequest.body = result.fields;
76
+ frameworkRequest.files = result.files;
77
+ return;
78
+ }
79
+ if (!hasNodeRequestBody(request)) {
80
+ frameworkRequest.body = undefined;
81
+ return;
82
+ }
54
83
  const bodyResult = await readRequestBody(request, headers['content-type'], maxBodySize, preserveRawBody);
55
- body = bodyResult.body;
56
- rawBody = bodyResult.rawBody;
57
- }
58
- const frameworkRequest = {
59
- body,
60
- cookies: parseCookieHeader(headers.cookie),
84
+ frameworkRequest.body = bodyResult.body;
85
+ if (bodyResult.rawBody) {
86
+ frameworkRequest.rawBody = bodyResult.rawBody;
87
+ }
88
+ });
89
+ frameworkRequest = createDeferredFrameworkRequestShell({
90
+ cookieHeader: cloneHeaderValue(headers.cookie),
61
91
  headers,
62
- method: request.method ?? 'GET',
63
- params: {},
64
- path: url.pathname,
65
- query: parseQueryParams(url.searchParams),
92
+ materializeBody,
93
+ method: request.method,
94
+ path: urlParts.path,
95
+ queryFactory: () => parseQueryParamsFromSearch(urlParts.search),
66
96
  raw: request,
97
+ requestId: resolvePrimaryRequestIdFromHeaders(headers),
67
98
  signal,
68
- url: url.pathname + url.search
99
+ url: urlParts.path + urlParts.search
100
+ });
101
+ return frameworkRequest;
102
+ }
103
+
104
+ /**
105
+ * Creates a framework request shell from already-snapshotted Node adapter metadata.
106
+ *
107
+ * @param options - Raw request, metadata factories, and deferred body materialization hooks.
108
+ * @returns A framework request with lazy headers, cookies, query values, and optional body materialization.
109
+ */
110
+ export function createDeferredFrameworkRequestShell({
111
+ cookieHeader,
112
+ headers,
113
+ headersFactory,
114
+ materializeBody,
115
+ method,
116
+ path,
117
+ query,
118
+ queryFactory,
119
+ raw,
120
+ requestId,
121
+ signal,
122
+ url
123
+ }) {
124
+ const hasQuerySnapshot = query !== undefined;
125
+ const hasLazySignal = typeof signal === 'function';
126
+ const resolveHeaders = headersFactory ? createMemoizedValue(headersFactory) : () => headers ?? {};
127
+ const resolveCookies = createMemoizedValue(() => parseCookieHeader(cookieHeader ?? resolveHeaders().cookie));
128
+ const resolveQuery = hasQuerySnapshot ? undefined : createMemoizedValue(() => queryFactory?.() ?? {});
129
+ const frameworkRequest = {
130
+ get cookies() {
131
+ return resolveCookies();
132
+ },
133
+ get headers() {
134
+ return resolveHeaders();
135
+ },
136
+ method: method ?? 'GET',
137
+ params: {},
138
+ path,
139
+ requestId,
140
+ raw,
141
+ url
69
142
  };
70
- if (files) {
71
- frameworkRequest.files = files;
143
+ if (hasLazySignal) {
144
+ Object.defineProperty(frameworkRequest, 'signal', {
145
+ configurable: true,
146
+ enumerable: true,
147
+ get() {
148
+ return signal();
149
+ }
150
+ });
151
+ } else {
152
+ frameworkRequest.signal = signal;
72
153
  }
73
- if (rawBody) {
74
- frameworkRequest.rawBody = rawBody;
154
+ if (hasQuerySnapshot) {
155
+ frameworkRequest.query = query;
156
+ } else {
157
+ Object.defineProperty(frameworkRequest, 'query', {
158
+ configurable: true,
159
+ enumerable: true,
160
+ get() {
161
+ return resolveQuery();
162
+ }
163
+ });
164
+ }
165
+ if (materializeBody) {
166
+ frameworkRequest.materializeBody = materializeBody;
75
167
  }
76
168
  return frameworkRequest;
77
169
  }
170
+ function hasNodeRequestBody(request) {
171
+ const contentLength = request.headers['content-length'];
172
+ const transferEncoding = request.headers['transfer-encoding'];
173
+ const primaryContentLength = Array.isArray(contentLength) ? contentLength[0] : contentLength;
174
+ if (transferEncoding !== undefined) {
175
+ return true;
176
+ }
177
+ if (primaryContentLength === undefined) {
178
+ return true;
179
+ }
180
+ const parsedContentLength = Number(primaryContentLength);
181
+ return !Number.isFinite(parsedContentLength) || parsedContentLength !== 0;
182
+ }
183
+
184
+ /**
185
+ * Materializes a deferred Node framework request body exactly once.
186
+ *
187
+ * @param request - Framework request returned by {@link createDeferredFrameworkRequest}.
188
+ * @returns A promise that settles after body, rawBody, and files fields are populated when applicable.
189
+ */
190
+ export async function materializeFrameworkRequestBody(request) {
191
+ await request.materializeBody?.();
192
+ delete request.materializeBody;
193
+ }
194
+
195
+ /**
196
+ * Creates a synchronous memoized value resolver.
197
+ *
198
+ * @param factory - Function that computes the value on first access.
199
+ * @returns A stable resolver that returns the cached value after the first call.
200
+ */
201
+ export function createMemoizedValue(factory) {
202
+ let initialized = false;
203
+ let value;
204
+ return () => {
205
+ if (!initialized) {
206
+ value = factory();
207
+ initialized = true;
208
+ }
209
+ return value;
210
+ };
211
+ }
212
+
213
+ /**
214
+ * Creates an async memoized side-effect resolver.
215
+ *
216
+ * @param factory - Async function to run at most once.
217
+ * @returns A resolver that returns the same in-flight or completed promise for every call.
218
+ */
219
+ export function createMemoizedAsyncValue(factory) {
220
+ let promise;
221
+ return () => {
222
+ promise ??= factory();
223
+ return promise;
224
+ };
225
+ }
78
226
 
79
227
  /**
80
228
  * Creates an abort signal that fires when the Node response closes unexpectedly.
@@ -107,6 +255,20 @@ export function resolveRequestIdFromHeaders(headers) {
107
255
  const requestId = headers['x-request-id'] ?? headers['x-correlation-id'];
108
256
  return Array.isArray(requestId) ? requestId[0] : requestId;
109
257
  }
258
+ function resolvePrimaryRequestIdFromHeaders(headers) {
259
+ const requestId = headers['x-request-id'];
260
+ return Array.isArray(requestId) ? requestId[0] : requestId;
261
+ }
262
+
263
+ /**
264
+ * Parses a raw URL search string into the framework query shape.
265
+ *
266
+ * @param search - Raw search string, with or without a leading question mark.
267
+ * @returns Query values where repeated keys become string arrays.
268
+ */
269
+ export function parseQueryParamsFromSearch(search) {
270
+ return parseQueryParams(new URLSearchParams(search));
271
+ }
110
272
  function parseQueryParams(searchParams) {
111
273
  const query = {};
112
274
  for (const [key, value] of searchParams.entries()) {
@@ -123,16 +285,81 @@ function parseQueryParams(searchParams) {
123
285
  }
124
286
  return query;
125
287
  }
126
- function cloneRequestHeaders(headers) {
127
- const clonedEntries = Object.entries(headers).map(([name, value]) => [name, Array.isArray(value) ? [...value] : value]);
288
+
289
+ /**
290
+ * Snapshots host-parsed query values when they already match framework semantics.
291
+ *
292
+ * @param query - Host query object exposed by a Node-backed adapter.
293
+ * @returns A cloned query record when all values are strings or string arrays; otherwise `undefined` for raw URL fallback.
294
+ */
295
+ export function snapshotSimpleQueryRecord(query) {
296
+ if (typeof query !== 'object' || query === null) {
297
+ return undefined;
298
+ }
299
+ const snapshot = {};
300
+ for (const [key, value] of Object.entries(query)) {
301
+ if (typeof value === 'string') {
302
+ snapshot[key] = value;
303
+ continue;
304
+ }
305
+ if (Array.isArray(value) && value.every(item => typeof item === 'string')) {
306
+ snapshot[key] = [...value];
307
+ continue;
308
+ }
309
+ return undefined;
310
+ }
311
+ return snapshot;
312
+ }
313
+
314
+ /**
315
+ * Clones Node request headers into the framework header record shape.
316
+ *
317
+ * @param headers - Raw Node incoming headers.
318
+ * @returns A shallow header snapshot with array values cloned.
319
+ */
320
+ export function cloneRequestHeaders(headers) {
321
+ const clonedEntries = Object.entries(headers).map(([name, value]) => [name, cloneHeaderValue(value)]);
128
322
  return Object.fromEntries(clonedEntries);
129
323
  }
130
- function readPrimaryHeaderValue(headerValue) {
324
+
325
+ /**
326
+ * Clones a single Node header value when it is array-backed.
327
+ *
328
+ * @param value - Header value to snapshot.
329
+ * @returns The original scalar value or a cloned array value.
330
+ */
331
+ export function cloneHeaderValue(value) {
332
+ return Array.isArray(value) ? [...value] : value;
333
+ }
334
+
335
+ /**
336
+ * Reads the primary value from a Node header value.
337
+ *
338
+ * @param headerValue - Header value that may contain multiple entries.
339
+ * @returns The first header value when present.
340
+ */
341
+ export function readPrimaryHeaderValue(headerValue) {
131
342
  if (Array.isArray(headerValue)) {
132
343
  return headerValue[0];
133
344
  }
134
345
  return headerValue;
135
346
  }
347
+
348
+ /**
349
+ * Normalizes a Node content-type header to its primary media type.
350
+ *
351
+ * @param headerValue - Raw content-type header value.
352
+ * @returns Lowercase primary media type without parameters, or `undefined` when absent.
353
+ */
354
+ export function normalizePrimaryContentType(headerValue) {
355
+ const primaryHeaderValue = readPrimaryHeaderValue(headerValue);
356
+ if (typeof primaryHeaderValue !== 'string') {
357
+ return undefined;
358
+ }
359
+ const [mediaType] = primaryHeaderValue.split(';', 1);
360
+ const normalizedMediaType = mediaType?.trim().toLowerCase();
361
+ return normalizedMediaType && normalizedMediaType.length > 0 ? normalizedMediaType : undefined;
362
+ }
136
363
  function decodeCookieValue(raw) {
137
364
  try {
138
365
  return decodeURIComponent(raw);
@@ -140,7 +367,14 @@ function decodeCookieValue(raw) {
140
367
  return raw;
141
368
  }
142
369
  }
143
- function parseCookieHeader(cookieHeader) {
370
+
371
+ /**
372
+ * Parses a Node cookie header into framework cookie values.
373
+ *
374
+ * @param cookieHeader - Raw cookie header value or values.
375
+ * @returns Cookie name/value pairs with percent-decoded values when possible.
376
+ */
377
+ export function parseCookieHeader(cookieHeader) {
144
378
  const normalizedCookieHeader = Array.isArray(cookieHeader) ? cookieHeader.join('; ') : cookieHeader;
145
379
  if (!normalizedCookieHeader) {
146
380
  return {};
@@ -177,8 +411,8 @@ async function readRequestBody(request, contentType, maxBodySize = 1 * 1024 * 10
177
411
  rawBody: preserveRawBody ? rawBody : undefined
178
412
  };
179
413
  }
180
- const primaryContentType = Array.isArray(contentType) ? contentType[0] : contentType;
181
- if (typeof primaryContentType === 'string' && primaryContentType.includes('application/json')) {
414
+ const primaryContentType = normalizePrimaryContentType(contentType);
415
+ if (primaryContentType === 'application/json') {
182
416
  try {
183
417
  return {
184
418
  body: JSON.parse(bodyText),
@@ -192,4 +426,51 @@ async function readRequestBody(request, contentType, maxBodySize = 1 * 1024 * 10
192
426
  body: bodyText,
193
427
  rawBody: preserveRawBody ? rawBody : undefined
194
428
  };
429
+ }
430
+
431
+ /**
432
+ * Splits a raw Node request URL into path and search components.
433
+ *
434
+ * @param rawUrl - Raw request URL, absolute URL, or undefined value from Node.
435
+ * @returns The pathname and search string used by framework request matching and query parsing.
436
+ */
437
+ export function splitRawRequestUrl(rawUrl) {
438
+ const resolvedRawUrl = rawUrl ?? '/';
439
+ if (resolvedRawUrl.startsWith('http://') || resolvedRawUrl.startsWith('https://')) {
440
+ const url = new URL(resolvedRawUrl);
441
+ return {
442
+ path: url.pathname,
443
+ search: url.search
444
+ };
445
+ }
446
+ const queryStart = resolvedRawUrl.indexOf('?');
447
+ const hashStart = resolvedRawUrl.indexOf('#');
448
+ const pathEndCandidates = [queryStart, hashStart].filter(index => index >= 0);
449
+ const pathEnd = pathEndCandidates.length > 0 ? Math.min(...pathEndCandidates) : resolvedRawUrl.length;
450
+ const path = resolvedRawUrl.slice(0, pathEnd) || '/';
451
+ if (queryStart === -1) {
452
+ return {
453
+ path,
454
+ search: ''
455
+ };
456
+ }
457
+ const searchEnd = hashStart >= 0 && hashStart > queryStart ? hashStart : resolvedRawUrl.length;
458
+ return {
459
+ path,
460
+ search: resolvedRawUrl.slice(queryStart, searchEnd)
461
+ };
462
+ }
463
+
464
+ /**
465
+ * Resolves a raw Node request URL into an absolute URL string.
466
+ *
467
+ * @param rawUrl - Raw request URL, absolute URL, or undefined value from Node.
468
+ * @returns An absolute URL suitable for Web-standard parsers.
469
+ */
470
+ export function resolveAbsoluteRequestUrl(rawUrl) {
471
+ const resolvedRawUrl = rawUrl ?? '/';
472
+ if (resolvedRawUrl.startsWith('http://') || resolvedRawUrl.startsWith('https://')) {
473
+ return resolvedRawUrl;
474
+ }
475
+ return new URL(resolvedRawUrl, 'http://localhost').toString();
195
476
  }
@@ -1,8 +1,28 @@
1
1
  import type { ServerResponse } from 'node:http';
2
2
  import { type FrameworkResponseCompression, type FrameworkResponse } from '@fluojs/http';
3
+ /**
4
+ * Defines the mutable framework response type.
5
+ */
3
6
  export type MutableFrameworkResponse = FrameworkResponse & {
4
7
  statusSet?: boolean;
5
8
  };
6
- export declare function createFrameworkResponse(response: ServerResponse, compression?: FrameworkResponseCompression): MutableFrameworkResponse;
9
+ type FrameworkResponseCompressionFactory = () => FrameworkResponseCompression | undefined;
10
+ /**
11
+ * Create framework response.
12
+ *
13
+ * @param response The response.
14
+ * @param compression The compression.
15
+ * @returns The create framework response result.
16
+ */
17
+ export declare function createFrameworkResponse(response: ServerResponse, compression?: FrameworkResponseCompression | FrameworkResponseCompressionFactory): MutableFrameworkResponse;
18
+ /**
19
+ * Write node adapter error response.
20
+ *
21
+ * @param error The error.
22
+ * @param response The response.
23
+ * @param requestId The request id.
24
+ * @returns The write node adapter error response result.
25
+ */
7
26
  export declare function writeNodeAdapterErrorResponse(error: unknown, response: FrameworkResponse, requestId?: string): Promise<void>;
27
+ export {};
8
28
  //# sourceMappingURL=internal-node-response.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"internal-node-response.d.ts","sourceRoot":"","sources":["../../src/node/internal-node-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAIL,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EAEvB,MAAM,cAAc,CAAC;AAEtB,MAAM,MAAM,wBAAwB,GAAG,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AA6CnF,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,cAAc,EACxB,WAAW,CAAC,EAAE,4BAA4B,GACzC,wBAAwB,CA+F1B;AAED,wBAAsB,6BAA6B,CACjD,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAIf"}
1
+ {"version":3,"file":"internal-node-response.d.ts","sourceRoot":"","sources":["../../src/node/internal-node-response.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEhD,OAAO,EAIL,KAAK,4BAA4B,EACjC,KAAK,iBAAiB,EAEvB,MAAM,cAAc,CAAC;AAEtB;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAAG,iBAAiB,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC;AAEnF,KAAK,mCAAmC,GAAG,MAAM,4BAA4B,GAAG,SAAS,CAAC;AA6C1F;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,cAAc,EACxB,WAAW,CAAC,EAAE,4BAA4B,GAAG,mCAAmC,GAC/E,wBAAwB,CAqH1B;AAED;;;;;;;GAOG;AACH,wBAAsB,6BAA6B,CACjD,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,iBAAiB,EAC3B,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAIf"}
@@ -1,4 +1,9 @@
1
1
  import { createErrorResponse, HttpException, InternalServerErrorException } from '@fluojs/http';
2
+
3
+ /**
4
+ * Defines the mutable framework response type.
5
+ */
6
+
2
7
  function createFrameworkResponseStream(response) {
3
8
  return {
4
9
  close() {
@@ -39,7 +44,28 @@ function createFrameworkResponseStream(response) {
39
44
  }
40
45
  };
41
46
  }
47
+
48
+ /**
49
+ * Create framework response.
50
+ *
51
+ * @param response The response.
52
+ * @param compression The compression.
53
+ * @returns The create framework response result.
54
+ */
42
55
  export function createFrameworkResponse(response, compression) {
56
+ let activeStream;
57
+ const resolveCompression = (() => {
58
+ const factory = typeof compression === 'function' ? compression : () => compression;
59
+ let resolved = false;
60
+ let value;
61
+ return () => {
62
+ if (!resolved) {
63
+ value = factory();
64
+ resolved = true;
65
+ }
66
+ return value;
67
+ };
68
+ })();
43
69
  const mergeSetCookieHeader = (current, incoming) => {
44
70
  const nextValues = Array.isArray(incoming) ? incoming : [incoming];
45
71
  if (current === undefined) {
@@ -56,7 +82,10 @@ export function createFrameworkResponse(response, compression) {
56
82
  committed: response.headersSent || response.writableEnded,
57
83
  headers: {},
58
84
  raw: response,
59
- stream: createFrameworkResponseStream(response),
85
+ get stream() {
86
+ activeStream ??= createFrameworkResponseStream(response);
87
+ return activeStream;
88
+ },
60
89
  redirect(status, location) {
61
90
  this.setStatus(status);
62
91
  this.setHeader('Location', location);
@@ -74,9 +103,10 @@ export function createFrameworkResponse(response, compression) {
74
103
  }
75
104
  const contentType = response.getHeader('Content-Type');
76
105
  const payload = typeof serialized.payload === 'string' ? Buffer.from(serialized.payload, 'utf8') : serialized.payload;
77
- if (compression) {
106
+ const activeCompression = resolveCompression();
107
+ if (activeCompression) {
78
108
  this.committed = true;
79
- return Promise.resolve(compression.write(payload, {
109
+ return Promise.resolve(activeCompression.write(payload, {
80
110
  contentType
81
111
  })).then(handled => {
82
112
  if (!handled && !response.writableEnded) {
@@ -113,6 +143,15 @@ export function createFrameworkResponse(response, compression) {
113
143
  };
114
144
  return frameworkResponse;
115
145
  }
146
+
147
+ /**
148
+ * Write node adapter error response.
149
+ *
150
+ * @param error The error.
151
+ * @param response The response.
152
+ * @param requestId The request id.
153
+ * @returns The write node adapter error response result.
154
+ */
116
155
  export async function writeNodeAdapterErrorResponse(error, response, requestId) {
117
156
  const httpError = toHttpException(error);
118
157
  response.setStatus(httpError.status);
@@ -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';
@@ -11,6 +12,9 @@ declare module '@fluojs/http' {
11
12
  rawBody?: Uint8Array;
12
13
  }
13
14
  }
15
+ /**
16
+ * Describes the node http adapter options contract.
17
+ */
14
18
  export interface NodeHttpAdapterOptions {
15
19
  host?: string;
16
20
  https?: HttpsServerOptions;
@@ -21,8 +25,17 @@ export interface NodeHttpAdapterOptions {
21
25
  retryLimit?: number;
22
26
  shutdownTimeoutMs?: number;
23
27
  }
28
+ /**
29
+ * Defines the node application signal type.
30
+ */
24
31
  export type NodeApplicationSignal = 'SIGINT' | 'SIGTERM';
32
+ /**
33
+ * Defines the cors input type.
34
+ */
25
35
  export type CorsInput = false | string | string[] | CorsOptions;
36
+ /**
37
+ * Describes the bootstrap node application options contract.
38
+ */
26
39
  export interface BootstrapNodeApplicationOptions extends Omit<CreateApplicationOptions, 'adapter' | 'logger' | 'middleware'> {
27
40
  compression?: boolean;
28
41
  cors?: CorsInput;
@@ -41,6 +54,9 @@ export interface BootstrapNodeApplicationOptions extends Omit<CreateApplicationO
41
54
  securityHeaders?: false | SecurityHeadersOptions;
42
55
  shutdownTimeoutMs?: number;
43
56
  }
57
+ /**
58
+ * Describes the run node application options contract.
59
+ */
44
60
  export interface RunNodeApplicationOptions extends BootstrapNodeApplicationOptions {
45
61
  forceExitTimeoutMs?: number;
46
62
  shutdownSignals?: false | readonly NodeApplicationSignal[];
@@ -50,22 +66,21 @@ interface NodeListenTarget {
50
66
  url: string;
51
67
  }
52
68
  type NodeServer = ReturnType<typeof createHttpServer> | ReturnType<typeof createHttpsServer>;
69
+ /**
70
+ * Represents the node http application adapter.
71
+ */
53
72
  export declare class NodeHttpApplicationAdapter implements HttpApplicationAdapter {
54
73
  private readonly port;
55
74
  private readonly host;
56
75
  private readonly retryDelayMs;
57
76
  private readonly retryLimit;
58
- private readonly compression;
59
77
  private readonly httpsOptions;
60
- private readonly multipartOptions?;
61
- private readonly maxBodySize;
62
- private readonly preserveRawBody;
63
78
  private readonly shutdownTimeoutMs;
64
79
  private readonly server;
65
80
  private dispatcher?;
66
81
  private readonly requestResponseFactory;
67
82
  private readonly sockets;
68
- constructor(port: number, host: string | undefined, retryDelayMs: number | undefined, retryLimit: number | undefined, compression: boolean | undefined, httpsOptions: HttpsServerOptions | undefined, multipartOptions?: MultipartOptions | undefined, maxBodySize?: number, preserveRawBody?: boolean, shutdownTimeoutMs?: number);
83
+ constructor(port: number, host: string | undefined, retryDelayMs: number | undefined, retryLimit: number | undefined, compression: boolean | undefined, httpsOptions: HttpsServerOptions | undefined, multipartOptions?: MultipartOptions, maxBodySize?: number, preserveRawBody?: boolean, shutdownTimeoutMs?: number);
69
84
  getServer(): NodeServer;
70
85
  getRealtimeCapability(): import("@fluojs/http").ServerBackedHttpAdapterRealtimeCapability;
71
86
  getListenTarget(): NodeListenTarget;
@@ -73,8 +88,30 @@ export declare class NodeHttpApplicationAdapter implements HttpApplicationAdapte
73
88
  close(): Promise<void>;
74
89
  private handleRequest;
75
90
  }
91
+ /**
92
+ * Create node http adapter.
93
+ *
94
+ * @param options The options.
95
+ * @param compression The compression.
96
+ * @param multipartOptions The multipart options.
97
+ * @returns The create node http adapter result.
98
+ */
76
99
  export declare function createNodeHttpAdapter(options?: NodeHttpAdapterOptions, compression?: boolean, multipartOptions?: MultipartOptions): HttpApplicationAdapter;
100
+ /**
101
+ * Bootstrap node application.
102
+ *
103
+ * @param rootModule The root module.
104
+ * @param options The options.
105
+ * @returns The bootstrap node application result.
106
+ */
77
107
  export declare function bootstrapNodeApplication(rootModule: ModuleType, options: BootstrapNodeApplicationOptions): Promise<Application>;
108
+ /**
109
+ * Run node application.
110
+ *
111
+ * @param rootModule The root module.
112
+ * @param options The options.
113
+ * @returns The run node application result.
114
+ */
78
115
  export declare function runNodeApplication(rootModule: ModuleType, options: RunNodeApplicationOptions): Promise<Application>;
79
- 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, };
80
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;AAYxC,OAAO,EACL,oCAAoC,EACpC,0BAA0B,EAC1B,uBAAuB,EACxB,MAAM,6BAA6B,CAAC;AACrC,OAAO,KAAK,EAAE,gBAAgB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAKtE,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAExG,OAAO,QAAQ,cAAc,CAAC;IAC5B,UAAU,gBAAgB;QACxB,KAAK,CAAC,EAAE,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,EAAE,UAAU,CAAC;KACtB;CACF;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,MAAM,qBAAqB,GAAG,QAAQ,GAAG,SAAS,CAAC;AAEzD,MAAM,MAAM,SAAS,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,EAAE,GAAG,WAAW,CAAC;AAIhE,MAAM,WAAW,+BAAgC,SAAQ,IAAI,CAAC,wBAAwB,EAAE,SAAS,GAAG,QAAQ,GAAG,YAAY,CAAC;IAC1H,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,kBAAkB,CAAC;IAC3B,MAAM,CAAC,EAAE,iBAAiB,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,KAAK,GAAG,sBAAsB,CAAC;IACjD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,yBAA0B,SAAQ,+BAA+B;IAChF,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,eAAe,CAAC,EAAE,KAAK,GAAG,SAAS,qBAAqB,EAAE,CAAC;CAC5D;AAED,UAAU,gBAAgB;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;CACb;AASD,KAAK,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC;AAG7F,qBAAa,0BAA2B,YAAW,sBAAsB;IAWrE,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,YAAY;IAC7B,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAC;IAClC,OAAO,CAAC,QAAQ,CAAC,WAAW;IAC5B,OAAO,CAAC,QAAQ,CAAC,eAAe;IAChC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAnBpC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAa;IACpC,OAAO,CAAC,UAAU,CAAC,CAAa;IAChC,OAAO,CAAC,QAAQ,CAAC,sBAAsB,CAIrC;IACF,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;gBAG1B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,YAAY,oBAAM,EAClB,UAAU,oBAAK,EACf,WAAW,qBAAQ,EACnB,YAAY,EAAE,kBAAkB,GAAG,SAAS,EAC5C,gBAAgB,CAAC,EAAE,gBAAgB,YAAA,EACnC,WAAW,SAAkB,EAC7B,eAAe,UAAQ,EACvB,iBAAiB,SAA8B;IAmBlE,SAAS,IAAI,UAAU;IAIvB,qBAAqB;IAIrB,eAAe,IAAI,gBAAgB;IAI7B,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAU7C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;YAad,aAAa;CAY5B;AA8CD,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,sBAA2B,EAAE,WAAW,UAAQ,EAAE,gBAAgB,CAAC,EAAE,gBAAgB,GAAG,sBAAsB,CAa5J;AAED,wBAAsB,wBAAwB,CAC5C,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,WAAW,CAAC,CAMtB;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,WAAW,CAAC,CAQtB;AAED,OAAO,EACL,oBAAoB,EACpB,6BAA6B,EAC7B,oCAAoC,EACpC,0BAA0B,EAC1B,uBAAuB,GACxB,CAAC"}
1
+ {"version":3,"file":"internal-node.d.ts","sourceRoot":"","sources":["../../src/node/internal-node.ts"],"names":[],"mappings":"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"}