@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,27 @@
|
|
|
1
|
+
import { getRequestHeader } from '../header-helpers.js';
|
|
2
|
+
const REQUEST_ID_HEADER = 'x-request-id';
|
|
3
|
+
const CORRELATION_ID_HEADER = 'x-correlation-id';
|
|
4
|
+
function readInboundHeaderValue(request, headerName) {
|
|
5
|
+
const rawHeaderValue = getRequestHeader(request, headerName);
|
|
6
|
+
const value = Array.isArray(rawHeaderValue) ? rawHeaderValue[0] : rawHeaderValue;
|
|
7
|
+
const normalized = value?.trim();
|
|
8
|
+
return normalized ? normalized : undefined;
|
|
9
|
+
}
|
|
10
|
+
function createRequestId() {
|
|
11
|
+
const randomUUID = globalThis.crypto?.randomUUID;
|
|
12
|
+
if (randomUUID) {
|
|
13
|
+
return randomUUID.call(globalThis.crypto);
|
|
14
|
+
}
|
|
15
|
+
return `req_${Date.now().toString(36)}_${Math.random().toString(36).slice(2)}`;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Resolves the request identity before dispatcher observers begin.
|
|
20
|
+
*
|
|
21
|
+
* @param request Adapter-normalized request carrying inbound correlation headers.
|
|
22
|
+
* @param generate Whether to generate an ID when neither supported inbound header is present.
|
|
23
|
+
* @returns The adopted request or legacy correlation ID, or a newly generated ID.
|
|
24
|
+
*/
|
|
25
|
+
export function resolveRequestId(request, generate = true) {
|
|
26
|
+
return readInboundHeaderValue(request, REQUEST_ID_HEADER) ?? readInboundHeaderValue(request, CORRELATION_ID_HEADER) ?? (generate ? createRequestId() : undefined);
|
|
27
|
+
}
|
package/dist/context/sse.d.ts
CHANGED
|
@@ -53,6 +53,8 @@ export declare function encodeSseMessage(data: unknown, options?: SseSendOptions
|
|
|
53
53
|
export declare class SseResponse {
|
|
54
54
|
private readonly context;
|
|
55
55
|
private closed;
|
|
56
|
+
private resolveCompletion;
|
|
57
|
+
private readonly completionPromise;
|
|
56
58
|
private readonly stream;
|
|
57
59
|
private removeCloseListener?;
|
|
58
60
|
private readonly onAbort;
|
|
@@ -72,8 +74,19 @@ export declare class SseResponse {
|
|
|
72
74
|
* @returns `true` when the underlying stream accepted the frame without backpressure.
|
|
73
75
|
*/
|
|
74
76
|
comment(comment: string): boolean;
|
|
77
|
+
/** @internal Completion signal consumed by the dispatcher for manual SSE responses. */
|
|
78
|
+
get completion(): Promise<void>;
|
|
75
79
|
/** Closes the SSE stream and removes registered abort/close listeners exactly once. */
|
|
76
80
|
close(): void;
|
|
77
81
|
private writeFrame;
|
|
78
82
|
}
|
|
83
|
+
/**
|
|
84
|
+
* Resolves after a manual SSE response closes through any supported termination path.
|
|
85
|
+
*
|
|
86
|
+
* @param response Manual SSE response whose lifecycle is observed.
|
|
87
|
+
* @returns A promise that resolves after the response closes.
|
|
88
|
+
*
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
export declare function waitForSseResponseCompletion(response: SseResponse): Promise<void>;
|
|
79
92
|
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/context/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8C,cAAc,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../../src/context/sse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAA8C,cAAc,EAAE,MAAM,aAAa,CAAC;AAG9F,iFAAiF;AACjF,MAAM,WAAW,cAAc;IAC7B,+EAA+E;IAC/E,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,6EAA6E;IAC7E,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrB,8FAA8F;IAC9F,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,OAAO,CAAE,SAAQ,cAAc;IAC7D,4DAA4D;IAC5D,IAAI,EAAE,CAAC,CAAC;CACT;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,GAAG,OAAO,EAAE,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAAC,CAAC,CAAC,CAEhF;AAoCD;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,MAAM,CAoBpF;AAED;;;;;GAKG;AACH,qBAAa,WAAW;IAcV,OAAO,CAAC,QAAQ,CAAC,OAAO;IAbpC,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAE/B;IACH,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA0B;IACjD,OAAO,CAAC,mBAAmB,CAAC,CAAa;IAEzC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAGtB;gBAE2B,OAAO,EAAE,cAAc;IAoCpD;;;;;;OAMG;IACH,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,OAAO;IAI1D;;;;;OAKG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIjC,uFAAuF;IACvF,IAAI,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,CAE9B;IAED,uFAAuF;IACvF,KAAK,IAAI,IAAI;IAoBb,OAAO,CAAC,UAAU;CAanB;AAED;;;;;;;GAOG;AACH,wBAAgB,4BAA4B,CAAC,QAAQ,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjF"}
|
package/dist/context/sse.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { markRequestContextAborted } from '../dispatch/request-abort.js';
|
|
2
|
+
|
|
1
3
|
/** Options that customize the fields emitted for one server-sent event frame. */
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -90,9 +92,14 @@ export function encodeSseMessage(data, options = {}) {
|
|
|
90
92
|
*/
|
|
91
93
|
export class SseResponse {
|
|
92
94
|
closed = false;
|
|
95
|
+
resolveCompletion = () => undefined;
|
|
96
|
+
completionPromise = new Promise(resolve => {
|
|
97
|
+
this.resolveCompletion = resolve;
|
|
98
|
+
});
|
|
93
99
|
stream;
|
|
94
100
|
removeCloseListener;
|
|
95
101
|
onAbort = () => {
|
|
102
|
+
markRequestContextAborted(this.context);
|
|
96
103
|
this.close();
|
|
97
104
|
};
|
|
98
105
|
constructor(context) {
|
|
@@ -121,6 +128,7 @@ export class SseResponse {
|
|
|
121
128
|
}
|
|
122
129
|
this.removeCloseListener = removeCloseListener;
|
|
123
130
|
if (this.stream.closed) {
|
|
131
|
+
markRequestContextAborted(this.context);
|
|
124
132
|
this.close();
|
|
125
133
|
}
|
|
126
134
|
}
|
|
@@ -146,28 +154,50 @@ export class SseResponse {
|
|
|
146
154
|
return this.writeFrame(encodeSseComment(comment));
|
|
147
155
|
}
|
|
148
156
|
|
|
157
|
+
/** @internal Completion signal consumed by the dispatcher for manual SSE responses. */
|
|
158
|
+
get completion() {
|
|
159
|
+
return this.completionPromise;
|
|
160
|
+
}
|
|
161
|
+
|
|
149
162
|
/** Closes the SSE stream and removes registered abort/close listeners exactly once. */
|
|
150
163
|
close() {
|
|
151
164
|
if (this.closed) {
|
|
152
165
|
return;
|
|
153
166
|
}
|
|
154
167
|
this.closed = true;
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.stream.
|
|
168
|
+
try {
|
|
169
|
+
this.context.request.signal?.removeEventListener('abort', this.onAbort);
|
|
170
|
+
this.removeCloseListener?.();
|
|
171
|
+
this.removeCloseListener = undefined;
|
|
172
|
+
if (!this.stream.closed) {
|
|
173
|
+
this.stream.close();
|
|
174
|
+
}
|
|
175
|
+
} finally {
|
|
176
|
+
this.context.response.committed = true;
|
|
177
|
+
this.resolveCompletion();
|
|
160
178
|
}
|
|
161
|
-
this.context.response.committed = true;
|
|
162
179
|
}
|
|
163
180
|
writeFrame(frame) {
|
|
164
181
|
if (this.closed) {
|
|
165
182
|
return false;
|
|
166
183
|
}
|
|
167
184
|
if (this.stream.closed) {
|
|
185
|
+
markRequestContextAborted(this.context);
|
|
168
186
|
this.close();
|
|
169
187
|
return false;
|
|
170
188
|
}
|
|
171
189
|
return this.stream.write(frame);
|
|
172
190
|
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Resolves after a manual SSE response closes through any supported termination path.
|
|
195
|
+
*
|
|
196
|
+
* @param response Manual SSE response whose lifecycle is observed.
|
|
197
|
+
* @returns A promise that resolves after the response closes.
|
|
198
|
+
*
|
|
199
|
+
* @internal
|
|
200
|
+
*/
|
|
201
|
+
export function waitForSseResponseCompletion(response) {
|
|
202
|
+
return response.completion;
|
|
173
203
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { FrameworkResponse } from './types.js';
|
|
2
|
+
/** SameSite policies supported by the portable cookie serializer. */
|
|
3
|
+
export type CookieSameSite = 'lax' | 'none' | 'strict';
|
|
4
|
+
/** Runtime-neutral attributes used when serializing one response cookie. */
|
|
5
|
+
export interface CookieOptions {
|
|
6
|
+
/** Domain that scopes the cookie. */
|
|
7
|
+
readonly domain?: string;
|
|
8
|
+
/** Absolute expiry time for the cookie. */
|
|
9
|
+
readonly expires?: Date;
|
|
10
|
+
/** Whether the cookie is inaccessible to client-side scripts. */
|
|
11
|
+
readonly httpOnly?: boolean;
|
|
12
|
+
/** Lifetime in whole seconds. */
|
|
13
|
+
readonly maxAgeSeconds?: number;
|
|
14
|
+
/** URL path that scopes the cookie. */
|
|
15
|
+
readonly path?: string;
|
|
16
|
+
/** Cross-site request policy for the cookie. */
|
|
17
|
+
readonly sameSite?: CookieSameSite;
|
|
18
|
+
/** Whether the cookie is sent only over secure connections. */
|
|
19
|
+
readonly secure?: boolean;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Attributes accepted when clearing a cookie.
|
|
23
|
+
*
|
|
24
|
+
* Only `path` and `domain` identify the browser cookie to delete. `httpOnly`,
|
|
25
|
+
* `secure`, and `sameSite` are deletion attributes, not cookie identity keys.
|
|
26
|
+
*/
|
|
27
|
+
export type ClearCookieOptions = Omit<CookieOptions, 'expires' | 'maxAgeSeconds'>;
|
|
28
|
+
/**
|
|
29
|
+
* Serialize one runtime-neutral response cookie as an independent `Set-Cookie` field.
|
|
30
|
+
*
|
|
31
|
+
* @param response Mutable response that receives the cookie header.
|
|
32
|
+
* @param name Cookie name, validated as an HTTP token.
|
|
33
|
+
* @param value Cookie value, percent-encoded before serialization.
|
|
34
|
+
* @param options Explicit cookie attributes shared by all supported adapters.
|
|
35
|
+
* @returns Nothing. The response receives one independent cookie field.
|
|
36
|
+
*/
|
|
37
|
+
export declare function setCookie(response: FrameworkResponse, name: string, value: string, options?: CookieOptions): void;
|
|
38
|
+
/**
|
|
39
|
+
* Expire one runtime-neutral response cookie while retaining its matching scope attributes.
|
|
40
|
+
*
|
|
41
|
+
* @param response Mutable response that receives the deletion cookie header.
|
|
42
|
+
* @param name Cookie name, validated as an HTTP token.
|
|
43
|
+
* @param options Original Path and Domain attributes required to target the same cookie.
|
|
44
|
+
* @returns Nothing. The response receives one independent deletion cookie field.
|
|
45
|
+
*/
|
|
46
|
+
export declare function clearCookie(response: FrameworkResponse, name: string, options?: ClearCookieOptions): void;
|
|
47
|
+
//# sourceMappingURL=cookie-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cookie-helpers.d.ts","sourceRoot":"","sources":["../src/cookie-helpers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAMpD,qEAAqE;AACrE,MAAM,MAAM,cAAc,GAAG,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;AAEvD,4EAA4E;AAC5E,MAAM,WAAW,aAAa;IAC5B,qCAAqC;IACrC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,2CAA2C;IAC3C,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC;IACxB,iEAAiE;IACjE,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,iCAAiC;IACjC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,uCAAuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,gDAAgD;IAChD,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,CAAC;IACnC,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,IAAI,CAAC,aAAa,EAAE,SAAS,GAAG,eAAe,CAAC,CAAC;AA8KlF;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,aAAkB,GAC1B,IAAI,CAEN;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,iBAAiB,EAC3B,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,kBAAuB,GAC/B,IAAI,CAUN"}
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
const COOKIE_DELETION_EXPIRES = new Date(0);
|
|
2
|
+
const COOKIE_NAME_TOKEN = /^[!#$%&'*+\-.^_`|~0-9A-Za-z]+$/;
|
|
3
|
+
const COOKIE_DOMAIN = /^(?:\.)?(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)*[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?$/;
|
|
4
|
+
|
|
5
|
+
/** SameSite policies supported by the portable cookie serializer. */
|
|
6
|
+
|
|
7
|
+
/** Runtime-neutral attributes used when serializing one response cookie. */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Attributes accepted when clearing a cookie.
|
|
11
|
+
*
|
|
12
|
+
* Only `path` and `domain` identify the browser cookie to delete. `httpOnly`,
|
|
13
|
+
* `secure`, and `sameSite` are deletion attributes, not cookie identity keys.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
function readCookieOptions(options) {
|
|
17
|
+
const {
|
|
18
|
+
domain,
|
|
19
|
+
expires,
|
|
20
|
+
httpOnly,
|
|
21
|
+
maxAgeSeconds,
|
|
22
|
+
path,
|
|
23
|
+
sameSite,
|
|
24
|
+
secure
|
|
25
|
+
} = options;
|
|
26
|
+
return {
|
|
27
|
+
domain,
|
|
28
|
+
expires,
|
|
29
|
+
httpOnly,
|
|
30
|
+
maxAgeSeconds,
|
|
31
|
+
path,
|
|
32
|
+
sameSite,
|
|
33
|
+
secure
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function validateCookieName(name) {
|
|
37
|
+
if (typeof name !== 'string' || !COOKIE_NAME_TOKEN.test(name)) {
|
|
38
|
+
throw new TypeError('Cookie names must be non-empty HTTP tokens.');
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
function validateOptionalBoolean(value, optionName) {
|
|
42
|
+
if (value !== undefined && typeof value !== 'boolean') {
|
|
43
|
+
throw new TypeError(`${optionName} must be a boolean when provided.`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function validateDomain(domain) {
|
|
47
|
+
const host = domain.startsWith('.') ? domain.slice(1) : domain;
|
|
48
|
+
if (typeof domain !== 'string' || host.length === 0 || host.length > 253 || !COOKIE_DOMAIN.test(domain)) {
|
|
49
|
+
throw new TypeError('Cookie domains must be valid ASCII DNS names.');
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function validatePath(path) {
|
|
53
|
+
if (typeof path !== 'string' || path.length === 0) {
|
|
54
|
+
throw new TypeError('Cookie paths must be non-empty RFC 6265 path values.');
|
|
55
|
+
}
|
|
56
|
+
for (const character of path) {
|
|
57
|
+
const codePoint = character.charCodeAt(0);
|
|
58
|
+
if (codePoint < 0x20 || codePoint === 0x3b || codePoint > 0x7e) {
|
|
59
|
+
throw new TypeError('Cookie paths must be RFC 6265 path values.');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function formatExpiry(expires) {
|
|
64
|
+
const timestamp = Date.prototype.getTime.call(expires);
|
|
65
|
+
if (!Number.isFinite(timestamp)) {
|
|
66
|
+
throw new TypeError('Cookie expiry must be a valid Date.');
|
|
67
|
+
}
|
|
68
|
+
const normalized = new Date(timestamp);
|
|
69
|
+
const year = normalized.getUTCFullYear();
|
|
70
|
+
if (year < 1601 || year > 9999) {
|
|
71
|
+
throw new TypeError('Cookie expiry must have a four-digit RFC 6265 year.');
|
|
72
|
+
}
|
|
73
|
+
return normalized.toUTCString();
|
|
74
|
+
}
|
|
75
|
+
function normalizeSameSite(sameSite, secure) {
|
|
76
|
+
if (sameSite === undefined) {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
switch (sameSite) {
|
|
80
|
+
case 'lax':
|
|
81
|
+
return 'Lax';
|
|
82
|
+
case 'strict':
|
|
83
|
+
return 'Strict';
|
|
84
|
+
case 'none':
|
|
85
|
+
if (secure !== true) {
|
|
86
|
+
throw new TypeError('SameSite=None cookies require secure: true.');
|
|
87
|
+
}
|
|
88
|
+
return 'None';
|
|
89
|
+
default:
|
|
90
|
+
throw new TypeError('sameSite must be lax, none, or strict.');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function serializeCookie(name, value, options) {
|
|
94
|
+
validateCookieName(name);
|
|
95
|
+
if (typeof value !== 'string') {
|
|
96
|
+
throw new TypeError('Cookie values must be strings.');
|
|
97
|
+
}
|
|
98
|
+
validateOptionalBoolean(options.httpOnly, 'httpOnly');
|
|
99
|
+
validateOptionalBoolean(options.secure, 'secure');
|
|
100
|
+
if (options.maxAgeSeconds !== undefined) {
|
|
101
|
+
if (typeof options.maxAgeSeconds !== 'number' || !Number.isSafeInteger(options.maxAgeSeconds) || options.maxAgeSeconds < 0) {
|
|
102
|
+
throw new TypeError('maxAgeSeconds must be a non-negative safe integer.');
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
if (options.domain !== undefined) {
|
|
106
|
+
validateDomain(options.domain);
|
|
107
|
+
}
|
|
108
|
+
if (options.path !== undefined) {
|
|
109
|
+
validatePath(options.path);
|
|
110
|
+
}
|
|
111
|
+
const sameSite = normalizeSameSite(options.sameSite, options.secure);
|
|
112
|
+
const encodedValue = encodeURIComponent(value);
|
|
113
|
+
const parts = [`${name}=${encodedValue}`];
|
|
114
|
+
if (options.maxAgeSeconds !== undefined) {
|
|
115
|
+
parts.push(`Max-Age=${options.maxAgeSeconds}`);
|
|
116
|
+
}
|
|
117
|
+
if (options.expires !== undefined) {
|
|
118
|
+
parts.push(`Expires=${formatExpiry(options.expires)}`);
|
|
119
|
+
}
|
|
120
|
+
if (options.path !== undefined) {
|
|
121
|
+
parts.push(`Path=${options.path}`);
|
|
122
|
+
}
|
|
123
|
+
if (options.domain !== undefined) {
|
|
124
|
+
parts.push(`Domain=${options.domain}`);
|
|
125
|
+
}
|
|
126
|
+
if (options.secure === true) {
|
|
127
|
+
parts.push('Secure');
|
|
128
|
+
}
|
|
129
|
+
if (options.httpOnly === true) {
|
|
130
|
+
parts.push('HttpOnly');
|
|
131
|
+
}
|
|
132
|
+
if (sameSite !== undefined) {
|
|
133
|
+
parts.push(`SameSite=${sameSite}`);
|
|
134
|
+
}
|
|
135
|
+
return parts.join('; ');
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Serialize one runtime-neutral response cookie as an independent `Set-Cookie` field.
|
|
140
|
+
*
|
|
141
|
+
* @param response Mutable response that receives the cookie header.
|
|
142
|
+
* @param name Cookie name, validated as an HTTP token.
|
|
143
|
+
* @param value Cookie value, percent-encoded before serialization.
|
|
144
|
+
* @param options Explicit cookie attributes shared by all supported adapters.
|
|
145
|
+
* @returns Nothing. The response receives one independent cookie field.
|
|
146
|
+
*/
|
|
147
|
+
export function setCookie(response, name, value, options = {}) {
|
|
148
|
+
response.setHeader('Set-Cookie', serializeCookie(name, value, readCookieOptions(options)));
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Expire one runtime-neutral response cookie while retaining its matching scope attributes.
|
|
153
|
+
*
|
|
154
|
+
* @param response Mutable response that receives the deletion cookie header.
|
|
155
|
+
* @param name Cookie name, validated as an HTTP token.
|
|
156
|
+
* @param options Original Path and Domain attributes required to target the same cookie.
|
|
157
|
+
* @returns Nothing. The response receives one independent deletion cookie field.
|
|
158
|
+
*/
|
|
159
|
+
export function clearCookie(response, name, options = {}) {
|
|
160
|
+
const values = readCookieOptions(options);
|
|
161
|
+
response.setHeader('Set-Cookie', serializeCookie(name, '', {
|
|
162
|
+
...values,
|
|
163
|
+
expires: COOKIE_DELETION_EXPIRES,
|
|
164
|
+
maxAgeSeconds: 0
|
|
165
|
+
}));
|
|
166
|
+
}
|
package/dist/decorators.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Constructor, MetadataPropertyKey } from '@fluojs/core';
|
|
2
2
|
import type { ConverterLike, GuardLike, InterceptorLike } from './types.js';
|
|
3
3
|
type StandardClassDecoratorFn = (value: Function, context: ClassDecoratorContext) => void;
|
|
4
4
|
type StandardMethodDecoratorFn = (value: Function, context: ClassMethodDecoratorContext) => void;
|
|
@@ -24,69 +24,90 @@ export declare function Version(version: string): ClassOrMethodDecoratorLike;
|
|
|
24
24
|
/**
|
|
25
25
|
* Registers a `GET` route handler.
|
|
26
26
|
*
|
|
27
|
-
* @param path
|
|
27
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
28
28
|
* @returns A method decorator that registers a `GET` handler mapping.
|
|
29
29
|
*/
|
|
30
|
-
export declare const Get: (path
|
|
30
|
+
export declare const Get: (path?: string) => MethodDecoratorLike;
|
|
31
31
|
/**
|
|
32
32
|
* Registers a server-sent events route handler as `GET` with `text/event-stream` produces metadata.
|
|
33
33
|
*
|
|
34
|
-
* @param path
|
|
34
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
35
35
|
* @returns A method decorator that registers a `GET` SSE handler mapping.
|
|
36
36
|
*
|
|
37
37
|
* @remarks
|
|
38
38
|
* Handlers may return `SseResponse` for manual control or `AsyncIterable<SseMessage<T> | T>` for managed dispatcher streaming.
|
|
39
39
|
*/
|
|
40
|
-
export declare const Sse: (path
|
|
40
|
+
export declare const Sse: (path?: string) => MethodDecoratorLike;
|
|
41
|
+
/**
|
|
42
|
+
* Registers a route handler for one validated HTTP method token.
|
|
43
|
+
*
|
|
44
|
+
* @param method HTTP method token, canonicalized to uppercase before metadata registration.
|
|
45
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
46
|
+
* @returns A method decorator that registers the method-specific handler mapping.
|
|
47
|
+
*
|
|
48
|
+
* @throws {InvalidHttpMethodError} When `method` is empty, contains non-token characters, or is the reserved `ALL` sentinel.
|
|
49
|
+
*
|
|
50
|
+
* @remarks
|
|
51
|
+
* Adapter wire support remains runtime-specific. `CONNECT` is outside ordinary routing conformance,
|
|
52
|
+
* and custom methods are not implied to be OpenAPI Path Item operations.
|
|
53
|
+
*/
|
|
54
|
+
export declare function Route(method: string, path?: string): MethodDecoratorLike;
|
|
55
|
+
/**
|
|
56
|
+
* Registers an RFC `QUERY` route handler.
|
|
57
|
+
*
|
|
58
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
59
|
+
* @returns A method decorator that registers a `QUERY` handler mapping.
|
|
60
|
+
*/
|
|
61
|
+
export declare const Query: (path?: string) => MethodDecoratorLike;
|
|
41
62
|
/**
|
|
42
63
|
* Registers a `POST` route handler.
|
|
43
64
|
*
|
|
44
|
-
* @param path
|
|
65
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
45
66
|
* @returns A method decorator that registers a `POST` handler mapping.
|
|
46
67
|
*/
|
|
47
|
-
export declare const Post: (path
|
|
68
|
+
export declare const Post: (path?: string) => MethodDecoratorLike;
|
|
48
69
|
/**
|
|
49
70
|
* Registers a `PUT` route handler.
|
|
50
71
|
*
|
|
51
|
-
* @param path
|
|
72
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
52
73
|
* @returns A method decorator that registers a `PUT` handler mapping.
|
|
53
74
|
*/
|
|
54
|
-
export declare const Put: (path
|
|
75
|
+
export declare const Put: (path?: string) => MethodDecoratorLike;
|
|
55
76
|
/**
|
|
56
77
|
* Registers a `PATCH` route handler.
|
|
57
78
|
*
|
|
58
|
-
* @param path
|
|
79
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
59
80
|
* @returns A method decorator that registers a `PATCH` handler mapping.
|
|
60
81
|
*/
|
|
61
|
-
export declare const Patch: (path
|
|
82
|
+
export declare const Patch: (path?: string) => MethodDecoratorLike;
|
|
62
83
|
/**
|
|
63
84
|
* Registers a `DELETE` route handler.
|
|
64
85
|
*
|
|
65
|
-
* @param path
|
|
86
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
66
87
|
* @returns A method decorator that registers a `DELETE` handler mapping.
|
|
67
88
|
*/
|
|
68
|
-
export declare const Delete: (path
|
|
89
|
+
export declare const Delete: (path?: string) => MethodDecoratorLike;
|
|
69
90
|
/**
|
|
70
91
|
* Registers an `OPTIONS` route handler.
|
|
71
92
|
*
|
|
72
|
-
* @param path
|
|
93
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
73
94
|
* @returns A method decorator that registers an `OPTIONS` handler mapping.
|
|
74
95
|
*/
|
|
75
|
-
export declare const Options: (path
|
|
96
|
+
export declare const Options: (path?: string) => MethodDecoratorLike;
|
|
76
97
|
/**
|
|
77
98
|
* Registers a `HEAD` route handler.
|
|
78
99
|
*
|
|
79
|
-
* @param path
|
|
100
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
80
101
|
* @returns A method decorator that registers a `HEAD` handler mapping.
|
|
81
102
|
*/
|
|
82
|
-
export declare const Head: (path
|
|
103
|
+
export declare const Head: (path?: string) => MethodDecoratorLike;
|
|
83
104
|
/**
|
|
84
105
|
* Registers a route handler that matches all HTTP methods.
|
|
85
106
|
*
|
|
86
|
-
* @param path
|
|
107
|
+
* @param path Relative route path; omission or `undefined` uses `''`, preserving the controller prefix.
|
|
87
108
|
* @returns A method decorator that registers an all-method handler mapping.
|
|
88
109
|
*/
|
|
89
|
-
export declare const All: (path
|
|
110
|
+
export declare const All: (path?: string) => MethodDecoratorLike;
|
|
90
111
|
/**
|
|
91
112
|
* Associates a DTO class used for request binding and validation.
|
|
92
113
|
*
|
|
@@ -151,6 +172,18 @@ export declare const FromCookie: (key?: string) => FieldDecoratorLike;
|
|
|
151
172
|
* @returns A field decorator that marks the binding source as `body`.
|
|
152
173
|
*/
|
|
153
174
|
export declare const FromBody: (key?: string) => FieldDecoratorLike;
|
|
175
|
+
/**
|
|
176
|
+
* Binds a DTO field from portable multipart files.
|
|
177
|
+
*
|
|
178
|
+
* The binding always yields a readonly array when the request exposes a file
|
|
179
|
+
* collection, preserving adapter order and filtering by the optional field name.
|
|
180
|
+
* An absent file collection remains absent so `@Optional()` can opt out of the
|
|
181
|
+
* normal required-field error.
|
|
182
|
+
*
|
|
183
|
+
* @param key Optional multipart field-name filter. Defaults to the DTO field name.
|
|
184
|
+
* @returns A field decorator that marks the binding source as `files`.
|
|
185
|
+
*/
|
|
186
|
+
export declare const FromFiles: (key?: string) => FieldDecoratorLike;
|
|
154
187
|
/**
|
|
155
188
|
* Marks a DTO field binding as optional.
|
|
156
189
|
*
|
package/dist/decorators.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"decorators.d.ts","sourceRoot":"","sources":["../src/decorators.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EACX,mBAAmB,EAEpB,MAAM,cAAc,CAAC;AAgBtB,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAc,eAAe,EAAE,MAAM,YAAY,CAAC;AAGxF,KAAK,wBAAwB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,qBAAqB,KAAK,IAAI,CAAC;AAC1F,KAAK,yBAAyB,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,2BAA2B,KAAK,IAAI,CAAC;AACjG,KAAK,wBAAwB,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,0BAA0B,CAAC,IAAI,EAAE,KAAK,CAAC,KAAK,IAAI,CAAC;AAI1H,KAAK,kBAAkB,GAAG,wBAAwB,CAAC;AACnD,KAAK,mBAAmB,GAAG,yBAAyB,CAAC;AACrD,KAAK,0BAA0B,GAAG,wBAAwB,GAAG,yBAAyB,CAAC;AACvF,KAAK,kBAAkB,GAAG,wBAAwB,CAAC;AA0VnD;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,QAAQ,SAAK,GAAG,kBAAkB,CAa5D;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,0BAA0B,CAuBnE;AAED;;;;;GAKG;AACH,eAAO,MAAM,GAAG,qBA/HM,mBA+HwB,CAAC;AAC/C;;;;;;;;GAQG;AACH,eAAO,MAAM,GAAG,qBAzIM,mBAyI+C,CAAC;AACtE;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,mBAAmB,CAEpE;AACD;;;;;GAKG;AACH,eAAO,MAAM,KAAK,GAAI,aAAS,KAAG,mBAA2C,CAAC;AAC9E;;;;;GAKG;AACH,eAAO,MAAM,IAAI,qBAvKK,mBAuK0B,CAAC;AACjD;;;;;GAKG;AACH,eAAO,MAAM,GAAG,qBA9KM,mBA8KwB,CAAC;AAC/C;;;;;GAKG;AACH,eAAO,MAAM,KAAK,qBArLI,mBAqL4B,CAAC;AACnD;;;;;GAKG;AACH,eAAO,MAAM,MAAM,qBA5LG,mBA4L8B,CAAC;AACrD;;;;;GAKG;AACH,eAAO,MAAM,OAAO,qBAnME,mBAmMgC,CAAC;AACvD;;;;;GAKG;AACH,eAAO,MAAM,IAAI,qBA1MK,mBA0M0B,CAAC;AACjD;;;;;GAKG;AACH,eAAO,MAAM,GAAG,qBAjNM,mBAiNwB,CAAC;AAE/C;;;;;GAKG;AACH,eAAO,MAAM,UAAU,0BA7LF,mBA+LnB,CAAC;AAEH;;;;;GAKG;AACH,wBAAgB,QAAQ,CAAC,GAAG,UAAU,EAAE,MAAM,EAAE,GAAG,mBAAmB,CAIrE;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,qBAnNA,mBAqNnB,CAAC;AAEH;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,WAAW,EAAE,WAAW,EAAE,mBAAmB,GAAG,MAAM,EAAE,GAAG,SAAS,CAM7H;AAED;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,SAzNL,MAAM,KAAG,kBAyN8B,CAAC;AACxD;;;;;GAKG;AACH,eAAO,MAAM,SAAS,SAhON,MAAM,KAAG,kBAgOgC,CAAC;AAC1D;;;;;GAKG;AACH,eAAO,MAAM,UAAU,SAvOP,MAAM,KAAG,kBAuOkC,CAAC;AAC5D;;;;;GAKG;AACH,eAAO,MAAM,UAAU,SA9OP,MAAM,KAAG,kBA8OkC,CAAC;AAC5D;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,SArPL,MAAM,KAAG,kBAqP8B,CAAC;AACxD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,SAAS,SAjQN,MAAM,KAAG,kBAiQgC,CAAC;AAE1D;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,kBAAkB,CAa7C;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,SAAS,EAAE,aAAa,GAAG,kBAAkB,CAapE;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,mBAAmB,CAcvE;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,mBAAmB,CAa9E;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,GAAG,MAAM,EAAE,SAAS,EAAE,GAAG,0BAA0B,CAyB5E;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,YAAY,EAAE,eAAe,EAAE,GAAG,0BAA0B,CAyB9F"}
|