@nifrajs/core 2.8.2 → 2.9.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/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/internal/route-execution.d.ts +8 -2
- package/dist/internal/route-execution.d.ts.map +1 -1
- package/dist/node-direct.d.ts.map +1 -1
- package/dist/node-direct.js +3 -1
- package/dist/node-direct.js.map +1 -1
- package/dist/router/router.d.ts.map +1 -1
- package/dist/router/router.js +9 -1
- package/dist/router/router.js.map +1 -1
- package/dist/server/context.d.ts +2 -0
- package/dist/server/context.d.ts.map +1 -1
- package/dist/server/cookies.d.ts.map +1 -1
- package/dist/server/cookies.js +4 -1
- package/dist/server/cookies.js.map +1 -1
- package/dist/server/http.d.ts.map +1 -1
- package/dist/server/http.js +16 -3
- package/dist/server/http.js.map +1 -1
- package/dist/server/node-outcome-hook.d.ts +78 -1
- package/dist/server/node-outcome-hook.d.ts.map +1 -1
- package/dist/server/node-outcome-hook.js +197 -1
- package/dist/server/node-outcome-hook.js.map +1 -1
- package/dist/server/node-outcome.d.ts +22 -2
- package/dist/server/node-outcome.d.ts.map +1 -1
- package/dist/server/node-outcome.js +86 -11
- package/dist/server/node-outcome.js.map +1 -1
- package/dist/server/query.d.ts +2 -0
- package/dist/server/query.d.ts.map +1 -1
- package/dist/server/query.js +27 -1
- package/dist/server/query.js.map +1 -1
- package/dist/server/request-context.d.ts +8 -1
- package/dist/server/request-context.d.ts.map +1 -1
- package/dist/server/request-context.js +23 -2
- package/dist/server/request-context.js.map +1 -1
- package/dist/server/respond.d.ts +29 -3
- package/dist/server/respond.d.ts.map +1 -1
- package/dist/server/respond.js +279 -16
- package/dist/server/respond.js.map +1 -1
- package/dist/server/response-contract-lane.d.ts +17 -3
- package/dist/server/response-contract-lane.d.ts.map +1 -1
- package/dist/server/response-contract-lane.js +6 -3
- package/dist/server/response-contract-lane.js.map +1 -1
- package/dist/server/server-types.d.ts +37 -0
- package/dist/server/server-types.d.ts.map +1 -1
- package/dist/server/server.d.ts +151 -7
- package/dist/server/server.d.ts.map +1 -1
- package/dist/server/server.js +1151 -173
- package/dist/server/server.js.map +1 -1
- package/dist/server/static-headers.d.ts +47 -0
- package/dist/server/static-headers.d.ts.map +1 -0
- package/dist/server/static-headers.js +109 -0
- package/dist/server/static-headers.js.map +1 -0
- package/dist/server.d.ts +2 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +1 -0
- package/dist/server.js.map +1 -1
- package/dist/transport-codec.d.ts +15 -0
- package/dist/transport-codec.d.ts.map +1 -1
- package/dist/transport-codec.js +49 -10
- package/dist/transport-codec.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +1 -1
- package/src/internal/route-execution.ts +19 -1
- package/src/node-direct.ts +7 -1
- package/src/router/router.ts +8 -1
- package/src/server/context.ts +2 -0
- package/src/server/cookies.ts +4 -1
- package/src/server/http.ts +16 -3
- package/src/server/node-outcome-hook.ts +315 -1
- package/src/server/node-outcome.ts +100 -14
- package/src/server/query.ts +26 -1
- package/src/server/request-context.ts +23 -1
- package/src/server/respond.ts +386 -17
- package/src/server/response-contract-lane.ts +17 -3
- package/src/server/server-types.ts +42 -0
- package/src/server/server.ts +1608 -236
- package/src/server/static-headers.ts +142 -0
- package/src/server.ts +9 -0
- package/src/transport-codec.ts +55 -10
|
@@ -1,2 +1,198 @@
|
|
|
1
|
-
|
|
1
|
+
/** Lazy Node-direct renderer seam. The base server retains the typed method but not its renderer. */
|
|
2
|
+
/**
|
|
3
|
+
* A {@link ResponseHeadersView} over a Node outcome's plain header record - the direct-writer
|
|
4
|
+
* counterpart of handing a Web hook the response's `Headers`. Mutations write lowercase names (the
|
|
5
|
+
* wire form every runtime emits) and reads are case-insensitive across whatever casing earlier
|
|
6
|
+
* writers used; repeated values join with `", "` on read, matching `Headers.get`. A class with
|
|
7
|
+
* prototype methods (not per-call closures), memoized per context, so a request running several
|
|
8
|
+
* portable hooks allocates ONE small view total.
|
|
9
|
+
*
|
|
10
|
+
* Name resolution is prepared ONCE, the first time this view touches the record, rather than per
|
|
11
|
+
* operation. Resolving each name by scanning the record - the straightforward way to stay
|
|
12
|
+
* case-insensitive - allocates an `Object.keys` array and lowercases every stored key on every
|
|
13
|
+
* get/set, and that is paid per header, so a middleware writing a handful of them (security
|
|
14
|
+
* headers, CORS) paid it several times per request: profiling a realistic Node route put that scan
|
|
15
|
+
* at roughly a fifth of the framework's own CPU time. Instead one pass records an alias only for
|
|
16
|
+
* keys whose casing differs from their lowercase form - none, for the records the framework itself
|
|
17
|
+
* builds - after which every operation is a direct property access and the common all-lowercase
|
|
18
|
+
* record allocates no index at all. Stored casing is left exactly as the writer chose it.
|
|
19
|
+
*/
|
|
20
|
+
class RecordHeadersView {
|
|
21
|
+
#target;
|
|
22
|
+
#prepared = false;
|
|
23
|
+
/** lowercase name -> the differently-cased key actually stored. Absent when none differ. */
|
|
24
|
+
#alias;
|
|
25
|
+
constructor(target) {
|
|
26
|
+
this.#target = target;
|
|
27
|
+
}
|
|
28
|
+
#prepare(record) {
|
|
29
|
+
this.#prepared = true;
|
|
30
|
+
// `Object.keys`, not `for...in`: the record is a `{}`-prototype literal on the render paths, and
|
|
31
|
+
// a for-in would let an enumerable `Object.prototype` property become a header on the wire.
|
|
32
|
+
const keys = Object.keys(record);
|
|
33
|
+
for (let i = 0; i < keys.length; i++) {
|
|
34
|
+
const key = keys[i];
|
|
35
|
+
// `key.toLowerCase() !== key` answers this too, but pays a runtime call plus a string compare
|
|
36
|
+
// for EVERY key on EVERY request, and the answer is almost always "already lowercase" - the
|
|
37
|
+
// framework, `c.set`, and middleware twins all write the wire spelling. An inline ASCII scan
|
|
38
|
+
// answers the common case without leaving the loop, and only a genuinely mixed-case key (a
|
|
39
|
+
// hand-written `X-Foo`) pays for the lowercase copy and the alias entry.
|
|
40
|
+
if (!RecordHeadersView.#hasUpperAscii(key))
|
|
41
|
+
continue;
|
|
42
|
+
if (this.#alias === undefined)
|
|
43
|
+
this.#alias = new Map();
|
|
44
|
+
this.#alias.set(key.toLowerCase(), key);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
/** True when the name contains an ASCII `A`-`Z`, i.e. is not already the wire spelling. */
|
|
48
|
+
static #hasUpperAscii(name) {
|
|
49
|
+
for (let i = 0; i < name.length; i++) {
|
|
50
|
+
const code = name.charCodeAt(i);
|
|
51
|
+
if (code >= 65 && code <= 90)
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
/** The wire spelling of a header name, without paying `toLowerCase` when it already is one. */
|
|
57
|
+
static #lower(name) {
|
|
58
|
+
return RecordHeadersView.#hasUpperAscii(name) ? name.toLowerCase() : name;
|
|
59
|
+
}
|
|
60
|
+
/** The stored key for an already-lowercased name. Resolution is the prepared index ONLY - a
|
|
61
|
+
* lowercase own-property check, then the alias map - never a per-operation key scan: a rescan on
|
|
62
|
+
* every miss (and setting a NEW header is always a miss) walked and lowercased the whole record
|
|
63
|
+
* per write, which measured as the single largest cost of a portable hook walk on JSC. The alias
|
|
64
|
+
* index is complete for the record as first touched and for every write made through this view;
|
|
65
|
+
* a raw record write from a custom native twin uses lowercase names (the wire form the record
|
|
66
|
+
* documents), so it stays visible without a scan. */
|
|
67
|
+
#actual(lower) {
|
|
68
|
+
const record = this.#target.headers;
|
|
69
|
+
if (record !== undefined && Object.hasOwn(record, lower))
|
|
70
|
+
return lower;
|
|
71
|
+
const known = this.#alias?.get(lower);
|
|
72
|
+
if (known !== undefined && record !== undefined && Object.hasOwn(record, known))
|
|
73
|
+
return known;
|
|
74
|
+
return lower;
|
|
75
|
+
}
|
|
76
|
+
/** The backing record if the outcome has one, prepared on first touch; `undefined` otherwise. */
|
|
77
|
+
#readable() {
|
|
78
|
+
const existing = this.#target.headers;
|
|
79
|
+
if (existing === undefined)
|
|
80
|
+
return undefined;
|
|
81
|
+
if (!this.#prepared)
|
|
82
|
+
this.#prepare(existing);
|
|
83
|
+
return existing;
|
|
84
|
+
}
|
|
85
|
+
/** As {@link #readable}, but creates the record when the outcome has none. A literal record from
|
|
86
|
+
* the render path is used AS-IS - values are strings/arrays, and assigning those through the
|
|
87
|
+
* inherited `__proto__` setter is a spec-level no-op, so the record cannot be polluted through
|
|
88
|
+
* this view; the one name that setter would swallow is stored via `defineProperty` in
|
|
89
|
+
* {@link set}/{@link append} instead. Copying to a null-prototype object here would demote every
|
|
90
|
+
* hook-carrying request's record to V8's dictionary mode (~2% of route throughput). */
|
|
91
|
+
#writable() {
|
|
92
|
+
const existing = this.#target.headers;
|
|
93
|
+
if (existing === undefined) {
|
|
94
|
+
const fresh = {};
|
|
95
|
+
this.#target.headers = fresh;
|
|
96
|
+
this.#prepared = true;
|
|
97
|
+
return fresh;
|
|
98
|
+
}
|
|
99
|
+
if (!this.#prepared)
|
|
100
|
+
this.#prepare(existing);
|
|
101
|
+
return existing;
|
|
102
|
+
}
|
|
103
|
+
/** Store under an attacker-influenceable name. `__proto__` (any casing is already lowercased)
|
|
104
|
+
* must not go through plain assignment - the inherited setter would silently swallow it - so it
|
|
105
|
+
* is defined as an own data property; every other name takes the fast plain store. */
|
|
106
|
+
static #store(record, lower, value) {
|
|
107
|
+
if (lower === "__proto__") {
|
|
108
|
+
Object.defineProperty(record, lower, {
|
|
109
|
+
value,
|
|
110
|
+
writable: true,
|
|
111
|
+
enumerable: true,
|
|
112
|
+
configurable: true,
|
|
113
|
+
});
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
record[lower] = value;
|
|
117
|
+
}
|
|
118
|
+
get(name) {
|
|
119
|
+
const headers = this.#readable();
|
|
120
|
+
if (headers === undefined)
|
|
121
|
+
return null;
|
|
122
|
+
const value = headers[this.#actual(RecordHeadersView.#lower(name))];
|
|
123
|
+
if (value === undefined)
|
|
124
|
+
return null;
|
|
125
|
+
return typeof value === "string" ? value : (value.join(", ") ?? null);
|
|
126
|
+
}
|
|
127
|
+
has(name) {
|
|
128
|
+
const headers = this.#readable();
|
|
129
|
+
return (headers !== undefined && headers[this.#actual(RecordHeadersView.#lower(name))] !== undefined);
|
|
130
|
+
}
|
|
131
|
+
set(name, value) {
|
|
132
|
+
const headers = this.#writable();
|
|
133
|
+
const lower = RecordHeadersView.#lower(name);
|
|
134
|
+
// The common response record is already lowercase (framework middleware and c.set use the wire
|
|
135
|
+
// spelling). A set cannot need to replace a differently-cased key in that shape, so skip the
|
|
136
|
+
// own-property/alias lookup that reads and deletes pay for. Mixed-case records were indexed by
|
|
137
|
+
// #prepare and retain the full case-insensitive replacement semantics below.
|
|
138
|
+
if (this.#alias === undefined) {
|
|
139
|
+
RecordHeadersView.#store(headers, lower, value);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
const actual = this.#actual(lower);
|
|
143
|
+
if (actual !== lower) {
|
|
144
|
+
delete headers[actual];
|
|
145
|
+
this.#alias?.delete(lower);
|
|
146
|
+
}
|
|
147
|
+
RecordHeadersView.#store(headers, lower, value);
|
|
148
|
+
}
|
|
149
|
+
append(name, value) {
|
|
150
|
+
const headers = this.#writable();
|
|
151
|
+
const lower = RecordHeadersView.#lower(name);
|
|
152
|
+
if (this.#alias === undefined) {
|
|
153
|
+
const current = Object.hasOwn(headers, lower) ? headers[lower] : undefined;
|
|
154
|
+
if (current === undefined) {
|
|
155
|
+
RecordHeadersView.#store(headers, lower, value);
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
RecordHeadersView.#store(headers, lower, typeof current === "string" ? [current, value] : [...current, value]);
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const actual = this.#actual(lower);
|
|
162
|
+
const current = Object.hasOwn(headers, actual) ? headers[actual] : undefined;
|
|
163
|
+
if (current === undefined) {
|
|
164
|
+
RecordHeadersView.#store(headers, lower, value);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (actual !== lower) {
|
|
168
|
+
delete headers[actual];
|
|
169
|
+
this.#alias?.delete(lower);
|
|
170
|
+
}
|
|
171
|
+
RecordHeadersView.#store(headers, lower, typeof current === "string" ? [current, value] : [...current, value]);
|
|
172
|
+
}
|
|
173
|
+
delete(name) {
|
|
174
|
+
const headers = this.#readable();
|
|
175
|
+
if (headers === undefined)
|
|
176
|
+
return;
|
|
177
|
+
const lower = RecordHeadersView.#lower(name);
|
|
178
|
+
if (this.#alias === undefined) {
|
|
179
|
+
delete headers[lower];
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const actual = this.#actual(lower);
|
|
183
|
+
delete headers[actual];
|
|
184
|
+
if (actual !== lower)
|
|
185
|
+
this.#alias?.delete(lower);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
const RECORD_VIEW = Symbol("nifra.record-headers-view");
|
|
189
|
+
export function recordHeadersView(target) {
|
|
190
|
+
const holder = target;
|
|
191
|
+
let view = holder[RECORD_VIEW];
|
|
192
|
+
if (view === undefined) {
|
|
193
|
+
view = new RecordHeadersView(target);
|
|
194
|
+
holder[RECORD_VIEW] = view;
|
|
195
|
+
}
|
|
196
|
+
return view;
|
|
197
|
+
}
|
|
2
198
|
//# sourceMappingURL=node-outcome-hook.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-outcome-hook.js","sourceRoot":"","sources":["../../src/server/node-outcome-hook.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"node-outcome-hook.js","sourceRoot":"","sources":["../../src/server/node-outcome-hook.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type HandlerResult } from "./runtime-core.js";
|
|
2
2
|
import type { CtxSet } from "./server.js";
|
|
3
|
+
import { type StaticResponseHeaders } from "./static-headers.js";
|
|
3
4
|
/**
|
|
4
5
|
* What {@link Server.resolveNode} returns: either a plain-data render the `@nifrajs/node` adapter writes
|
|
5
6
|
* to the socket directly (`kind: "json"` - status + headers + cookies + a pre-stringified body, **no**
|
|
@@ -13,8 +14,8 @@ export type NodeServeOutcome = {
|
|
|
13
14
|
} | {
|
|
14
15
|
readonly kind: "json";
|
|
15
16
|
readonly status: number;
|
|
16
|
-
/**
|
|
17
|
-
readonly headers: Readonly<Record<string, string>> | undefined;
|
|
17
|
+
/** Header record after native hooks; repeated values are retained as arrays. */
|
|
18
|
+
readonly headers: Readonly<Record<string, string | readonly string[]>> | undefined;
|
|
18
19
|
/** Queued `Set-Cookie` lines, or `undefined`; the adapter emits one header line each. */
|
|
19
20
|
readonly cookies: readonly string[] | undefined;
|
|
20
21
|
/** The JSON body already stringified, or `null` for an empty (204) response. */
|
|
@@ -33,5 +34,24 @@ export type NodeServeOutcome = {
|
|
|
33
34
|
* works on Node).
|
|
34
35
|
*/
|
|
35
36
|
export declare function toNodeOutcome(result: HandlerResult, set: CtxSet): NodeServeOutcome;
|
|
37
|
+
/**
|
|
38
|
+
* Materialize a buffered node outcome only when a Web `onResponse` hook needs to see a real
|
|
39
|
+
* `Response`. The marker lets an in-place hook (`response.headers.set(...); return response`) go back
|
|
40
|
+
* to the direct socket writer without draining the body through a Web stream. A hook that replaces,
|
|
41
|
+
* consumes, or otherwise changes the response naturally loses the marker and stays on the portable
|
|
42
|
+
* response path.
|
|
43
|
+
*/
|
|
44
|
+
export declare function nodeOutcomeToResponse(outcome: NodeServeOutcome): Response;
|
|
45
|
+
/**
|
|
46
|
+
* Fold declared static headers into a resolved outcome, ONCE, before any native response hook runs -
|
|
47
|
+
* so a header or body twin sees the declared values through its view exactly as it would see values
|
|
48
|
+
* a hook had written, and so the no-hook direct-writer path (which never calls the finish step) still
|
|
49
|
+
* ships them.
|
|
50
|
+
*
|
|
51
|
+
* The record handed over is always a fresh copy: the Node writers mutate the outcome's record in
|
|
52
|
+
* place (content-type, content-length, cookies), and the static record is shared by every request.
|
|
53
|
+
* Its names are already lowercase, so the writer's all-lowercase fast path still holds.
|
|
54
|
+
*/
|
|
55
|
+
export declare function withStaticNodeHeaders(outcome: NodeServeOutcome, statics: StaticResponseHeaders): NodeServeOutcome;
|
|
36
56
|
export declare function nodeOutcomeFromResponse(response: Response): NodeServeOutcome;
|
|
37
57
|
//# sourceMappingURL=node-outcome.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-outcome.d.ts","sourceRoot":"","sources":["../../src/server/node-outcome.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"node-outcome.d.ts","sourceRoot":"","sources":["../../src/server/node-outcome.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,KAAK,aAAa,EAAoB,MAAM,mBAAmB,CAAA;AACxE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AACzC,OAAO,EAEL,KAAK,qBAAqB,EAE3B,MAAM,qBAAqB,CAAA;AAM5B;;;;;;GAMG;AACH,MAAM,MAAM,gBAAgB,GACxB;IAAE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAA;CAAE,GAC1D;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,gFAAgF;IAChF,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IAClF,yFAAyF;IACzF,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAA;IAC/C,gFAAgF;IAChF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAA;CAC7B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC,CAAC,GAAG,SAAS,CAAA;IAClF,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;CACnC,CAAA;AAEL;;;;;;GAMG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,gBAAgB,CA2BlF;AAED;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,gBAAgB,GAAG,QAAQ,CAmCzE;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,gBAAgB,EACzB,OAAO,EAAE,qBAAqB,GAC7B,gBAAgB,CAUlB;AAED,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,QAAQ,GAAG,gBAAgB,CAM5E"}
|
|
@@ -3,8 +3,12 @@
|
|
|
3
3
|
* conversion. Mirrors `respond.ts` but skips the undici `Response` build where the adapter can write a
|
|
4
4
|
* plain-data render straight to the socket. Imports only runtime-core + respond + the spine types.
|
|
5
5
|
*/
|
|
6
|
-
import { appendCookiesToResponse } from "./respond.js";
|
|
6
|
+
import { appendCookiesToResponse, applyStaticResponseHeaders, markTaggedResponse, normalizeBodylessResponse, rememberMutableHeaders, taggedResponseBody, } from "./respond.js";
|
|
7
7
|
import { isResponseResult } from "./runtime-core.js";
|
|
8
|
+
import { mergeStaticHeaderRecord, staticHeaderRecordCopy, } from "./static-headers.js";
|
|
9
|
+
function isBodylessStatus(status) {
|
|
10
|
+
return status === 204 || status === 205 || status === 304;
|
|
11
|
+
}
|
|
8
12
|
/**
|
|
9
13
|
* `finalize` for the node-direct path - mirror of `toResponse` that skips the `Response` build:
|
|
10
14
|
* a plain value becomes pre-stringified JSON primitives (the adapter `JSON.stringify`s once, here, not
|
|
@@ -20,25 +24,95 @@ export function toNodeOutcome(result, set) {
|
|
|
20
24
|
kind: "body",
|
|
21
25
|
status: body.status,
|
|
22
26
|
headers: appendCookiesToNodeHeaders(body.headers, set._cookies),
|
|
23
|
-
body: body.body,
|
|
27
|
+
body: isBodylessStatus(body.status) ? new Uint8Array(0) : body.body,
|
|
24
28
|
};
|
|
25
29
|
}
|
|
26
|
-
return nodeOutcomeFromResponse(appendCookiesToResponse(result.toResponse(), set));
|
|
30
|
+
return nodeOutcomeFromResponse(appendCookiesToResponse(normalizeBodylessResponse(result.toResponse()), set));
|
|
27
31
|
}
|
|
28
32
|
if (result instanceof Response) {
|
|
29
|
-
return nodeOutcomeFromResponse(appendCookiesToResponse(result, set));
|
|
33
|
+
return nodeOutcomeFromResponse(appendCookiesToResponse(normalizeBodylessResponse(result), set));
|
|
30
34
|
}
|
|
31
35
|
const status = set.status ?? (result === undefined ? 204 : 200);
|
|
36
|
+
const body = result === undefined || isBodylessStatus(status) ? null : JSON.stringify(result);
|
|
32
37
|
return {
|
|
33
38
|
kind: "json",
|
|
34
39
|
status,
|
|
35
40
|
headers: set._headers,
|
|
36
41
|
cookies: set._cookies,
|
|
37
|
-
body
|
|
42
|
+
body,
|
|
38
43
|
};
|
|
39
44
|
}
|
|
40
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Materialize a buffered node outcome only when a Web `onResponse` hook needs to see a real
|
|
47
|
+
* `Response`. The marker lets an in-place hook (`response.headers.set(...); return response`) go back
|
|
48
|
+
* to the direct socket writer without draining the body through a Web stream. A hook that replaces,
|
|
49
|
+
* consumes, or otherwise changes the response naturally loses the marker and stays on the portable
|
|
50
|
+
* response path.
|
|
51
|
+
*/
|
|
52
|
+
export function nodeOutcomeToResponse(outcome) {
|
|
53
|
+
if (outcome.kind === "response")
|
|
54
|
+
return outcome.response;
|
|
55
|
+
// A prebuilt `Headers` on purpose: undici's Response constructor takes a fast clone path for a
|
|
56
|
+
// `Headers` instance, which measured cheaper than handing it a pairs list to fill (pairs pay a
|
|
57
|
+
// webidl sequence conversion per entry).
|
|
58
|
+
const headers = new Headers();
|
|
59
|
+
if (outcome.headers !== undefined) {
|
|
60
|
+
for (const [name, value] of Object.entries(outcome.headers)) {
|
|
61
|
+
if (typeof value !== "string") {
|
|
62
|
+
for (const item of value)
|
|
63
|
+
headers.append(name, item);
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
headers.set(name, value);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (outcome.kind === "json") {
|
|
71
|
+
if (outcome.cookies !== undefined) {
|
|
72
|
+
for (const cookie of outcome.cookies)
|
|
73
|
+
headers.append("set-cookie", cookie);
|
|
74
|
+
}
|
|
75
|
+
if (outcome.body !== null && headers.get("content-type") === null) {
|
|
76
|
+
headers.set("content-type", "application/json;charset=utf-8");
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
if (isBodylessStatus(outcome.status))
|
|
80
|
+
headers.delete("content-length");
|
|
81
|
+
const body = isBodylessStatus(outcome.status) ? null : outcome.body;
|
|
82
|
+
// `Uint8Array<ArrayBufferLike>` vs the lib's body-init generic - runtime-accepted everywhere,
|
|
83
|
+
// only the type narrows wrong under the DOM-free lib set (same idiom as the Headers cast in
|
|
84
|
+
// transport-codec.ts).
|
|
85
|
+
const response = new Response(body, {
|
|
86
|
+
status: outcome.status,
|
|
87
|
+
headers,
|
|
88
|
+
});
|
|
89
|
+
if (body !== null)
|
|
90
|
+
markTaggedResponse(response, body);
|
|
91
|
+
rememberMutableHeaders(response.headers);
|
|
92
|
+
return response;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Fold declared static headers into a resolved outcome, ONCE, before any native response hook runs -
|
|
96
|
+
* so a header or body twin sees the declared values through its view exactly as it would see values
|
|
97
|
+
* a hook had written, and so the no-hook direct-writer path (which never calls the finish step) still
|
|
98
|
+
* ships them.
|
|
99
|
+
*
|
|
100
|
+
* The record handed over is always a fresh copy: the Node writers mutate the outcome's record in
|
|
101
|
+
* place (content-type, content-length, cookies), and the static record is shared by every request.
|
|
102
|
+
* Its names are already lowercase, so the writer's all-lowercase fast path still holds.
|
|
103
|
+
*/
|
|
104
|
+
export function withStaticNodeHeaders(outcome, statics) {
|
|
105
|
+
if (outcome.kind === "response") {
|
|
106
|
+
return { kind: "response", response: applyStaticResponseHeaders(outcome.response, statics) };
|
|
107
|
+
}
|
|
108
|
+
const own = outcome.headers;
|
|
109
|
+
const headers = own === undefined
|
|
110
|
+
? staticHeaderRecordCopy(statics)
|
|
111
|
+
: mergeStaticHeaderRecord(statics.record, own);
|
|
112
|
+
return { ...outcome, headers };
|
|
113
|
+
}
|
|
41
114
|
export function nodeOutcomeFromResponse(response) {
|
|
115
|
+
response = normalizeBodylessResponse(response);
|
|
42
116
|
const body = nodeResponseBody(response);
|
|
43
117
|
return body === undefined
|
|
44
118
|
? { kind: "response", response }
|
|
@@ -47,18 +121,17 @@ export function nodeOutcomeFromResponse(response) {
|
|
|
47
121
|
function nodeResponseBody(response) {
|
|
48
122
|
if (response.bodyUsed)
|
|
49
123
|
return undefined;
|
|
50
|
-
|
|
51
|
-
return typeof body === "string" || body instanceof Uint8Array ? body : undefined;
|
|
124
|
+
return taggedResponseBody(response);
|
|
52
125
|
}
|
|
53
126
|
function responseHeadersForNode(response) {
|
|
54
127
|
let headers;
|
|
55
128
|
response.headers.forEach((value, key) => {
|
|
56
|
-
headers ??=
|
|
129
|
+
headers ??= Object.create(null);
|
|
57
130
|
headers[key] = value;
|
|
58
131
|
});
|
|
59
132
|
const setCookies = response.headers.getSetCookie?.();
|
|
60
133
|
if (setCookies !== undefined && setCookies.length > 0) {
|
|
61
|
-
headers ??=
|
|
134
|
+
headers ??= Object.create(null);
|
|
62
135
|
headers["set-cookie"] = setCookies;
|
|
63
136
|
}
|
|
64
137
|
return headers;
|
|
@@ -66,7 +139,9 @@ function responseHeadersForNode(response) {
|
|
|
66
139
|
function appendCookiesToNodeHeaders(headers, cookies) {
|
|
67
140
|
if (cookies === undefined || cookies.length === 0)
|
|
68
141
|
return headers;
|
|
69
|
-
const out =
|
|
142
|
+
const out = Object.create(null);
|
|
143
|
+
if (headers !== undefined)
|
|
144
|
+
Object.assign(out, headers);
|
|
70
145
|
const existing = out["set-cookie"];
|
|
71
146
|
const setCookies = existing === undefined ? [] : typeof existing === "string" ? [existing] : [...existing];
|
|
72
147
|
out["set-cookie"] = [...setCookies, ...cookies];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node-outcome.js","sourceRoot":"","sources":["../../src/server/node-outcome.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,
|
|
1
|
+
{"version":3,"file":"node-outcome.js","sourceRoot":"","sources":["../../src/server/node-outcome.ts"],"names":[],"mappings":"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"}
|
package/dist/server/query.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export declare function searchOf(url: string): string;
|
|
|
6
6
|
* `t.string()` schemas are untouched; a repeated key against a string schema now FAILS validation
|
|
7
7
|
* (an explicit 400 beats silently picking one). */
|
|
8
8
|
export type QueryValue = string | string[];
|
|
9
|
+
/** Return a value-equal, likely-internalized copy of a parsed record key. See the note above. */
|
|
10
|
+
export declare function internParseKey(key: string): string;
|
|
9
11
|
export declare function queryObjectOf(search: string): Record<string, QueryValue>;
|
|
10
12
|
/** `application/x-www-form-urlencoded`, with or without a charset suffix. */
|
|
11
13
|
export declare function isUrlEncodedForm(contentType: string): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/server/query.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;mDAImD;AACnD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/server/query.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAMhD,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;;;mDAImD;AACnD,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,EAAE,CAAA;AAgB1C,iGAAiG;AACjG,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAOlD;AAsCD,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAyBxE;AAED,6EAA6E;AAC7E,wBAAgB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAK7D;AAID;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,CAchD"}
|
package/dist/server/query.js
CHANGED
|
@@ -12,11 +12,37 @@ import { jsonError, urlPartsOf } from "./http.js";
|
|
|
12
12
|
export function searchOf(url) {
|
|
13
13
|
return urlPartsOf(url).search;
|
|
14
14
|
}
|
|
15
|
+
// V8 stores a FRESHLY-SLICED string key on a dictionary-mode (null-prototype) record ~13x slower
|
|
16
|
+
// than an already-internalized one - the store internalizes the fresh string every time (measured
|
|
17
|
+
// ~300ns vs ~22ns for a literal key; it was the single largest slice of query parsing on Node).
|
|
18
|
+
// JSC has no such cliff (~2.5ns either way), so the whole scheme is bypassed there. Interning
|
|
19
|
+
// repeated keys through a small bounded map hands every later request the SAME first-seen (and by
|
|
20
|
+
// then internalized) string, so the store takes the fast path. Query/cookie key sets in a real app
|
|
21
|
+
// are tiny and stable; a hostile high-cardinality caller stops being cached at the cap and an
|
|
22
|
+
// oversized key never enters, so both degrade to exactly today's uncached behavior - the returned
|
|
23
|
+
// key is always value-equal to the input, cached or not.
|
|
24
|
+
const FRESH_KEY_STORE_IS_CHEAP = typeof globalThis.Bun !== "undefined";
|
|
25
|
+
const PARSE_KEY_INTERN = new Map();
|
|
26
|
+
const PARSE_KEY_INTERN_CAP = 2048;
|
|
27
|
+
const PARSE_KEY_MAX_LENGTH = 64;
|
|
28
|
+
/** Return a value-equal, likely-internalized copy of a parsed record key. See the note above. */
|
|
29
|
+
export function internParseKey(key) {
|
|
30
|
+
if (FRESH_KEY_STORE_IS_CHEAP)
|
|
31
|
+
return key;
|
|
32
|
+
const hit = PARSE_KEY_INTERN.get(key);
|
|
33
|
+
if (hit !== undefined)
|
|
34
|
+
return hit;
|
|
35
|
+
if (key.length > PARSE_KEY_MAX_LENGTH || PARSE_KEY_INTERN.size >= PARSE_KEY_INTERN_CAP)
|
|
36
|
+
return key;
|
|
37
|
+
PARSE_KEY_INTERN.set(key, key);
|
|
38
|
+
return key;
|
|
39
|
+
}
|
|
15
40
|
/** Accumulate into a NULL-PROTOTYPE record (every call site below creates one): with no inherited
|
|
16
41
|
* `constructor`/`toString`/`__proto__` accessors, a hostile key is just an own data key - the
|
|
17
42
|
* promotion logic can't collide with `Object.prototype` members, and `__proto__` needs no special
|
|
18
43
|
* case (direct assignment on a null-proto object creates an own property). */
|
|
19
|
-
function setQueryValue(out,
|
|
44
|
+
function setQueryValue(out, rawKey, value) {
|
|
45
|
+
const key = internParseKey(rawKey);
|
|
20
46
|
const existing = out[key];
|
|
21
47
|
if (existing === undefined) {
|
|
22
48
|
out[key] = value;
|
package/dist/server/query.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/server/query.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAC5C,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAGjD,+FAA+F;AAC/F,oGAAoG;AACpG,oGAAoG;AACpG,2DAA2D;AAC3D,MAAM,UAAU,QAAQ,CAAC,GAAW;IAClC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,MAAM,CAAA;AAC/B,CAAC;AASD;;;8EAG8E;AAC9E,SAAS,aAAa,CAAC,GAA+B,EAAE,
|
|
1
|
+
{"version":3,"file":"query.js","sourceRoot":"","sources":["../../src/server/query.ts"],"names":[],"mappings":"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"}
|
|
@@ -23,7 +23,13 @@ export declare class RequestContext implements RawContext {
|
|
|
23
23
|
private readonly maxBodyBytes;
|
|
24
24
|
constructor(source: RequestSource, params: Record<string, string>, maxBodyBytes: number);
|
|
25
25
|
constructor(source: RequestSource, params: Record<string, string>, search: string | undefined, signal: AbortSignal, budget: RequestBudget, platform: Platform | undefined, maxBodyBytes: number);
|
|
26
|
-
|
|
26
|
+
/**
|
|
27
|
+
* The no-timeout context: `c.signal`/`c.budget` fall back to the never-abort signal and the
|
|
28
|
+
* unbounded budget, which is exactly what the request would have been handed, so the two slots
|
|
29
|
+
* are left unwritten instead of initialized. `search` carries the router's already-split query
|
|
30
|
+
* string when it has one; `undefined` leaves `c.query` to re-scan the URL lazily.
|
|
31
|
+
*/
|
|
32
|
+
static native(source: RequestSource, params: Record<string, string>, search: string | undefined, maxBodyBytes: number, platform?: Platform): RequestContext;
|
|
27
33
|
[CONTEXT_SET](): CtxSet | undefined;
|
|
28
34
|
get [CONTEXT_SEARCH](): string;
|
|
29
35
|
get set(): CtxSet;
|
|
@@ -34,6 +40,7 @@ export declare class RequestContext implements RawContext {
|
|
|
34
40
|
get waitUntil(): (promise: Promise<unknown>) => void;
|
|
35
41
|
get req(): Request;
|
|
36
42
|
get request(): Request;
|
|
43
|
+
header(name: string): string | null;
|
|
37
44
|
json(body: unknown, init?: ResponseInit | number): Response;
|
|
38
45
|
text(body: string, init?: ResponseInit | number): Response;
|
|
39
46
|
get query(): unknown;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAA;AAEjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAA;AAI5C,OAAO,EACL,cAAc,EACd,WAAW,EAOZ,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"request-context.d.ts","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,6 +11,13 @@ class LazyResponseControls {
|
|
|
11
11
|
_headers;
|
|
12
12
|
_cookies;
|
|
13
13
|
get headers() {
|
|
14
|
+
// A plain literal record on purpose: values here are strings, and assigning a STRING through
|
|
15
|
+
// the inherited `__proto__` setter is a silent no-op by spec - it cannot mutate the record's
|
|
16
|
+
// prototype - so a literal object is not pollutable through header writes. The trade is that a
|
|
17
|
+
// header literally named "__proto__" is dropped rather than stored (the sinks that accept
|
|
18
|
+
// attacker-influenced names guard that name explicitly); in exchange the record stays in V8's
|
|
19
|
+
// fast property mode, which a null-prototype object never enters - measured at ~2% of
|
|
20
|
+
// throughput on a realistic middleware route on BOTH V8 and JSC.
|
|
14
21
|
this._headers ??= {};
|
|
15
22
|
return this._headers;
|
|
16
23
|
}
|
|
@@ -52,8 +59,19 @@ export class RequestContext {
|
|
|
52
59
|
this.platformValue = platform;
|
|
53
60
|
this.maxBodyBytes = maxBodyBytes;
|
|
54
61
|
}
|
|
55
|
-
|
|
56
|
-
|
|
62
|
+
/**
|
|
63
|
+
* The no-timeout context: `c.signal`/`c.budget` fall back to the never-abort signal and the
|
|
64
|
+
* unbounded budget, which is exactly what the request would have been handed, so the two slots
|
|
65
|
+
* are left unwritten instead of initialized. `search` carries the router's already-split query
|
|
66
|
+
* string when it has one; `undefined` leaves `c.query` to re-scan the URL lazily.
|
|
67
|
+
*/
|
|
68
|
+
static native(source, params, search, maxBodyBytes, platform) {
|
|
69
|
+
const context = new RequestContext(source, params, maxBodyBytes);
|
|
70
|
+
if (search !== undefined)
|
|
71
|
+
context.searchValue = search;
|
|
72
|
+
if (platform !== undefined)
|
|
73
|
+
context.platformValue = platform;
|
|
74
|
+
return context;
|
|
57
75
|
}
|
|
58
76
|
[CONTEXT_SET]() {
|
|
59
77
|
return this.setValue;
|
|
@@ -89,6 +107,9 @@ export class RequestContext {
|
|
|
89
107
|
get request() {
|
|
90
108
|
return requestOf(this.source);
|
|
91
109
|
}
|
|
110
|
+
header(name) {
|
|
111
|
+
return headerOf(this.source, name);
|
|
112
|
+
}
|
|
92
113
|
json(body, init) {
|
|
93
114
|
return Response.json(body, statusInit(init));
|
|
94
115
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAA;AAE7E,OAAO,EAAsB,YAAY,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAChF,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAA;AACrC,OAAO,EACL,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,yBAAyB,EACzB,QAAQ,EACR,SAAS,EACT,YAAY,GACb,MAAM,mBAAmB,CAAA;AAG1B;2BAC2B;AAC3B,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAA;AAEzB,MAAM,oBAAoB;IACxB,MAAM,CAAS;IACf,QAAQ,CAAyB;IACjC,QAAQ,CAAW;IAEnB,IAAI,OAAO;QACT,IAAI,CAAC,QAAQ,KAAK,EAAE,CAAA;QACpB,OAAO,IAAI,CAAC,QAAQ,CAAA;IACtB,CAAC;IAED,MAAM,CAAC,IAAY,EAAE,KAAa,EAAE,OAAuB;QACzD,sFAAsF;QACtF,MAAM,MAAM,GAAkB;YAC5B,QAAQ,EAAE,IAAI;YACd,MAAM,EAAE,IAAI;YACZ,QAAQ,EAAE,KAAK;YACf,IAAI,EAAE,GAAG;YACT,GAAG,OAAO;SACX,CAAA;QACD,IAAI,CAAC,QAAQ,KAAK,EAAE,CAAA;QACpB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAA;IAC1D,CAAC;IAED,YAAY,CAAC,IAAY,EAAE,OAAgD;QACzE,kGAAkG;QAClG,IAAI,CAAC,QAAQ,KAAK,EAAE,CAAA;QACpB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAChB,eAAe,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,GAAG,OAAO,EAAE,MAAM,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAChF,CAAA;IACH,CAAC;CACF;AAED,0GAA0G;AAC1G,SAAS,UAAU,CAAC,IAA4B;IAC9C,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAA;AAC3D,CAAC;AAED,MAAM,OAAO,cAAc;IA6BzB,YACE,MAAqB,EACrB,MAA8B,EAC9B,oBAAiD,EACjD,MAAoB,EACpB,MAAsB,EACtB,QAAmB,EACnB,YAAqB;QAErB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAA;QACpB,IAAI,OAAO,oBAAoB,KAAK,QAAQ,EAAE,CAAC;YAC7C,IAAI,CAAC,YAAY,GAAG,oBAAoB,CAAA;YACxC,OAAM;QACR,CAAC;QACD,IAAI,oBAAoB,KAAK,SAAS;YAAE,IAAI,CAAC,WAAW,GAAG,oBAAoB,CAAA;QAC/E,IAAI,CAAC,WAAW,GAAG,MAAM,CAAA;QACzB,IAAI,CAAC,WAAW,GAAG,MAAM,CAAA;QACzB,IAAI,QAAQ,KAAK,SAAS;YAAE,IAAI,CAAC,aAAa,GAAG,QAAQ,CAAA;QACzD,IAAI,CAAC,YAAY,GAAG,YAAsB,CAAA;IAC5C,CAAC;IAED,MAAM,CAAC,MAAM,CACX,MAAqB,EACrB,MAA8B,EAC9B,YAAoB;
|
|
1
|
+
{"version":3,"file":"request-context.js","sourceRoot":"","sources":["../../src/server/request-context.ts"],"names":[],"mappings":"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"}
|