@fluojs/http 1.1.2 → 3.0.0
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/README.ko.md +430 -15
- package/README.md +437 -15
- package/dist/access-log-observer.d.ts +77 -0
- package/dist/access-log-observer.d.ts.map +1 -0
- package/dist/access-log-observer.js +171 -0
- package/dist/adapter.d.ts +9 -0
- package/dist/adapter.d.ts.map +1 -1
- package/dist/adapter.js +15 -1
- package/dist/adapters/binding.d.ts.map +1 -1
- package/dist/adapters/binding.js +18 -16
- package/dist/adapters/dto-binding-plan.d.ts +2 -2
- package/dist/adapters/dto-binding-plan.d.ts.map +1 -1
- package/dist/adapters/dto-binding-plan.js +13 -4
- package/dist/adapters/dto-validation-adapter.d.ts +2 -1
- package/dist/adapters/dto-validation-adapter.d.ts.map +1 -1
- package/dist/adapters/dto-validation-adapter.js +2 -2
- package/dist/byte-range-response.d.ts +71 -0
- package/dist/byte-range-response.d.ts.map +1 -0
- package/dist/byte-range-response.js +347 -0
- package/dist/client-identity.d.ts +8 -4
- package/dist/client-identity.d.ts.map +1 -1
- package/dist/client-identity.js +12 -93
- package/dist/compiled-route-identity.d.ts +17 -0
- package/dist/compiled-route-identity.d.ts.map +1 -0
- package/dist/compiled-route-identity.js +29 -0
- package/dist/connection.d.ts +67 -0
- package/dist/connection.d.ts.map +1 -0
- package/dist/connection.js +480 -0
- package/dist/context/request-context-node-store.d.ts +6 -0
- package/dist/context/request-context-node-store.d.ts.map +1 -1
- package/dist/context/request-context-node-store.js +14 -0
- package/dist/context/request-context.d.ts +5 -5
- package/dist/context/request-context.d.ts.map +1 -1
- package/dist/context/request-context.js +8 -83
- package/dist/context/request-id.d.ts +10 -0
- package/dist/context/request-id.d.ts.map +1 -0
- package/dist/context/request-id.js +27 -0
- package/dist/context/sse.d.ts +13 -0
- package/dist/context/sse.d.ts.map +1 -1
- package/dist/context/sse.js +36 -6
- package/dist/cookie-helpers.d.ts +47 -0
- package/dist/cookie-helpers.d.ts.map +1 -0
- package/dist/cookie-helpers.js +166 -0
- package/dist/decorators.d.ts +52 -19
- package/dist/decorators.d.ts.map +1 -1
- package/dist/decorators.js +57 -10
- package/dist/dispatch/conditional-request-policy.d.ts +67 -0
- package/dist/dispatch/conditional-request-policy.d.ts.map +1 -0
- package/dist/dispatch/conditional-request-policy.js +297 -0
- package/dist/dispatch/dispatch-content-negotiation.d.ts +8 -0
- package/dist/dispatch/dispatch-content-negotiation.d.ts.map +1 -1
- package/dist/dispatch/dispatch-content-negotiation.js +89 -42
- package/dist/dispatch/dispatch-error-negotiation.d.ts +26 -0
- package/dist/dispatch/dispatch-error-negotiation.d.ts.map +1 -0
- package/dist/dispatch/dispatch-error-negotiation.js +110 -0
- package/dist/dispatch/dispatch-error-policy.d.ts +1 -10
- package/dist/dispatch/dispatch-error-policy.d.ts.map +1 -1
- package/dist/dispatch/dispatch-error-policy.js +1 -33
- package/dist/dispatch/dispatch-error-representation.d.ts +18 -0
- package/dist/dispatch/dispatch-error-representation.d.ts.map +1 -0
- package/dist/dispatch/dispatch-error-representation.js +125 -0
- package/dist/dispatch/dispatch-response-metadata.d.ts +10 -0
- package/dist/dispatch/dispatch-response-metadata.d.ts.map +1 -0
- package/dist/dispatch/dispatch-response-metadata.js +12 -0
- package/dist/dispatch/dispatch-response-policy.d.ts +33 -5
- package/dist/dispatch/dispatch-response-policy.d.ts.map +1 -1
- package/dist/dispatch/dispatch-response-policy.js +149 -18
- package/dist/dispatch/dispatcher.d.ts +5 -1
- package/dist/dispatch/dispatcher.d.ts.map +1 -1
- package/dist/dispatch/dispatcher.js +178 -107
- package/dist/dispatch/fast-path/debug-visibility.d.ts.map +1 -1
- package/dist/dispatch/fast-path/debug-visibility.js +6 -3
- package/dist/dispatch/fast-path/dispatcher-state.d.ts +10 -0
- package/dist/dispatch/fast-path/dispatcher-state.d.ts.map +1 -0
- package/dist/dispatch/fast-path/dispatcher-state.js +52 -0
- package/dist/dispatch/fast-path/eligibility-checker.d.ts.map +1 -1
- package/dist/dispatch/fast-path/eligibility-checker.js +27 -15
- package/dist/dispatch/fast-path/eligibility.d.ts +16 -10
- package/dist/dispatch/fast-path/eligibility.d.ts.map +1 -1
- package/dist/dispatch/fast-path/eligibility.js +10 -4
- package/dist/dispatch/fast-path/fast-path-executor.d.ts +14 -1
- package/dist/dispatch/fast-path/fast-path-executor.d.ts.map +1 -1
- package/dist/dispatch/fast-path/fast-path-executor.js +23 -6
- package/dist/dispatch/request-abort.d.ts +22 -0
- package/dist/dispatch/request-abort.d.ts.map +1 -0
- package/dist/dispatch/request-abort.js +30 -0
- package/dist/dispatch/response-integration.d.ts +55 -0
- package/dist/dispatch/response-integration.d.ts.map +1 -0
- package/dist/dispatch/response-integration.js +57 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +19 -0
- package/dist/guards.d.ts +1 -1
- package/dist/guards.d.ts.map +1 -1
- package/dist/header-helpers.d.ts +59 -0
- package/dist/header-helpers.d.ts.map +1 -0
- package/dist/header-helpers.js +185 -0
- package/dist/index.d.ts +1 -16
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -15
- package/dist/index.portable.d.ts +25 -0
- package/dist/index.portable.d.ts.map +1 -0
- package/dist/index.portable.js +21 -0
- package/dist/internal.d.ts +3 -1
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +2 -0
- package/dist/mapping.d.ts.map +1 -1
- package/dist/mapping.js +100 -15
- package/dist/middleware/correlation.d.ts +9 -1
- package/dist/middleware/correlation.d.ts.map +1 -1
- package/dist/middleware/correlation.js +25 -14
- package/dist/middleware/cors.d.ts.map +1 -1
- package/dist/middleware/cors.js +7 -8
- package/dist/middleware/middleware.d.ts +3 -3
- package/dist/middleware/middleware.d.ts.map +1 -1
- package/dist/middleware/rate-limit.d.ts +13 -2
- package/dist/middleware/rate-limit.d.ts.map +1 -1
- package/dist/middleware/rate-limit.js +1 -0
- package/dist/static-assets.d.ts +77 -0
- package/dist/static-assets.d.ts.map +1 -0
- package/dist/static-assets.js +270 -0
- package/dist/types.d.ts +225 -17
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +71 -1
- package/package.json +19 -9
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import type { MaybePromise } from '@fluojs/core';
|
|
2
|
+
import { type ResolveHttpConnectionOptions } from './connection.js';
|
|
3
|
+
import type { RequestObserver } from './types.js';
|
|
4
|
+
/** Structured lifecycle event emitted by {@link createAccessLogObserver}. */
|
|
5
|
+
export type AccessLogEvent = AccessLogStartEvent | AccessLogErrorEvent | AccessLogFinishEvent;
|
|
6
|
+
/** A non-terminal access log record emitted when dispatch begins. */
|
|
7
|
+
export interface AccessLogStartEvent extends AccessLogRequestFields {
|
|
8
|
+
readonly event: 'http.access.start';
|
|
9
|
+
}
|
|
10
|
+
/** A non-terminal access log record emitted when request dispatch fails. */
|
|
11
|
+
export interface AccessLogErrorEvent extends AccessLogRequestFields {
|
|
12
|
+
readonly errorName: string;
|
|
13
|
+
readonly event: 'http.access.error';
|
|
14
|
+
}
|
|
15
|
+
/** Terminal access log record emitted exactly once after request dispatch settles. */
|
|
16
|
+
export interface AccessLogFinishEvent extends AccessLogRequestFields {
|
|
17
|
+
readonly durationMs: number;
|
|
18
|
+
readonly event: 'http.access.finish';
|
|
19
|
+
readonly outcome: AccessLogOutcome;
|
|
20
|
+
readonly responseHeaders?: Readonly<Record<string, string | readonly string[]>>;
|
|
21
|
+
readonly status?: number;
|
|
22
|
+
}
|
|
23
|
+
/** Common request fields carried by every structured access log event. */
|
|
24
|
+
export interface AccessLogRequestFields {
|
|
25
|
+
readonly clientAddress?: string;
|
|
26
|
+
readonly matchedRoute?: string;
|
|
27
|
+
readonly method: string;
|
|
28
|
+
readonly path: string;
|
|
29
|
+
readonly requestHeaders?: Readonly<Record<string, string | readonly string[]>>;
|
|
30
|
+
readonly requestId?: string;
|
|
31
|
+
}
|
|
32
|
+
/** Terminal request result classified from the observed dispatch lifecycle. */
|
|
33
|
+
export type AccessLogOutcome = 'aborted' | 'handled_error' | 'not_found' | 'success' | 'unhandled_error';
|
|
34
|
+
/** Consumer-owned structured event sink used by an access log observer. */
|
|
35
|
+
export interface AccessLogSink {
|
|
36
|
+
/**
|
|
37
|
+
* Receives one immutable access log lifecycle event.
|
|
38
|
+
*
|
|
39
|
+
* @param event Structured request lifecycle data with only allowlisted headers.
|
|
40
|
+
*/
|
|
41
|
+
emit(event: AccessLogEvent): MaybePromise<void>;
|
|
42
|
+
}
|
|
43
|
+
/** Header policy applied independently to request and response access log fields. */
|
|
44
|
+
export interface AccessLogHeaderOptions {
|
|
45
|
+
/** Header names to include. The default empty allowlist emits no headers. */
|
|
46
|
+
readonly allow?: readonly string[];
|
|
47
|
+
/** Additional header names whose values must be redacted when allowlisted. */
|
|
48
|
+
readonly redact?: readonly string[];
|
|
49
|
+
}
|
|
50
|
+
/** Options used to create a structured HTTP access log observer. */
|
|
51
|
+
export interface CreateAccessLogObserverOptions {
|
|
52
|
+
/**
|
|
53
|
+
* Explicit connection trust policy used to include a client address.
|
|
54
|
+
*
|
|
55
|
+
* Omit this option to keep transport and forwarded identity out of access logs.
|
|
56
|
+
*/
|
|
57
|
+
readonly clientIdentity?: ResolveHttpConnectionOptions;
|
|
58
|
+
/** Monotonic clock used to calculate terminal duration. Defaults to `performance.now()`. */
|
|
59
|
+
readonly clock?: () => number;
|
|
60
|
+
/** Allowlist and redaction policy for request and response headers. */
|
|
61
|
+
readonly headers?: AccessLogHeaderOptions;
|
|
62
|
+
/** Consumer-owned structured event destination. */
|
|
63
|
+
readonly sink: AccessLogSink;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Create a request observer that emits safe, structured access log lifecycle events.
|
|
67
|
+
*
|
|
68
|
+
* @param options Structured sink, optional client identity policy, header policy, and monotonic clock.
|
|
69
|
+
* @returns A request observer suitable for `CreateDispatcherOptions.observers`.
|
|
70
|
+
*
|
|
71
|
+
* @remarks
|
|
72
|
+
* The observer emits one start record, zero or more error records, and exactly one
|
|
73
|
+
* terminal finish record per admitted request. Header values are never emitted unless
|
|
74
|
+
* allowlisted, and authorization and cookie fields remain redacted even when allowed.
|
|
75
|
+
*/
|
|
76
|
+
export declare function createAccessLogObserver(options: CreateAccessLogObserverOptions): RequestObserver;
|
|
77
|
+
//# sourceMappingURL=access-log-observer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"access-log-observer.d.ts","sourceRoot":"","sources":["../src/access-log-observer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAyB,KAAK,4BAA4B,EAAE,MAAM,iBAAiB,CAAC;AAE3F,OAAO,KAAK,EAIV,eAAe,EAChB,MAAM,YAAY,CAAC;AAWpB,6EAA6E;AAC7E,MAAM,MAAM,cAAc,GACtB,mBAAmB,GACnB,mBAAmB,GACnB,oBAAoB,CAAC;AAEzB,qEAAqE;AACrE,MAAM,WAAW,mBAAoB,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;CACrC;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAoB,SAAQ,sBAAsB;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAC;CACrC;AAED,sFAAsF;AACtF,MAAM,WAAW,oBAAqB,SAAQ,sBAAsB;IAClE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,KAAK,EAAE,oBAAoB,CAAC;IACrC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,eAAe,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;IAChF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,cAAc,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,CAAC;IAC/E,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,+EAA+E;AAC/E,MAAM,MAAM,gBAAgB,GACxB,SAAS,GACT,eAAe,GACf,WAAW,GACX,SAAS,GACT,iBAAiB,CAAC;AAEtB,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B;;;;OAIG;IACH,IAAI,CAAC,KAAK,EAAE,cAAc,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;CACjD;AAED,qFAAqF;AACrF,MAAM,WAAW,sBAAsB;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACrC;AAED,oEAAoE;AACpE,MAAM,WAAW,8BAA8B;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,4BAA4B,CAAC;IACvD,4FAA4F;IAC5F,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B,uEAAuE;IACvE,QAAQ,CAAC,OAAO,CAAC,EAAE,sBAAsB,CAAC;IAC1C,mDAAmD;IACnD,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC;CAC9B;AAsGD;;;;;;;;;;GAUG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,8BAA8B,GAAG,eAAe,CAwEhG"}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { resolveHttpConnection } from './connection.js';
|
|
2
|
+
import { isRequestContextAborted } from './dispatch/request-abort.js';
|
|
3
|
+
const REDACTED_HEADER_VALUE = '[REDACTED]';
|
|
4
|
+
const DEFAULT_REDACTED_HEADERS = new Set(['authorization', 'cookie', 'proxy-authorization', 'set-cookie', 'x-api-key']);
|
|
5
|
+
|
|
6
|
+
/** Structured lifecycle event emitted by {@link createAccessLogObserver}. */
|
|
7
|
+
|
|
8
|
+
/** A non-terminal access log record emitted when dispatch begins. */
|
|
9
|
+
|
|
10
|
+
/** A non-terminal access log record emitted when request dispatch fails. */
|
|
11
|
+
|
|
12
|
+
/** Terminal access log record emitted exactly once after request dispatch settles. */
|
|
13
|
+
|
|
14
|
+
/** Common request fields carried by every structured access log event. */
|
|
15
|
+
|
|
16
|
+
/** Terminal request result classified from the observed dispatch lifecycle. */
|
|
17
|
+
|
|
18
|
+
/** Consumer-owned structured event sink used by an access log observer. */
|
|
19
|
+
|
|
20
|
+
/** Header policy applied independently to request and response access log fields. */
|
|
21
|
+
|
|
22
|
+
/** Options used to create a structured HTTP access log observer. */
|
|
23
|
+
|
|
24
|
+
function normalizeHeaderName(name) {
|
|
25
|
+
return name.toLowerCase();
|
|
26
|
+
}
|
|
27
|
+
function createHeaderPolicy(options) {
|
|
28
|
+
const allowed = new Set((options?.allow ?? []).map(normalizeHeaderName));
|
|
29
|
+
const redacted = new Set(DEFAULT_REDACTED_HEADERS);
|
|
30
|
+
for (const header of options?.redact ?? []) {
|
|
31
|
+
redacted.add(normalizeHeaderName(header));
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
allowed,
|
|
35
|
+
redacted
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function collectAllowedHeaders(headers, policy) {
|
|
39
|
+
const selected = {};
|
|
40
|
+
for (const [name, value] of Object.entries(headers)) {
|
|
41
|
+
const normalizedName = normalizeHeaderName(name);
|
|
42
|
+
if (value === undefined || !policy.allowed.has(normalizedName)) {
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
selected[normalizedName] = policy.redacted.has(normalizedName) ? REDACTED_HEADER_VALUE : Array.isArray(value) ? Object.freeze([...value]) : value;
|
|
46
|
+
}
|
|
47
|
+
return Object.keys(selected).length === 0 ? undefined : Object.freeze(selected);
|
|
48
|
+
}
|
|
49
|
+
function freezeAccessLogEvent(event) {
|
|
50
|
+
return Object.freeze(event);
|
|
51
|
+
}
|
|
52
|
+
function requestFields(state) {
|
|
53
|
+
return {
|
|
54
|
+
...(state.clientAddress === undefined ? {} : {
|
|
55
|
+
clientAddress: state.clientAddress
|
|
56
|
+
}),
|
|
57
|
+
...(state.matchedRoute === undefined ? {} : {
|
|
58
|
+
matchedRoute: state.matchedRoute
|
|
59
|
+
}),
|
|
60
|
+
method: state.request.method,
|
|
61
|
+
path: state.request.path,
|
|
62
|
+
...(state.requestHeaders === undefined ? {} : {
|
|
63
|
+
requestHeaders: state.requestHeaders
|
|
64
|
+
}),
|
|
65
|
+
...(state.requestId === undefined ? {} : {
|
|
66
|
+
requestId: state.requestId
|
|
67
|
+
})
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function readErrorName(error) {
|
|
71
|
+
return error instanceof Error ? error.name : 'UnknownError';
|
|
72
|
+
}
|
|
73
|
+
function isRequestAborted(request) {
|
|
74
|
+
return request.signal?.aborted === true || request.isAborted?.() === true;
|
|
75
|
+
}
|
|
76
|
+
function resolveFinalStatus(response) {
|
|
77
|
+
return response.statusCode ?? (response.committed ? 200 : undefined);
|
|
78
|
+
}
|
|
79
|
+
function resolveOutcome(state, context, status) {
|
|
80
|
+
if (isRequestContextAborted(context.requestContext)) {
|
|
81
|
+
return 'aborted';
|
|
82
|
+
}
|
|
83
|
+
if (!state.hasError) {
|
|
84
|
+
return 'success';
|
|
85
|
+
}
|
|
86
|
+
if (state.matchedRoute === undefined && status === 404) {
|
|
87
|
+
return 'not_found';
|
|
88
|
+
}
|
|
89
|
+
return (status ?? 500) < 500 ? 'handled_error' : 'unhandled_error';
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Create a request observer that emits safe, structured access log lifecycle events.
|
|
94
|
+
*
|
|
95
|
+
* @param options Structured sink, optional client identity policy, header policy, and monotonic clock.
|
|
96
|
+
* @returns A request observer suitable for `CreateDispatcherOptions.observers`.
|
|
97
|
+
*
|
|
98
|
+
* @remarks
|
|
99
|
+
* The observer emits one start record, zero or more error records, and exactly one
|
|
100
|
+
* terminal finish record per admitted request. Header values are never emitted unless
|
|
101
|
+
* allowlisted, and authorization and cookie fields remain redacted even when allowed.
|
|
102
|
+
*/
|
|
103
|
+
export function createAccessLogObserver(options) {
|
|
104
|
+
const headerPolicy = createHeaderPolicy(options.headers);
|
|
105
|
+
const clock = options.clock ?? performance.now.bind(performance);
|
|
106
|
+
const states = new WeakMap();
|
|
107
|
+
return {
|
|
108
|
+
onHandlerMatched(context) {
|
|
109
|
+
const state = states.get(context.requestContext);
|
|
110
|
+
if (state) {
|
|
111
|
+
state.matchedRoute = context.handler?.route.path;
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
async onRequestError(context, error) {
|
|
115
|
+
const state = states.get(context.requestContext);
|
|
116
|
+
if (!state) {
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
state.hasError = true;
|
|
120
|
+
await options.sink.emit(freezeAccessLogEvent({
|
|
121
|
+
...requestFields(state),
|
|
122
|
+
errorName: readErrorName(error),
|
|
123
|
+
event: 'http.access.error'
|
|
124
|
+
}));
|
|
125
|
+
},
|
|
126
|
+
async onRequestFinish(context) {
|
|
127
|
+
const state = states.get(context.requestContext);
|
|
128
|
+
if (!state) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
states.delete(context.requestContext);
|
|
132
|
+
const responseHeaders = collectAllowedHeaders(context.requestContext.response.headers, headerPolicy);
|
|
133
|
+
const status = resolveFinalStatus(context.requestContext.response);
|
|
134
|
+
await options.sink.emit(freezeAccessLogEvent({
|
|
135
|
+
...requestFields(state),
|
|
136
|
+
durationMs: Math.max(0, clock() - state.startedAt),
|
|
137
|
+
event: 'http.access.finish',
|
|
138
|
+
outcome: resolveOutcome(state, context, status),
|
|
139
|
+
...(responseHeaders === undefined ? {} : {
|
|
140
|
+
responseHeaders
|
|
141
|
+
}),
|
|
142
|
+
...(status === undefined ? {} : {
|
|
143
|
+
status
|
|
144
|
+
})
|
|
145
|
+
}));
|
|
146
|
+
},
|
|
147
|
+
async onRequestStart(context) {
|
|
148
|
+
const requestHeaders = collectAllowedHeaders(context.requestContext.request.headers, headerPolicy);
|
|
149
|
+
const clientAddress = options.clientIdentity === undefined ? undefined : resolveHttpConnection(context.requestContext.request, options.clientIdentity).clientAddress;
|
|
150
|
+
const state = {
|
|
151
|
+
...(clientAddress === undefined ? {} : {
|
|
152
|
+
clientAddress
|
|
153
|
+
}),
|
|
154
|
+
hasError: false,
|
|
155
|
+
request: context.requestContext.request,
|
|
156
|
+
...(requestHeaders === undefined ? {} : {
|
|
157
|
+
requestHeaders
|
|
158
|
+
}),
|
|
159
|
+
...(context.requestContext.requestId === undefined ? {} : {
|
|
160
|
+
requestId: context.requestContext.requestId
|
|
161
|
+
}),
|
|
162
|
+
startedAt: clock()
|
|
163
|
+
};
|
|
164
|
+
states.set(context.requestContext, state);
|
|
165
|
+
await options.sink.emit(freezeAccessLogEvent({
|
|
166
|
+
...requestFields(state),
|
|
167
|
+
event: 'http.access.start'
|
|
168
|
+
}));
|
|
169
|
+
}
|
|
170
|
+
};
|
|
171
|
+
}
|
package/dist/adapter.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export interface UnsupportedHttpAdapterRealtimeCapability {
|
|
|
19
19
|
* Describes the fetch style http adapter realtime capability contract.
|
|
20
20
|
*/
|
|
21
21
|
export interface FetchStyleHttpAdapterRealtimeCapability {
|
|
22
|
+
bindingInstallation?: HttpAdapterRealtimeBindingInstallation;
|
|
22
23
|
contract: 'raw-websocket-expansion';
|
|
23
24
|
kind: 'fetch-style';
|
|
24
25
|
mode: 'request-upgrade';
|
|
@@ -26,6 +27,13 @@ export interface FetchStyleHttpAdapterRealtimeCapability {
|
|
|
26
27
|
support: 'contract-only' | 'supported';
|
|
27
28
|
version: 1;
|
|
28
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Versioned host installation seam for protocol-owned fetch-style realtime bindings.
|
|
32
|
+
*/
|
|
33
|
+
export interface HttpAdapterRealtimeBindingInstallation {
|
|
34
|
+
install(binding: unknown | undefined): void;
|
|
35
|
+
version: 1;
|
|
36
|
+
}
|
|
29
37
|
/**
|
|
30
38
|
* Defines the http adapter realtime capability type.
|
|
31
39
|
*/
|
|
@@ -52,6 +60,7 @@ export declare function createUnsupportedHttpAdapterRealtimeCapability(reason: s
|
|
|
52
60
|
* @returns The create fetch style http adapter realtime capability result.
|
|
53
61
|
*/
|
|
54
62
|
export declare function createFetchStyleHttpAdapterRealtimeCapability(reason: string, options?: {
|
|
63
|
+
bindingInstallation?: Omit<HttpAdapterRealtimeBindingInstallation, 'version'>;
|
|
55
64
|
support?: FetchStyleHttpAdapterRealtimeCapability['support'];
|
|
56
65
|
}): FetchStyleHttpAdapterRealtimeCapability;
|
|
57
66
|
/**
|
package/dist/adapter.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,yCAAyC;IACxD,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,wCAAwC;IACvD,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,uCAAuC;IACtD,QAAQ,EAAE,yBAAyB,CAAC;IACpC,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,GAAG,WAAW,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,MAAM,6BAA6B,GACrC,yCAAyC,GACzC,uCAAuC,GACvC,wCAAwC,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,+CAA+C,CAC7D,MAAM,EAAE,OAAO,GACd,yCAAyC,CAK3C;AAED;;;;;GAKG;AACH,wBAAgB,8CAA8C,CAC5D,MAAM,EAAE,MAAM,GACb,wCAAwC,CAM1C;AAED;;;;;;GAMG;AACH,wBAAgB,6CAA6C,CAC3D,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,OAAO,CAAC,EAAE,uCAAuC,CAAC,SAAS,CAAC,CAAC;CACzD,GACL,uCAAuC,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAE7C;;GAEG;AACH,MAAM,WAAW,yCAAyC;IACxD,IAAI,EAAE,eAAe,CAAC;IACtB,MAAM,EAAE,OAAO,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,wCAAwC;IACvD,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,MAAM,WAAW,uCAAuC;IACtD,mBAAmB,CAAC,EAAE,sCAAsC,CAAC;IAC7D,QAAQ,EAAE,yBAAyB,CAAC;IACpC,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,iBAAiB,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,eAAe,GAAG,WAAW,CAAC;IACvC,OAAO,EAAE,CAAC,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,sCAAsC;IACrD,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC;CACZ;AAED;;GAEG;AACH,MAAM,MAAM,6BAA6B,GACrC,yCAAyC,GACzC,uCAAuC,GACvC,wCAAwC,CAAC;AAE7C;;;;;GAKG;AACH,wBAAgB,+CAA+C,CAC7D,MAAM,EAAE,OAAO,GACd,yCAAyC,CAK3C;AAED;;;;;GAKG;AACH,wBAAgB,8CAA8C,CAC5D,MAAM,EAAE,MAAM,GACb,wCAAwC,CAM1C;AAED;;;;;;GAMG;AACH,wBAAgB,6CAA6C,CAC3D,MAAM,EAAE,MAAM,EACd,OAAO,GAAE;IACP,mBAAmB,CAAC,EAAE,IAAI,CAAC,sCAAsC,EAAE,SAAS,CAAC,CAAC;IAC9E,OAAO,CAAC,EAAE,uCAAuC,CAAC,SAAS,CAAC,CAAC;CACzD,GACL,uCAAuC,CAqBzC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,SAAS,CAAC,IAAI,OAAO,CAAC;IAEtB,qBAAqB,CAAC,IAAI,6BAA6B,CAAC;IAExD;;;;;OAKG;IACH,MAAM,CAAC,UAAU,EAAE,UAAU,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;;OAKG;IACH,KAAK,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,CAAC;CAC5C;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,IAAI,sBAAsB,CAUzE"}
|
package/dist/adapter.js
CHANGED
|
@@ -10,6 +10,10 @@
|
|
|
10
10
|
* Describes the fetch style http adapter realtime capability contract.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
/**
|
|
14
|
+
* Versioned host installation seam for protocol-owned fetch-style realtime bindings.
|
|
15
|
+
*/
|
|
16
|
+
|
|
13
17
|
/**
|
|
14
18
|
* Defines the http adapter realtime capability type.
|
|
15
19
|
*/
|
|
@@ -49,7 +53,7 @@ export function createUnsupportedHttpAdapterRealtimeCapability(reason) {
|
|
|
49
53
|
* @returns The create fetch style http adapter realtime capability result.
|
|
50
54
|
*/
|
|
51
55
|
export function createFetchStyleHttpAdapterRealtimeCapability(reason, options = {}) {
|
|
52
|
-
|
|
56
|
+
const capability = {
|
|
53
57
|
contract: 'raw-websocket-expansion',
|
|
54
58
|
kind: 'fetch-style',
|
|
55
59
|
mode: 'request-upgrade',
|
|
@@ -57,6 +61,16 @@ export function createFetchStyleHttpAdapterRealtimeCapability(reason, options =
|
|
|
57
61
|
support: options.support ?? 'contract-only',
|
|
58
62
|
version: 1
|
|
59
63
|
};
|
|
64
|
+
if (options.bindingInstallation === undefined) {
|
|
65
|
+
return capability;
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
...capability,
|
|
69
|
+
bindingInstallation: {
|
|
70
|
+
install: options.bindingInstallation.install,
|
|
71
|
+
version: 1
|
|
72
|
+
}
|
|
73
|
+
};
|
|
60
74
|
}
|
|
61
75
|
|
|
62
76
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/adapters/binding.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"binding.d.ts","sourceRoot":"","sources":["../../src/adapters/binding.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAA8B,MAAM,cAAc,CAAC;AAI5E,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,eAAe,EAAoB,MAAM,aAAa,CAAC;AAkDhI;;GAEG;AACH,qBAAa,gBAAiB,YAAW,SAAS;IAChD,OAAO,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,GAAG,OAAO;CAG3D;AAqED;;GAEG;AACH,qBAAa,aAAc,YAAW,MAAM;IAC9B,OAAO,CAAC,QAAQ,CAAC,UAAU;gBAAV,UAAU,GAAE,SAAS,aAAa,EAAO;IAEhE,IAAI,CAAC,GAAG,EAAE,WAAW,EAAE,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,OAAO,CAAC;CAuGjF"}
|
package/dist/adapters/binding.js
CHANGED
|
@@ -65,6 +65,12 @@ function isConverter(value) {
|
|
|
65
65
|
function isConverterToken(value) {
|
|
66
66
|
return typeof value === 'function' || typeof value === 'string' || typeof value === 'symbol';
|
|
67
67
|
}
|
|
68
|
+
function hasRegisteredConverter(container, token) {
|
|
69
|
+
if (typeof container !== 'object' || container === null || !('has' in container) || typeof container.has !== 'function') {
|
|
70
|
+
return undefined;
|
|
71
|
+
}
|
|
72
|
+
return container.has(token);
|
|
73
|
+
}
|
|
68
74
|
async function resolveConverter(value, context, cache) {
|
|
69
75
|
if (!value) {
|
|
70
76
|
return undefined;
|
|
@@ -79,24 +85,20 @@ async function resolveConverter(value, context, cache) {
|
|
|
79
85
|
if (!isConverterToken(value)) {
|
|
80
86
|
throw new InvariantError('Converter metadata must be a converter instance or DI token.');
|
|
81
87
|
}
|
|
82
|
-
|
|
83
|
-
const
|
|
84
|
-
if (!isConverter(
|
|
85
|
-
throw new InvariantError('
|
|
88
|
+
if (typeof value === 'function' && hasRegisteredConverter(context.requestContext.container, value) === false) {
|
|
89
|
+
const instantiated = new value();
|
|
90
|
+
if (!isConverter(instantiated)) {
|
|
91
|
+
throw new InvariantError('Converter class must implement convert(value, target).');
|
|
86
92
|
}
|
|
87
|
-
cache.set(value,
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
throw new InvariantError('Converter class must implement convert(value, target).');
|
|
94
|
-
}
|
|
95
|
-
cache.set(value, instantiated);
|
|
96
|
-
return instantiated;
|
|
97
|
-
}
|
|
98
|
-
throw error;
|
|
93
|
+
cache.set(value, instantiated);
|
|
94
|
+
return instantiated;
|
|
95
|
+
}
|
|
96
|
+
const resolved = await context.requestContext.container.resolve(value);
|
|
97
|
+
if (!isConverter(resolved)) {
|
|
98
|
+
throw new InvariantError('Resolved converter token does not implement convert().');
|
|
99
99
|
}
|
|
100
|
+
cache.set(value, resolved);
|
|
101
|
+
return resolved;
|
|
100
102
|
}
|
|
101
103
|
|
|
102
104
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { type DtoFieldBindingMetadata } from '@fluojs/core/
|
|
1
|
+
import type { Constructor, MetadataPropertyKey, MetadataSource } from '@fluojs/core';
|
|
2
|
+
import { type DtoFieldBindingMetadata } from '@fluojs/core/request-pipeline';
|
|
3
3
|
import type { FrameworkRequest } from '../types.js';
|
|
4
4
|
export interface CompiledDtoBindingPlanEntry {
|
|
5
5
|
readonly converter?: DtoFieldBindingMetadata['converter'];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dto-binding-plan.d.ts","sourceRoot":"","sources":["../../src/adapters/dto-binding-plan.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"dto-binding-plan.d.ts","sourceRoot":"","sources":["../../src/adapters/dto-binding-plan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACrF,OAAO,EAKL,KAAK,uBAAuB,EAE7B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,KAAK,EAAE,gBAAgB,EAAwB,MAAM,aAAa,CAAC;AAoB1E,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,SAAS,CAAC,EAAE,uBAAuB,CAAC,WAAW,CAAC,CAAC;IAC1D,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,WAAW,EAAE,mBAAmB,CAAC;IAC1C,QAAQ,CAAC,IAAI,EAAE,CAAC,OAAO,EAAE,gBAAgB,KAAK,OAAO,CAAC;IACtD,QAAQ,CAAC,MAAM,EAAE,cAAc,CAAC;IAChC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,SAAS,2BAA2B,EAAE,CAAC;IACzD,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,eAAe,EAAE,OAAO,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,SAAS,mBAAmB,EAAE,CAAC;IACtD,QAAQ,CAAC,iBAAiB,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,OAAO,CAAC;CACzD;AAqDD,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,WAAW,GAAG,sBAAsB,CA4ClF"}
|
|
@@ -1,12 +1,19 @@
|
|
|
1
|
-
import { getClassValidationRules, getDtoBindingSchema, getDtoValidationSchema } from '@fluojs/core/
|
|
1
|
+
import { getClassValidationRules, getDtoBindingSchema, getDtoValidationSchema } from '@fluojs/core/request-pipeline';
|
|
2
|
+
import { getRequestHeader } from '../header-helpers.js';
|
|
2
3
|
function toFieldName(propertyKey) {
|
|
3
4
|
return typeof propertyKey === 'string' ? propertyKey : String(propertyKey);
|
|
4
5
|
}
|
|
5
6
|
function resolveSourceKey(propertyKey, key) {
|
|
6
7
|
return key ?? toFieldName(propertyKey);
|
|
7
8
|
}
|
|
8
|
-
function
|
|
9
|
-
return
|
|
9
|
+
function toPortableRequestFile(file) {
|
|
10
|
+
return {
|
|
11
|
+
buffer: file.buffer,
|
|
12
|
+
fieldname: file.fieldname,
|
|
13
|
+
mimetype: file.mimetype,
|
|
14
|
+
originalname: file.originalname,
|
|
15
|
+
size: file.size
|
|
16
|
+
};
|
|
10
17
|
}
|
|
11
18
|
const dtoBindingPlanCache = new WeakMap();
|
|
12
19
|
function createSourceReader(source, sourceKey) {
|
|
@@ -16,11 +23,13 @@ function createSourceReader(source, sourceKey) {
|
|
|
16
23
|
case 'query':
|
|
17
24
|
return request => request.query[sourceKey];
|
|
18
25
|
case 'header':
|
|
19
|
-
return request =>
|
|
26
|
+
return request => getRequestHeader(request, sourceKey);
|
|
20
27
|
case 'cookie':
|
|
21
28
|
return request => request.cookies[sourceKey];
|
|
22
29
|
case 'body':
|
|
23
30
|
return request => request.body?.[sourceKey];
|
|
31
|
+
case 'files':
|
|
32
|
+
return request => request.files?.filter(file => file.fieldname === sourceKey).map(toPortableRequestFile);
|
|
24
33
|
default:
|
|
25
34
|
return () => undefined;
|
|
26
35
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Constructor } from '@fluojs/core';
|
|
2
|
+
import { type MaterializeOptions } from '@fluojs/validation';
|
|
2
3
|
import type { Validator } from '../types.js';
|
|
3
4
|
/**
|
|
4
5
|
* Represents the http dto validation adapter.
|
|
@@ -7,6 +8,6 @@ export declare class HttpDtoValidationAdapter implements Validator {
|
|
|
7
8
|
private readonly validator;
|
|
8
9
|
private throwBadRequestForValidationError;
|
|
9
10
|
validate(value: unknown, target: Constructor): Promise<void>;
|
|
10
|
-
materialize<T>(value: unknown, target: Constructor<T
|
|
11
|
+
materialize<T>(value: unknown, target: Constructor<T>, options?: MaterializeOptions): Promise<T>;
|
|
11
12
|
}
|
|
12
13
|
//# sourceMappingURL=dto-validation-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dto-validation-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/dto-validation-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"dto-validation-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/dto-validation-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAGL,KAAK,kBAAkB,EACxB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,KAAK,EAAmB,SAAS,EAAE,MAAM,aAAa,CAAC;AAG9D;;GAEG;AACH,qBAAa,wBAAyB,YAAW,SAAS;IACxD,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA8B;IAExD,OAAO,CAAC,iCAAiC;IAMnC,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAkB5D,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,CAAC,CAAC;CAWvG"}
|
|
@@ -27,9 +27,9 @@ export class HttpDtoValidationAdapter {
|
|
|
27
27
|
throw error;
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
async materialize(value, target) {
|
|
30
|
+
async materialize(value, target, options) {
|
|
31
31
|
try {
|
|
32
|
-
return await this.validator.materialize(value, target);
|
|
32
|
+
return await this.validator.materialize(value, target, options);
|
|
33
33
|
} catch (error) {
|
|
34
34
|
if (error instanceof DtoValidationError) {
|
|
35
35
|
this.throwBadRequestForValidationError(error);
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { FrameworkRequest, FrameworkResponse, ResponseValidators } from './types.js';
|
|
2
|
+
type ByteRangeSource = ((() => ReadableStream<Uint8Array>) | ArrayBuffer | ReadableStream<Uint8Array> | Uint8Array);
|
|
3
|
+
/**
|
|
4
|
+
* Input accepted by {@link createByteRangeResponse}.
|
|
5
|
+
*
|
|
6
|
+
* A streamed representation needs its exact full byte length so the response
|
|
7
|
+
* can evaluate `Range`, `If-Range`, and `HEAD` before consuming the stream.
|
|
8
|
+
* Pass a stream factory when `HEAD` must not construct the stream.
|
|
9
|
+
*/
|
|
10
|
+
export type ByteRangeResponseSource = ByteRangeSource;
|
|
11
|
+
/** Options that describe a range-capable byte representation. */
|
|
12
|
+
export interface ByteRangeResponseOptions {
|
|
13
|
+
/** Media type emitted when route metadata did not already choose one. */
|
|
14
|
+
readonly contentType?: string;
|
|
15
|
+
/** Exact representation size in bytes. Required for a `ReadableStream` source. */
|
|
16
|
+
readonly size?: number;
|
|
17
|
+
}
|
|
18
|
+
/** Internal byte-representation data shared by response writers. */
|
|
19
|
+
export interface ByteRangeResponseEntry {
|
|
20
|
+
readonly contentType: string;
|
|
21
|
+
readonly size: number;
|
|
22
|
+
readonly source: ByteRangeResponseSource;
|
|
23
|
+
}
|
|
24
|
+
/** Inputs for writing a byte representation through a portable response facade. */
|
|
25
|
+
export interface ByteRangeResponseWriteOptions {
|
|
26
|
+
readonly applySuccessResponseMetadata: () => void;
|
|
27
|
+
/** Whether adapter-owned dynamic compression may transform byte-backed responses. */
|
|
28
|
+
readonly compression?: boolean;
|
|
29
|
+
readonly entry: ByteRangeResponseEntry;
|
|
30
|
+
readonly request: FrameworkRequest;
|
|
31
|
+
readonly response: FrameworkResponse;
|
|
32
|
+
readonly validators: ResponseValidators | undefined;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Creates a response entry with RFC single-byte-range semantics.
|
|
36
|
+
*
|
|
37
|
+
* `Uint8Array` and `ArrayBuffer` values can be returned directly from a
|
|
38
|
+
* handler. Use this helper when returning a portable `ReadableStream`.
|
|
39
|
+
*
|
|
40
|
+
* @param source Byte representation or stream factory to expose with range support.
|
|
41
|
+
* @param options Optional content type and required stream size metadata.
|
|
42
|
+
* @returns A registered response entry that applies single-byte-range semantics.
|
|
43
|
+
*/
|
|
44
|
+
export declare function createByteRangeResponse(source: ByteRangeResponseSource, options?: ByteRangeResponseOptions): object;
|
|
45
|
+
/**
|
|
46
|
+
* Returns whether a normal handler result is an automatically range-capable byte value.
|
|
47
|
+
*
|
|
48
|
+
* @param value Value to test for a byte representation.
|
|
49
|
+
* @returns `true` when the value is an `ArrayBuffer` or `Uint8Array`; otherwise `false`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function isByteRangeByteSource(value: unknown): value is ArrayBuffer | Uint8Array;
|
|
52
|
+
/**
|
|
53
|
+
* Determines whether an ordinary byte result requires byte-range processing.
|
|
54
|
+
*
|
|
55
|
+
* Explicit byte-range responses retain their full-response metadata behavior;
|
|
56
|
+
* this only guards automatic range handling for plain handler values.
|
|
57
|
+
*
|
|
58
|
+
* @param request Incoming request whose `Range` and `If-Range` fields are evaluated.
|
|
59
|
+
* @param validators Selected response validators used to evaluate `If-Range`.
|
|
60
|
+
* @returns `true` when the request has a valid byte range and `If-Range` permits it.
|
|
61
|
+
*/
|
|
62
|
+
export declare function shouldApplyByteRange(request: FrameworkRequest, validators: ResponseValidators | undefined): boolean;
|
|
63
|
+
/**
|
|
64
|
+
* Writes one byte representation while preserving range and cancellation semantics.
|
|
65
|
+
*
|
|
66
|
+
* @param options Request, response, validators, and representation metadata.
|
|
67
|
+
* @returns A promise that settles after the representation completes or fails.
|
|
68
|
+
*/
|
|
69
|
+
export declare function writeByteRangeResponse(options: ByteRangeResponseWriteOptions): Promise<void>;
|
|
70
|
+
export {};
|
|
71
|
+
//# sourceMappingURL=byte-range-response.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"byte-range-response.d.ts","sourceRoot":"","sources":["../src/byte-range-response.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,iBAAiB,EAA2B,kBAAkB,EAAE,MAAM,YAAY,CAAC;AASnH,KAAK,eAAe,GAAG,CACnB,CAAC,MAAM,cAAc,CAAC,UAAU,CAAC,CAAC,GAClC,WAAW,GACX,cAAc,CAAC,UAAU,CAAC,GAC1B,UAAU,CACb,CAAC;AAOF;;;;;;GAMG;AACH,MAAM,MAAM,uBAAuB,GAAG,eAAe,CAAC;AAEtD,iEAAiE;AACjE,MAAM,WAAW,wBAAwB;IACvC,yEAAyE;IACzE,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kFAAkF;IAClF,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,oEAAoE;AACpE,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,uBAAuB,CAAC;CAC1C;AAED,mFAAmF;AACnF,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,4BAA4B,EAAE,MAAM,IAAI,CAAC;IAClD,qFAAqF;IACrF,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,sBAAsB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC;IACnC,QAAQ,CAAC,QAAQ,EAAE,iBAAiB,CAAC;IACrC,QAAQ,CAAC,UAAU,EAAE,kBAAkB,GAAG,SAAS,CAAC;CACrD;AAED;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,uBAAuB,EAC/B,OAAO,GAAE,wBAA6B,GACrC,MAAM,CAuBR;AAED;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,WAAW,GAAG,UAAU,CAEvF;AAED;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,gBAAgB,EACzB,UAAU,EAAE,kBAAkB,GAAG,SAAS,GACzC,OAAO,CAIT;AA4DD;;;;;GAKG;AACH,wBAAsB,sBAAsB,CAC1C,OAAO,EAAE,6BAA6B,GACrC,OAAO,CAAC,IAAI,CAAC,CAwGf"}
|