@solidjs/web 2.0.0-rc.4 → 2.0.0-rc.5
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/dev.cjs +52 -7
- package/dist/dev.js +51 -8
- package/dist/server.cjs +162 -35
- package/dist/server.js +161 -36
- package/dist/web.cjs +32 -7
- package/dist/web.js +31 -8
- package/frames/dist/client.cjs +41 -8
- package/frames/dist/client.dev.cjs +41 -8
- package/frames/dist/client.dev.js +41 -8
- package/frames/dist/client.js +41 -8
- package/frames/dist/server.cjs +432 -44
- package/frames/dist/server.js +432 -44
- package/package.json +2 -2
- package/serialization/dist/decode.cjs +4 -2
- package/serialization/dist/decode.js +4 -2
- package/serialization/dist/serialization.cjs +12 -8
- package/serialization/dist/serialization.js +12 -8
- package/serialization/types/index.d.ts +7 -0
- package/serialization/types/serializer-decode.d.ts +14 -1
- package/serialization/types/serializer.d.ts +7 -0
- package/serialization/types-cjs/index.d.cts +7 -0
- package/serialization/types-cjs/serializer-decode.d.cts +14 -1
- package/serialization/types-cjs/serializer.d.cts +7 -0
- package/server-functions/dist/client.cjs +150 -33
- package/server-functions/dist/client.js +147 -34
- package/server-functions/dist/server.cjs +731 -118
- package/server-functions/dist/server.dev.cjs +751 -118
- package/server-functions/dist/server.dev.js +747 -119
- package/server-functions/dist/server.js +727 -119
- package/types/cookies.d.ts +6 -14
- package/types/frames/frame-client.d.ts +4 -0
- package/types/frames/serializer-decode.d.ts +14 -1
- package/types/frames/serializer.d.ts +7 -0
- package/types/jsx.d.ts +11 -16
- package/types/response.d.ts +11 -0
- package/types/serializer-decode.d.ts +14 -1
- package/types/serializer.d.ts +7 -0
- package/types/server-functions/client.d.ts +22 -2
- package/types/server-functions/flash.d.ts +9 -0
- package/types/server-functions/server.d.ts +58 -9
- package/types/server-functions/shared.d.ts +77 -14
- package/types/server-mock.d.ts +17 -2
- package/types/server.d.ts +16 -2
- package/types-cjs/cookies.d.cts +6 -14
- package/types-cjs/frames/frame-client.d.cts +4 -0
- package/types-cjs/frames/serializer-decode.d.cts +14 -1
- package/types-cjs/frames/serializer.d.cts +7 -0
- package/types-cjs/jsx.d.cts +11 -16
- package/types-cjs/response.d.cts +11 -0
- package/types-cjs/serializer-decode.d.cts +14 -1
- package/types-cjs/serializer.d.cts +7 -0
- package/types-cjs/server-functions/client.d.cts +22 -2
- package/types-cjs/server-functions/flash.d.cts +9 -0
- package/types-cjs/server-functions/server.d.cts +58 -9
- package/types-cjs/server-functions/shared.d.cts +77 -14
- package/types-cjs/server-mock.d.cts +17 -2
- package/types-cjs/server.d.cts +16 -2
|
@@ -11,6 +11,8 @@ function isSafeError(value) {
|
|
|
11
11
|
return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
|
|
12
12
|
}
|
|
13
13
|
const REVALIDATE_HEADER = "X-Revalidate";
|
|
14
|
+
const RESPONSE_HEADER_VALUE_LIMIT = 4096;
|
|
15
|
+
const NULL_BODY_STATUSES = new Set([204, 205, 304]);
|
|
14
16
|
|
|
15
17
|
const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
|
|
16
18
|
function getServerFunctionMetadata(fn) {
|
|
@@ -90,6 +92,7 @@ function serializeCookie(name, value, options = {}) {
|
|
|
90
92
|
if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
|
|
91
93
|
if (options.httpOnly) cookie += "; HttpOnly";
|
|
92
94
|
if (options.secure) cookie += "; Secure";
|
|
95
|
+
if (options.partitioned) cookie += "; Partitioned";
|
|
93
96
|
if (options.sameSite) {
|
|
94
97
|
const sameSite = options.sameSite.toLowerCase();
|
|
95
98
|
cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
|
|
@@ -114,8 +117,23 @@ function configureServerFunctionsCodec(codec) {
|
|
|
114
117
|
function getServerFunctionsCodec() {
|
|
115
118
|
return codecConfig.codec;
|
|
116
119
|
}
|
|
117
|
-
|
|
120
|
+
const UNNAMED_FLIGHT_SOURCE = "true";
|
|
121
|
+
const flightConfig = {
|
|
122
|
+
consumers: new Map()
|
|
123
|
+
};
|
|
124
|
+
function assertFlightSource(source) {
|
|
125
|
+
if (source === UNNAMED_FLIGHT_SOURCE || source === "" || source.includes(",")) {
|
|
126
|
+
throw new TypeError(`Invalid flight data source id "${source}": ids ride the ` + `${SINGLE_FLIGHT_HEADER} header as a comma-separated list, and "true" is ` + `reserved for the unnamed registration (the bare consumer/hook signatures).`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function subscribeFlightData(sourceOrConsumer, maybeConsumer) {
|
|
130
|
+
const named = typeof sourceOrConsumer === "string";
|
|
131
|
+
if (named) assertFlightSource(sourceOrConsumer);
|
|
132
|
+
const source = named ? sourceOrConsumer : UNNAMED_FLIGHT_SOURCE;
|
|
133
|
+
const consumer = named ? maybeConsumer : sourceOrConsumer;
|
|
134
|
+
flightConfig.consumers.set(source, consumer);
|
|
118
135
|
return () => {
|
|
136
|
+
if (flightConfig.consumers.get(source) === consumer) flightConfig.consumers.delete(source);
|
|
119
137
|
};
|
|
120
138
|
}
|
|
121
139
|
function serverFunctionAddress(endpoint, id) {
|
|
@@ -127,10 +145,18 @@ function parseServerFunctionAddress(pathname, endpoint) {
|
|
|
127
145
|
if (!pathname.startsWith(mount)) return null;
|
|
128
146
|
const rest = pathname.slice(mount.length);
|
|
129
147
|
if (!rest.startsWith("/")) return null;
|
|
130
|
-
|
|
148
|
+
let segment = rest.slice(1);
|
|
149
|
+
let data = false;
|
|
150
|
+
if (segment.startsWith("data/")) {
|
|
151
|
+
segment = segment.slice(5);
|
|
152
|
+
data = true;
|
|
153
|
+
}
|
|
131
154
|
if (!segment || segment.includes("/")) return null;
|
|
132
155
|
try {
|
|
133
|
-
return
|
|
156
|
+
return {
|
|
157
|
+
id: decodeURIComponent(segment),
|
|
158
|
+
data
|
|
159
|
+
};
|
|
134
160
|
} catch {
|
|
135
161
|
return null;
|
|
136
162
|
}
|
|
@@ -162,6 +188,28 @@ function decodeErrorHeaderValue(value) {
|
|
|
162
188
|
}
|
|
163
189
|
const INSTANCE_HEADER = "X-Server-Function-Instance";
|
|
164
190
|
const BODY_FORMAT_HEADER = "X-Server-Function-Format";
|
|
191
|
+
const UNKNOWN_HEADER = "X-Server-Function-Unknown";
|
|
192
|
+
const REDIRECT_HEADER = "X-Server-Function-Redirect";
|
|
193
|
+
function decodeRedirectHeaderValue(value) {
|
|
194
|
+
if (typeof value !== "string") return undefined;
|
|
195
|
+
const at = value.indexOf(" ");
|
|
196
|
+
if (at < 0) return undefined;
|
|
197
|
+
const status = Number(value.slice(0, at));
|
|
198
|
+
const url = value.slice(at + 1);
|
|
199
|
+
if (!Number.isInteger(status) || !url) return undefined;
|
|
200
|
+
if (status !== 301 && status !== 302 && status !== 303 && status !== 307 && status !== 308) return undefined;
|
|
201
|
+
let parsed;
|
|
202
|
+
try {
|
|
203
|
+
parsed = new URL(url);
|
|
204
|
+
} catch {
|
|
205
|
+
return undefined;
|
|
206
|
+
}
|
|
207
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return undefined;
|
|
208
|
+
return {
|
|
209
|
+
status,
|
|
210
|
+
url
|
|
211
|
+
};
|
|
212
|
+
}
|
|
165
213
|
const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
|
|
166
214
|
const FILE_FORM_KEY = "__server_function_file__";
|
|
167
215
|
const BodyFormat = {
|
|
@@ -204,7 +252,11 @@ function isJSONSafe(value) {
|
|
|
204
252
|
const proto = Object.getPrototypeOf(v);
|
|
205
253
|
if (proto !== Object.prototype && proto !== null) return false;
|
|
206
254
|
if (Symbol.asyncIterator in v || Symbol.iterator in v) return false;
|
|
207
|
-
for (const k in v)
|
|
255
|
+
for (const k in v) {
|
|
256
|
+
const descriptor = Object.getOwnPropertyDescriptor(v, k);
|
|
257
|
+
if (descriptor === undefined || !("value" in descriptor)) return false;
|
|
258
|
+
stack.push(descriptor.value);
|
|
259
|
+
}
|
|
208
260
|
}
|
|
209
261
|
}
|
|
210
262
|
return true;
|
|
@@ -313,18 +365,34 @@ function createChunk(data) {
|
|
|
313
365
|
class ChunkReader {
|
|
314
366
|
constructor(stream) {
|
|
315
367
|
this.reader = stream.getReader();
|
|
316
|
-
this.
|
|
368
|
+
this.store = new Uint8Array(0);
|
|
369
|
+
this.buffer = this.store;
|
|
317
370
|
this.done = false;
|
|
318
371
|
}
|
|
319
372
|
async readChunk() {
|
|
320
373
|
const chunk = await this.reader.read();
|
|
321
|
-
if (
|
|
322
|
-
const newBuffer = new Uint8Array(this.buffer.length + chunk.value.length);
|
|
323
|
-
newBuffer.set(this.buffer);
|
|
324
|
-
newBuffer.set(chunk.value, this.buffer.length);
|
|
325
|
-
this.buffer = newBuffer;
|
|
326
|
-
} else {
|
|
374
|
+
if (chunk.done) {
|
|
327
375
|
this.done = true;
|
|
376
|
+
return;
|
|
377
|
+
}
|
|
378
|
+
const incoming = chunk.value;
|
|
379
|
+
const store = this.store;
|
|
380
|
+
const start = this.buffer.byteOffset;
|
|
381
|
+
const end = start + this.buffer.length;
|
|
382
|
+
const needed = this.buffer.length + incoming.length;
|
|
383
|
+
if (end + incoming.length <= store.length) {
|
|
384
|
+
store.set(incoming, end);
|
|
385
|
+
this.buffer = store.subarray(start, end + incoming.length);
|
|
386
|
+
} else if (needed <= store.length) {
|
|
387
|
+
store.copyWithin(0, start, end);
|
|
388
|
+
store.set(incoming, this.buffer.length);
|
|
389
|
+
this.buffer = store.subarray(0, needed);
|
|
390
|
+
} else {
|
|
391
|
+
const grown = new Uint8Array(Math.max(needed, store.length * 2));
|
|
392
|
+
grown.set(this.buffer);
|
|
393
|
+
grown.set(incoming, this.buffer.length);
|
|
394
|
+
this.store = grown;
|
|
395
|
+
this.buffer = grown.subarray(0, needed);
|
|
328
396
|
}
|
|
329
397
|
}
|
|
330
398
|
async next() {
|
|
@@ -366,6 +434,27 @@ class ChunkReader {
|
|
|
366
434
|
}
|
|
367
435
|
}
|
|
368
436
|
}
|
|
437
|
+
const ERROR_TRAILER_PREFIX = "!";
|
|
438
|
+
function encodeErrorTrailer(error) {
|
|
439
|
+
const shaped = error instanceof Error ? error : new Error(String(error));
|
|
440
|
+
return ERROR_TRAILER_PREFIX + JSON.stringify(shaped.name && shaped.name !== "Error" ? {
|
|
441
|
+
name: shaped.name,
|
|
442
|
+
message: shaped.message
|
|
443
|
+
} : {
|
|
444
|
+
message: shaped.message
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
function errorFromTrailer(payload) {
|
|
448
|
+
let shape;
|
|
449
|
+
try {
|
|
450
|
+
shape = JSON.parse(payload.slice(1));
|
|
451
|
+
} catch {
|
|
452
|
+
shape = null;
|
|
453
|
+
}
|
|
454
|
+
const error = new Error(shape && typeof shape.message === "string" ? shape.message : "Server function result could not be delivered.");
|
|
455
|
+
if (shape && typeof shape.name === "string") error.name = shape.name;
|
|
456
|
+
return error;
|
|
457
|
+
}
|
|
369
458
|
async function deserializeStream(source, codecOptions) {
|
|
370
459
|
if (!source.body) {
|
|
371
460
|
throw new Error("missing body");
|
|
@@ -373,11 +462,17 @@ async function deserializeStream(source, codecOptions) {
|
|
|
373
462
|
const reader = new ChunkReader(source.body);
|
|
374
463
|
const result = await reader.next();
|
|
375
464
|
if (!result.done) {
|
|
465
|
+
if (result.value.startsWith(ERROR_TRAILER_PREFIX)) {
|
|
466
|
+
throw errorFromTrailer(result.value);
|
|
467
|
+
}
|
|
376
468
|
const {
|
|
377
469
|
createJSONDeserializer
|
|
378
470
|
} = await import('@solidjs/web/serialization/decode');
|
|
379
471
|
const deserializeChunk = createJSONDeserializer(codecOptions);
|
|
380
472
|
function interpretChunk(chunk) {
|
|
473
|
+
if (chunk.startsWith(ERROR_TRAILER_PREFIX)) {
|
|
474
|
+
throw errorFromTrailer(chunk);
|
|
475
|
+
}
|
|
381
476
|
return deserializeChunk(JSON.parse(chunk));
|
|
382
477
|
}
|
|
383
478
|
reader.drain(interpretChunk).then(() => deserializeChunk.abort(new Error("Server function stream ended unexpectedly.")), error => deserializeChunk.abort(error));
|
|
@@ -441,7 +536,7 @@ function copyInitHeaders(init) {
|
|
|
441
536
|
for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
|
|
442
537
|
return headers;
|
|
443
538
|
}
|
|
444
|
-
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
|
|
539
|
+
const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location"].map(header => header.toLowerCase()));
|
|
445
540
|
function fillsStubGap(key, headers, response) {
|
|
446
541
|
if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
|
|
447
542
|
if (response.body === null && (key === "content-type" || key === "content-length")) return false;
|
|
@@ -457,24 +552,16 @@ function commitEventResponse(response, event = getRequestEvent()) {
|
|
|
457
552
|
if (fillsStubGap(key, response.headers, response)) hasGaps = true;
|
|
458
553
|
});
|
|
459
554
|
if (!cookies.length && !hasGaps) return response;
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if (fillsStubGap(key, headers, response)) headers.set(key, value);
|
|
471
|
-
});
|
|
472
|
-
return new Response(response.body, {
|
|
473
|
-
status: response.status,
|
|
474
|
-
statusText: response.statusText,
|
|
475
|
-
headers
|
|
476
|
-
});
|
|
477
|
-
}
|
|
555
|
+
const headers = copyInitHeaders(response.headers);
|
|
556
|
+
for (const cookie of cookies) headers.append("Set-Cookie", cookie);
|
|
557
|
+
stub.headers.forEach((value, key) => {
|
|
558
|
+
if (fillsStubGap(key, headers, response)) headers.set(key, value);
|
|
559
|
+
});
|
|
560
|
+
return new Response(response.body, {
|
|
561
|
+
status: response.status,
|
|
562
|
+
statusText: response.statusText,
|
|
563
|
+
headers
|
|
564
|
+
});
|
|
478
565
|
}
|
|
479
566
|
|
|
480
567
|
function encodeInputValue(value) {
|
|
@@ -506,11 +593,35 @@ function encodeFlashCookie(url, result, input, thrown) {
|
|
|
506
593
|
thrown: !!thrown,
|
|
507
594
|
input: input.map(encodeInputValue)
|
|
508
595
|
};
|
|
596
|
+
if (fitsCookie(payload)) return flashCookie(payload);
|
|
597
|
+
payload.truncated = true;
|
|
598
|
+
payload.input = [];
|
|
599
|
+
if (!fitsCookie(payload)) {
|
|
600
|
+
if (typeof payload.result === "string") {
|
|
601
|
+
let prefix = payload.result;
|
|
602
|
+
while (prefix.length > 0 && !fitsCookie({
|
|
603
|
+
...payload,
|
|
604
|
+
result: prefix
|
|
605
|
+
})) {
|
|
606
|
+
prefix = prefix.slice(0, prefix.length >> 1);
|
|
607
|
+
}
|
|
608
|
+
payload.result = prefix.length > 0 ? prefix : true;
|
|
609
|
+
} else {
|
|
610
|
+
payload.result = true;
|
|
611
|
+
}
|
|
612
|
+
}
|
|
613
|
+
return flashCookie(payload);
|
|
614
|
+
}
|
|
615
|
+
function flashCookie(payload) {
|
|
509
616
|
return serializeCookie(FLASH_COOKIE, JSON.stringify(payload), {
|
|
510
617
|
secure: true,
|
|
511
618
|
httpOnly: true
|
|
512
619
|
});
|
|
513
620
|
}
|
|
621
|
+
const COOKIE_PAIR_BUDGET = 4000;
|
|
622
|
+
function fitsCookie(payload) {
|
|
623
|
+
return FLASH_COOKIE.length + 1 + encodeURIComponent(JSON.stringify(payload)).length <= COOKIE_PAIR_BUDGET;
|
|
624
|
+
}
|
|
514
625
|
function decodeFlashCookie(cookieHeader) {
|
|
515
626
|
const match = parseCookieHeader(cookieHeader)[FLASH_COOKIE];
|
|
516
627
|
if (!match) return;
|
|
@@ -518,12 +629,14 @@ function decodeFlashCookie(cookieHeader) {
|
|
|
518
629
|
const payload = JSON.parse(match);
|
|
519
630
|
if (!payload || !payload.result) return;
|
|
520
631
|
const result = payload.error ? new Error(payload.result) : payload.result;
|
|
521
|
-
|
|
632
|
+
const submission = {
|
|
522
633
|
input: Array.isArray(payload.input) ? payload.input.map(decodeInputValue) : [],
|
|
523
634
|
url: payload.url,
|
|
524
635
|
result: payload.thrown ? undefined : result,
|
|
525
636
|
error: payload.thrown ? result : undefined
|
|
526
637
|
};
|
|
638
|
+
if (payload.truncated) submission.truncated = true;
|
|
639
|
+
return submission;
|
|
527
640
|
} catch (error) {
|
|
528
641
|
console.error(error);
|
|
529
642
|
}
|
|
@@ -538,7 +651,9 @@ const config = {
|
|
|
538
651
|
transformDirectResult: undefined,
|
|
539
652
|
handleNoJS: undefined,
|
|
540
653
|
endpoint: "/_server",
|
|
541
|
-
csrf: true
|
|
654
|
+
csrf: true,
|
|
655
|
+
bodySizeLimit: 1_048_576,
|
|
656
|
+
maxArguments: 1000
|
|
542
657
|
};
|
|
543
658
|
function configureServerFunctionsServer({
|
|
544
659
|
provideEvent,
|
|
@@ -550,7 +665,9 @@ function configureServerFunctionsServer({
|
|
|
550
665
|
handleNoJS,
|
|
551
666
|
endpoint,
|
|
552
667
|
csrf,
|
|
553
|
-
codec
|
|
668
|
+
codec,
|
|
669
|
+
bodySizeLimit,
|
|
670
|
+
maxArguments
|
|
554
671
|
} = {}) {
|
|
555
672
|
if (provideEvent !== undefined) config.provideEvent = provideEvent;
|
|
556
673
|
if (wrapInvocation !== undefined) config.wrapInvocation = wrapInvocation;
|
|
@@ -562,6 +679,16 @@ function configureServerFunctionsServer({
|
|
|
562
679
|
if (endpoint !== undefined) config.endpoint = endpoint;
|
|
563
680
|
if (csrf !== undefined) config.csrf = csrf;
|
|
564
681
|
if (codec !== undefined) configureServerFunctionsCodec(codec);
|
|
682
|
+
if (bodySizeLimit !== undefined) config.bodySizeLimit = bodySizeLimit;
|
|
683
|
+
if (maxArguments !== undefined) config.maxArguments = maxArguments;
|
|
684
|
+
}
|
|
685
|
+
const flightSources = new Map();
|
|
686
|
+
function registerFlightDataSource(source, hook) {
|
|
687
|
+
assertFlightSource(source);
|
|
688
|
+
flightSources.set(source, hook);
|
|
689
|
+
return () => {
|
|
690
|
+
if (flightSources.get(source) === hook) flightSources.delete(source);
|
|
691
|
+
};
|
|
565
692
|
}
|
|
566
693
|
function provideEvent(event, fn) {
|
|
567
694
|
if (config.provideEvent) return config.provideEvent(event, fn);
|
|
@@ -583,6 +710,7 @@ function provideRPC() {
|
|
|
583
710
|
}
|
|
584
711
|
function registerServerFunction(id, callback) {
|
|
585
712
|
provideRPC();
|
|
713
|
+
if (REGISTRATIONS.get(id) !== callback) METHODS.delete(id);
|
|
586
714
|
REGISTRATIONS.set(id, callback);
|
|
587
715
|
return callback;
|
|
588
716
|
}
|
|
@@ -656,7 +784,10 @@ function createServerReference({
|
|
|
656
784
|
const ogEvt = getRequestEvent();
|
|
657
785
|
if (!ogEvt) throw new Error("Cannot call server function outside of a request");
|
|
658
786
|
const evt = {
|
|
659
|
-
...ogEvt
|
|
787
|
+
...ogEvt,
|
|
788
|
+
locals: {
|
|
789
|
+
...ogEvt.locals
|
|
790
|
+
}
|
|
660
791
|
};
|
|
661
792
|
INVOCATIONS.set(evt, {
|
|
662
793
|
id
|
|
@@ -727,15 +858,67 @@ function getServerFunctionInvocation() {
|
|
|
727
858
|
function getEventServerFunctionInvocation(event) {
|
|
728
859
|
return event && INVOCATIONS.get(event);
|
|
729
860
|
}
|
|
730
|
-
function
|
|
861
|
+
function resolveAddress(url) {
|
|
731
862
|
return parseServerFunctionAddress(url.pathname, config.endpoint);
|
|
732
863
|
}
|
|
733
|
-
|
|
864
|
+
const DECODE_DEPTH_LIMIT = 64;
|
|
865
|
+
function assertDecodeDepth(value) {
|
|
866
|
+
let level = [value];
|
|
867
|
+
for (let depth = 0; level.length > 0; depth++) {
|
|
868
|
+
if (depth > DECODE_DEPTH_LIMIT) {
|
|
869
|
+
throw new TypeError("Server function arguments exceed the decode depth limit");
|
|
870
|
+
}
|
|
871
|
+
const next = [];
|
|
872
|
+
for (const node of level) {
|
|
873
|
+
if (node === null || typeof node !== "object") continue;
|
|
874
|
+
if (Array.isArray(node)) {
|
|
875
|
+
for (const child of node) next.push(child);
|
|
876
|
+
} else {
|
|
877
|
+
for (const key of Object.keys(node)) next.push(node[key]);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
level = next;
|
|
881
|
+
}
|
|
882
|
+
}
|
|
883
|
+
async function bufferBodyWithin(request, limit) {
|
|
884
|
+
const reader = request.clone().body.getReader();
|
|
885
|
+
const chunks = [];
|
|
886
|
+
let total = 0;
|
|
887
|
+
for (;;) {
|
|
888
|
+
const {
|
|
889
|
+
done,
|
|
890
|
+
value
|
|
891
|
+
} = await reader.read();
|
|
892
|
+
if (done) break;
|
|
893
|
+
total += value.byteLength;
|
|
894
|
+
if (total > limit) {
|
|
895
|
+
reader.cancel().catch(() => {});
|
|
896
|
+
return null;
|
|
897
|
+
}
|
|
898
|
+
chunks.push(value);
|
|
899
|
+
}
|
|
900
|
+
const body = new Uint8Array(total);
|
|
901
|
+
let offset = 0;
|
|
902
|
+
for (const chunk of chunks) {
|
|
903
|
+
body.set(chunk, offset);
|
|
904
|
+
offset += chunk.byteLength;
|
|
905
|
+
}
|
|
906
|
+
return new Request(request, {
|
|
907
|
+
body
|
|
908
|
+
});
|
|
909
|
+
}
|
|
910
|
+
async function parseArguments(request, url, scripted, codec) {
|
|
734
911
|
const parsed = [];
|
|
735
912
|
const bodyFormat = request.method === "POST" ? request.headers.get(BODY_FORMAT_HEADER) : null;
|
|
736
913
|
const args = url.searchParams.get("args");
|
|
737
|
-
if (args && (!
|
|
738
|
-
|
|
914
|
+
if (args && (!scripted || request.method === "GET" || bodyFormat !== BodyFormat.Serialized)) {
|
|
915
|
+
let result;
|
|
916
|
+
if (args.startsWith(";0x")) {
|
|
917
|
+
result = await deserializeString(args, codec);
|
|
918
|
+
} else {
|
|
919
|
+
result = JSON.parse(args);
|
|
920
|
+
assertDecodeDepth(result);
|
|
921
|
+
}
|
|
739
922
|
if (!Array.isArray(result)) {
|
|
740
923
|
throw new TypeError("Server function arguments must encode an array");
|
|
741
924
|
}
|
|
@@ -748,18 +931,34 @@ async function parseArguments(request, url, instance, codec) {
|
|
|
748
931
|
if (request.method === "POST" && request.body !== null) {
|
|
749
932
|
const decoded = await extractBody(request.clone(), codec);
|
|
750
933
|
if (bodyFormat === BodyFormat.Serialized || bodyFormat === BodyFormat.Json) {
|
|
934
|
+
if (bodyFormat === BodyFormat.Json) assertDecodeDepth(decoded);
|
|
935
|
+
if (!Array.isArray(decoded)) {
|
|
936
|
+
throw new TypeError("Server function arguments must encode an array");
|
|
937
|
+
}
|
|
751
938
|
return decoded;
|
|
752
939
|
}
|
|
940
|
+
if (decoded === undefined) {
|
|
941
|
+
throw new TypeError("Server function body carries no usable encoding");
|
|
942
|
+
}
|
|
753
943
|
parsed.push(decoded);
|
|
754
944
|
}
|
|
755
945
|
return parsed;
|
|
756
946
|
}
|
|
757
|
-
async function foldFlightData(
|
|
947
|
+
async function foldFlightData(hooks, event, headers, outcome, context = {}) {
|
|
758
948
|
if (outcome.value instanceof Response && outcome.value.body) return outcome.value;
|
|
759
949
|
digestOutcome(event, outcome);
|
|
760
|
-
const
|
|
761
|
-
|
|
762
|
-
|
|
950
|
+
const folded = [];
|
|
951
|
+
for (const [source, hook] of hooks) {
|
|
952
|
+
try {
|
|
953
|
+
const slice = await hook(event, outcome);
|
|
954
|
+
if (slice !== undefined) folded.push([source, slice]);
|
|
955
|
+
} catch (error) {
|
|
956
|
+
console.error(`Error collecting flight data for source "${source}"`, error);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
if (folded.length === 0) return outcome.value;
|
|
960
|
+
const data = Object.fromEntries(folded);
|
|
961
|
+
headers.set(SINGLE_FLIGHT_HEADER, folded.map(([source]) => source).join(","));
|
|
763
962
|
if (context.transformFlightResult) {
|
|
764
963
|
const transformed = await context.transformFlightResult(event, {
|
|
765
964
|
value: outcome.value,
|
|
@@ -848,6 +1047,52 @@ function mergeResponseHeaders(target, source) {
|
|
|
848
1047
|
}
|
|
849
1048
|
}
|
|
850
1049
|
const validRedirectStatuses = new Set([301, 302, 303, 307, 308]);
|
|
1050
|
+
function maskRedirect(headers, response, requestUrl) {
|
|
1051
|
+
const target = response.headers && response.headers.get("Location");
|
|
1052
|
+
if (target) {
|
|
1053
|
+
headers.set(REDIRECT_HEADER, `${response.status} ${new URL(target, requestUrl)}`);
|
|
1054
|
+
}
|
|
1055
|
+
headers.delete("Location");
|
|
1056
|
+
}
|
|
1057
|
+
const BOUNDED_COMPOSED_HEADERS = [REDIRECT_HEADER, "Location", REVALIDATE_HEADER];
|
|
1058
|
+
function refusedTargetScheme(target) {
|
|
1059
|
+
const match = /^[a-zA-Z][a-zA-Z0-9+.-]*:/.exec(target);
|
|
1060
|
+
return match !== null && !/^https?:$/i.test(match[0]);
|
|
1061
|
+
}
|
|
1062
|
+
function enforceComposedHeaderInvariants(response) {
|
|
1063
|
+
for (const name of BOUNDED_COMPOSED_HEADERS) {
|
|
1064
|
+
const value = response.headers.get(name);
|
|
1065
|
+
if (value === null) continue;
|
|
1066
|
+
if (value.length > RESPONSE_HEADER_VALUE_LIMIT) {
|
|
1067
|
+
return refuseComposedHeader(response, name, `${name} response header refused at ${value.length} characters`, DEV ? `The ${name} response header is ${value.length} characters; past ` + `${RESPONSE_HEADER_VALUE_LIMIT} it would overflow receivers (an 8 KiB proxy ` + `buffer holds the whole header block) and the response dies at the socket after ` + `the mutation committed. Refused rather than trimmed: a cut redirect target is a ` + `different address, a dropped revalidate key is a silently stale cache. The ` + `redirect()/reload() helpers enforce this bound with the full reasoning at the ` + `call site.` : null);
|
|
1068
|
+
}
|
|
1069
|
+
if (name === REVALIDATE_HEADER) continue;
|
|
1070
|
+
const target = name === REDIRECT_HEADER ? value.slice(value.indexOf(" ") + 1) : value;
|
|
1071
|
+
if (refusedTargetScheme(target)) {
|
|
1072
|
+
return refuseComposedHeader(response, name, `${name} response header refused: non-http(s) navigation target`, DEV ? `The ${name} response header carries a navigation target with a non-http(s) ` + `scheme ("${target.slice(0, 64)}"). A javascript: target is same-origin script ` + `execution in any integration that navigates to it, so only http(s) and ` + `relative targets leave this transport. If the target came from request data ` + `(?next= and friends), validate it against your own origin before redirecting.` : null);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
return response;
|
|
1076
|
+
}
|
|
1077
|
+
function refuseComposedHeader(response, name, headerMessage, body) {
|
|
1078
|
+
if (response.body) {
|
|
1079
|
+
try {
|
|
1080
|
+
const cancelled = response.body.cancel();
|
|
1081
|
+
if (cancelled && typeof cancelled.then === "function") cancelled.then(undefined, () => {});
|
|
1082
|
+
} catch {}
|
|
1083
|
+
}
|
|
1084
|
+
const headers = new Headers();
|
|
1085
|
+
headers.set(ERROR_HEADER, boundedErrorHeaderValue(DEV ? headerMessage : GENERIC_SERVER_ERROR_MESSAGE));
|
|
1086
|
+
return new Response(body, {
|
|
1087
|
+
status: 500,
|
|
1088
|
+
headers
|
|
1089
|
+
});
|
|
1090
|
+
}
|
|
1091
|
+
function warnScripted304(functionId) {
|
|
1092
|
+
if (DEV) {
|
|
1093
|
+
console.warn(`Server function "${functionId}" answered a scripted call with 304 Not Modified. ` + `The client transport sends no conditional headers, so nothing was asked to be ` + `revalidated: the call resolves to undefined, not "unchanged". For conditional ` + `reads, declare the function GET and set ETag/Cache-Control response headers - ` + `the browser owns that exchange and replays its cached answer on a 304.`);
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
851
1096
|
function createNoJSHandler({
|
|
852
1097
|
base = ""
|
|
853
1098
|
} = {}) {
|
|
@@ -891,44 +1136,279 @@ function isFormPost(request) {
|
|
|
891
1136
|
const type = request.headers.get("content-type") || "";
|
|
892
1137
|
return type.startsWith("application/x-www-form-urlencoded") || type.startsWith("multipart/form-data");
|
|
893
1138
|
}
|
|
894
|
-
function
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
let onAbort = null;
|
|
899
|
-
const teardown = () => {
|
|
900
|
-
if (closed) return;
|
|
901
|
-
closed = true;
|
|
902
|
-
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
903
|
-
if (cancelSerialize) cancelSerialize();
|
|
904
|
-
if (closeIterator) closeIterator();
|
|
1139
|
+
function guardFailures(value, state) {
|
|
1140
|
+
if (!state) state = {
|
|
1141
|
+
seen: new WeakMap(),
|
|
1142
|
+
cyclic: new WeakSet()
|
|
905
1143
|
};
|
|
906
|
-
|
|
1144
|
+
const entered = enterGuard(value, state);
|
|
1145
|
+
if (!(entered instanceof Frame)) return entered;
|
|
1146
|
+
const stack = [entered];
|
|
1147
|
+
let delivered = NOTHING;
|
|
1148
|
+
for (;;) {
|
|
1149
|
+
const top = stack[stack.length - 1];
|
|
1150
|
+
const items = top.items;
|
|
1151
|
+
let pushed = null;
|
|
1152
|
+
while (top.i < items.length) {
|
|
1153
|
+
const i = top.i;
|
|
1154
|
+
let original;
|
|
1155
|
+
if (top.kind === OBJECT) {
|
|
1156
|
+
const descriptor = top.descriptors[items[i]];
|
|
1157
|
+
if ("value" in descriptor) {
|
|
1158
|
+
original = descriptor.value;
|
|
1159
|
+
} else if (typeof descriptor.get === "function") {
|
|
1160
|
+
if (top.accessorRead !== i) {
|
|
1161
|
+
try {
|
|
1162
|
+
top.accessorValue = descriptor.get.call(top.value);
|
|
1163
|
+
} catch (error) {
|
|
1164
|
+
throw sanitizeServerError(error);
|
|
1165
|
+
}
|
|
1166
|
+
top.accessorRead = i;
|
|
1167
|
+
}
|
|
1168
|
+
original = top.accessorValue;
|
|
1169
|
+
} else {
|
|
1170
|
+
top.i++;
|
|
1171
|
+
continue;
|
|
1172
|
+
}
|
|
1173
|
+
} else {
|
|
1174
|
+
original = items[i];
|
|
1175
|
+
}
|
|
1176
|
+
let guarded;
|
|
1177
|
+
if (delivered !== NOTHING) {
|
|
1178
|
+
guarded = delivered;
|
|
1179
|
+
delivered = NOTHING;
|
|
1180
|
+
} else {
|
|
1181
|
+
guarded = enterGuard(original, state);
|
|
1182
|
+
if (guarded instanceof Frame) {
|
|
1183
|
+
pushed = guarded;
|
|
1184
|
+
break;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
1187
|
+
if (top.kind === ARRAY) {
|
|
1188
|
+
if (guarded !== original) {
|
|
1189
|
+
top.next[i] = guarded;
|
|
1190
|
+
top.changed = true;
|
|
1191
|
+
}
|
|
1192
|
+
} else if (top.kind === MAP) {
|
|
1193
|
+
if ((i & 1) === 0) top.pendingKey = guarded;else top.next.set(top.pendingKey, guarded);
|
|
1194
|
+
if (guarded !== original) top.changed = true;
|
|
1195
|
+
} else if (top.kind === SET) {
|
|
1196
|
+
top.next.add(guarded);
|
|
1197
|
+
if (guarded !== original) top.changed = true;
|
|
1198
|
+
} else if (guarded !== original || top.accessorRead === i) {
|
|
1199
|
+
Object.defineProperty(top.next, items[i], top.accessorRead === i ? {
|
|
1200
|
+
enumerable: true,
|
|
1201
|
+
configurable: true,
|
|
1202
|
+
writable: true,
|
|
1203
|
+
value: guarded
|
|
1204
|
+
} : {
|
|
1205
|
+
...top.descriptors[items[i]],
|
|
1206
|
+
value: guarded
|
|
1207
|
+
});
|
|
1208
|
+
top.changed = true;
|
|
1209
|
+
}
|
|
1210
|
+
top.i++;
|
|
1211
|
+
}
|
|
1212
|
+
if (pushed !== null) {
|
|
1213
|
+
stack.push(pushed);
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
stack.pop();
|
|
1217
|
+
const out = keepGuarded(top.value, top.next, top.changed, state);
|
|
1218
|
+
if (stack.length === 0) return out;
|
|
1219
|
+
delivered = out;
|
|
1220
|
+
}
|
|
1221
|
+
}
|
|
1222
|
+
const NOTHING = Symbol();
|
|
1223
|
+
const ARRAY = 0;
|
|
1224
|
+
const MAP = 1;
|
|
1225
|
+
const SET = 2;
|
|
1226
|
+
const OBJECT = 3;
|
|
1227
|
+
class Frame {
|
|
1228
|
+
constructor(kind, value, next, items, descriptors) {
|
|
1229
|
+
this.kind = kind;
|
|
1230
|
+
this.value = value;
|
|
1231
|
+
this.next = next;
|
|
1232
|
+
this.items = items;
|
|
1233
|
+
this.descriptors = descriptors;
|
|
1234
|
+
this.i = 0;
|
|
1235
|
+
this.changed = false;
|
|
1236
|
+
this.accessorRead = -1;
|
|
1237
|
+
this.accessorValue = undefined;
|
|
1238
|
+
this.pendingKey = undefined;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
function enterGuard(value, state) {
|
|
1242
|
+
if (value === null || typeof value !== "object") return value;
|
|
1243
|
+
if (state.seen.has(value)) {
|
|
1244
|
+
state.cyclic.add(value);
|
|
1245
|
+
return state.seen.get(value);
|
|
1246
|
+
}
|
|
1247
|
+
if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) {
|
|
1248
|
+
let reader;
|
|
1249
|
+
const gate = state.gate;
|
|
1250
|
+
let finished = false;
|
|
1251
|
+
const close = () => {
|
|
1252
|
+
if (finished) return;
|
|
1253
|
+
finished = true;
|
|
1254
|
+
try {
|
|
1255
|
+
const cancelled = reader ? reader.cancel() : value.cancel();
|
|
1256
|
+
if (cancelled && typeof cancelled.then === "function") cancelled.then(undefined, () => {});
|
|
1257
|
+
} catch {}
|
|
1258
|
+
};
|
|
1259
|
+
const guardedStream = new ReadableStream({
|
|
1260
|
+
async pull(controller) {
|
|
1261
|
+
try {
|
|
1262
|
+
if (gate && !finished && !gate.wantsMore()) await gate.awaitDemand();
|
|
1263
|
+
if (finished) {
|
|
1264
|
+
controller.close();
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
if (!reader) reader = value.getReader();
|
|
1268
|
+
const {
|
|
1269
|
+
done,
|
|
1270
|
+
value: chunk
|
|
1271
|
+
} = await reader.read();
|
|
1272
|
+
done ? controller.close() : controller.enqueue(guardFailures(chunk, state));
|
|
1273
|
+
} catch (error) {
|
|
1274
|
+
controller.error(sanitizeServerError(error));
|
|
1275
|
+
}
|
|
1276
|
+
},
|
|
1277
|
+
cancel(reason) {
|
|
1278
|
+
finished = true;
|
|
1279
|
+
return reader ? reader.cancel(reason) : value.cancel(reason);
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
if (gate) gate.onOpen(close);
|
|
1283
|
+
state.seen.set(value, guardedStream);
|
|
1284
|
+
return guardedStream;
|
|
1285
|
+
}
|
|
1286
|
+
if (typeof value.then === "function") {
|
|
1287
|
+
const guardedPromise = Promise.resolve(value).then(resolved => guardFailures(resolved, state), error => {
|
|
1288
|
+
throw sanitizeServerError(error);
|
|
1289
|
+
});
|
|
1290
|
+
state.seen.set(value, guardedPromise);
|
|
1291
|
+
return guardedPromise;
|
|
1292
|
+
}
|
|
1293
|
+
if (typeof value[Symbol.asyncIterator] === "function") {
|
|
907
1294
|
const source = value;
|
|
908
|
-
|
|
1295
|
+
const gate = state.gate;
|
|
1296
|
+
const guardedIterable = {
|
|
909
1297
|
[Symbol.asyncIterator]() {
|
|
910
|
-
const
|
|
1298
|
+
const iterator = source[Symbol.asyncIterator]();
|
|
911
1299
|
let finished = false;
|
|
912
|
-
|
|
1300
|
+
const close = () => {
|
|
913
1301
|
if (finished) return;
|
|
914
1302
|
finished = true;
|
|
915
1303
|
try {
|
|
916
|
-
const returned =
|
|
1304
|
+
const returned = iterator.return && iterator.return();
|
|
917
1305
|
if (returned && typeof returned.then === "function") returned.then(undefined, () => {});
|
|
918
1306
|
} catch {}
|
|
919
1307
|
};
|
|
920
|
-
if (
|
|
1308
|
+
if (gate) gate.onOpen(close);
|
|
1309
|
+
const step = () => finished ? Promise.resolve({
|
|
1310
|
+
done: true,
|
|
1311
|
+
value: undefined
|
|
1312
|
+
}) : iterator.next().then(step => {
|
|
1313
|
+
if (step.done) {
|
|
1314
|
+
finished = true;
|
|
1315
|
+
return step;
|
|
1316
|
+
}
|
|
1317
|
+
return {
|
|
1318
|
+
done: false,
|
|
1319
|
+
value: guardFailures(step.value, state)
|
|
1320
|
+
};
|
|
1321
|
+
}, error => {
|
|
1322
|
+
throw sanitizeServerError(error);
|
|
1323
|
+
});
|
|
921
1324
|
return {
|
|
922
|
-
next: () => finished ?
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
1325
|
+
next: () => finished || !gate || gate.wantsMore() ? step() : gate.awaitDemand().then(step),
|
|
1326
|
+
return: () => {
|
|
1327
|
+
close();
|
|
1328
|
+
return Promise.resolve({
|
|
1329
|
+
done: true,
|
|
1330
|
+
value: undefined
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
926
1333
|
};
|
|
927
1334
|
}
|
|
928
1335
|
};
|
|
1336
|
+
state.seen.set(value, guardedIterable);
|
|
1337
|
+
return guardedIterable;
|
|
1338
|
+
}
|
|
1339
|
+
if (Array.isArray(value)) {
|
|
1340
|
+
const next = value.slice();
|
|
1341
|
+
state.seen.set(value, next);
|
|
1342
|
+
return new Frame(ARRAY, value, next, value, null);
|
|
929
1343
|
}
|
|
1344
|
+
if (value instanceof Map) {
|
|
1345
|
+
const next = new Map();
|
|
1346
|
+
state.seen.set(value, next);
|
|
1347
|
+
const items = [];
|
|
1348
|
+
for (const entry of value) items.push(entry[0], entry[1]);
|
|
1349
|
+
return new Frame(MAP, value, next, items, null);
|
|
1350
|
+
}
|
|
1351
|
+
if (value instanceof Set) {
|
|
1352
|
+
const next = new Set();
|
|
1353
|
+
state.seen.set(value, next);
|
|
1354
|
+
return new Frame(SET, value, next, [...value], null);
|
|
1355
|
+
}
|
|
1356
|
+
const prototype = Object.getPrototypeOf(value);
|
|
1357
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
1358
|
+
state.seen.set(value, value);
|
|
1359
|
+
return value;
|
|
1360
|
+
}
|
|
1361
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
1362
|
+
const next = Object.create(prototype, descriptors);
|
|
1363
|
+
state.seen.set(value, next);
|
|
1364
|
+
return new Frame(OBJECT, value, next, Object.keys(descriptors), descriptors);
|
|
1365
|
+
}
|
|
1366
|
+
function keepGuarded(value, next, changed, state) {
|
|
1367
|
+
if (changed || state.cyclic.has(value)) return next;
|
|
1368
|
+
state.seen.set(value, value);
|
|
1369
|
+
return value;
|
|
1370
|
+
}
|
|
1371
|
+
function serializeResponseStream(value, codecOptions, signal) {
|
|
1372
|
+
let closed = false;
|
|
1373
|
+
let streamController = null;
|
|
1374
|
+
let demandWaiters = null;
|
|
1375
|
+
const wantsMore = () => streamController !== null && streamController.desiredSize > 0;
|
|
1376
|
+
const awaitDemand = () => new Promise(resolve => (demandWaiters ??= []).push(resolve));
|
|
1377
|
+
const supplyDemand = () => {
|
|
1378
|
+
const resolvers = demandWaiters;
|
|
1379
|
+
demandWaiters = null;
|
|
1380
|
+
if (resolvers) for (const resolve of resolvers) resolve();
|
|
1381
|
+
};
|
|
1382
|
+
const sourceClosers = new Set();
|
|
1383
|
+
const gate = {
|
|
1384
|
+
wantsMore,
|
|
1385
|
+
awaitDemand,
|
|
1386
|
+
onOpen(close) {
|
|
1387
|
+
if (closed) close();else sourceClosers.add(close);
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
value = guardFailures(value, {
|
|
1391
|
+
seen: new WeakMap(),
|
|
1392
|
+
cyclic: new WeakSet(),
|
|
1393
|
+
gate
|
|
1394
|
+
});
|
|
1395
|
+
let cancelSerialize = null;
|
|
1396
|
+
let onAbort = null;
|
|
1397
|
+
const finishSource = () => {
|
|
1398
|
+
for (const close of sourceClosers) close();
|
|
1399
|
+
sourceClosers.clear();
|
|
1400
|
+
supplyDemand();
|
|
1401
|
+
};
|
|
1402
|
+
const teardown = () => {
|
|
1403
|
+
if (closed) return;
|
|
1404
|
+
closed = true;
|
|
1405
|
+
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
1406
|
+
if (cancelSerialize) cancelSerialize();
|
|
1407
|
+
finishSource();
|
|
1408
|
+
};
|
|
930
1409
|
return new ReadableStream({
|
|
931
1410
|
async start(controller) {
|
|
1411
|
+
streamController = controller;
|
|
932
1412
|
if (signal) {
|
|
933
1413
|
if (signal.aborted) {
|
|
934
1414
|
teardown();
|
|
@@ -964,16 +1444,29 @@ function serializeResponseStream(value, codecOptions, signal) {
|
|
|
964
1444
|
if (closed) return;
|
|
965
1445
|
closed = true;
|
|
966
1446
|
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
1447
|
+
finishSource();
|
|
967
1448
|
controller.close();
|
|
968
1449
|
},
|
|
969
1450
|
onError(error) {
|
|
970
1451
|
if (closed) return;
|
|
971
1452
|
closed = true;
|
|
972
1453
|
if (onAbort) signal.removeEventListener("abort", onAbort);
|
|
973
|
-
|
|
1454
|
+
finishSource();
|
|
1455
|
+
try {
|
|
1456
|
+
const delivered = sanitizeServerError(DEV && error instanceof Error ? new Error(`Server function result could not be encoded: ${error.message}`) : error);
|
|
1457
|
+
controller.enqueue(createChunk(encodeErrorTrailer(delivered)));
|
|
1458
|
+
controller.close();
|
|
1459
|
+
} catch {
|
|
1460
|
+
try {
|
|
1461
|
+
controller.error(error);
|
|
1462
|
+
} catch {}
|
|
1463
|
+
}
|
|
974
1464
|
}
|
|
975
1465
|
});
|
|
976
1466
|
},
|
|
1467
|
+
pull() {
|
|
1468
|
+
supplyDemand();
|
|
1469
|
+
},
|
|
977
1470
|
cancel() {
|
|
978
1471
|
teardown();
|
|
979
1472
|
}
|
|
@@ -987,6 +1480,18 @@ function serializedResponse(value, headers, codec, signal) {
|
|
|
987
1480
|
});
|
|
988
1481
|
}
|
|
989
1482
|
function encodeResult(value, headers, status, codec, signal) {
|
|
1483
|
+
if (NULL_BODY_STATUSES.has(status)) {
|
|
1484
|
+
if (value === undefined || value === null) {
|
|
1485
|
+
headers.set(BODY_FORMAT_HEADER, BodyFormat.Void);
|
|
1486
|
+
return new Response(null, {
|
|
1487
|
+
status,
|
|
1488
|
+
headers
|
|
1489
|
+
});
|
|
1490
|
+
}
|
|
1491
|
+
const error = new Error(`Server function answered status ${status}, which forbids a response body, with a value. ` + `Return respond(undefined, { status: ${status} }) for a bodiless answer, or drop the ` + `status to send the value.`);
|
|
1492
|
+
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error.message));
|
|
1493
|
+
return encodeResult(error, headers, 500, codec, signal);
|
|
1494
|
+
}
|
|
990
1495
|
const direct = getHeadersAndBody(value);
|
|
991
1496
|
if (direct) {
|
|
992
1497
|
for (const [key, val] of Object.entries(direct.headers || {})) {
|
|
@@ -1015,11 +1520,25 @@ function encodeResult(value, headers, status, codec, signal) {
|
|
|
1015
1520
|
}
|
|
1016
1521
|
} catch {
|
|
1017
1522
|
}
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
status,
|
|
1021
|
-
|
|
1022
|
-
|
|
1523
|
+
try {
|
|
1524
|
+
const response = serializedResponse(value, headers, codec, signal);
|
|
1525
|
+
return status === 200 ? response : new Response(response.body, {
|
|
1526
|
+
status,
|
|
1527
|
+
headers
|
|
1528
|
+
});
|
|
1529
|
+
} catch (error) {
|
|
1530
|
+
throw DEV && error instanceof Error ? new Error(`Server function result could not be encoded: ${error.message}`) : error;
|
|
1531
|
+
}
|
|
1532
|
+
}
|
|
1533
|
+
const ERROR_HEADER_VALUE_LIMIT = 1024;
|
|
1534
|
+
function boundedErrorHeaderValue(message) {
|
|
1535
|
+
let label = message.length > 256 ? message.slice(0, 256) : message;
|
|
1536
|
+
let encoded = encodeErrorHeaderValue(label);
|
|
1537
|
+
while (encoded.length > ERROR_HEADER_VALUE_LIMIT && label.length > 1) {
|
|
1538
|
+
label = label.slice(0, Math.ceil(label.length / 2));
|
|
1539
|
+
encoded = encodeErrorHeaderValue(label);
|
|
1540
|
+
}
|
|
1541
|
+
return encoded;
|
|
1023
1542
|
}
|
|
1024
1543
|
const GENERIC_SERVER_ERROR_MESSAGE = "Internal Server Error";
|
|
1025
1544
|
let DEV = false === true;
|
|
@@ -1043,11 +1562,12 @@ function serverFunctionUrl(id, boundArgs) {
|
|
|
1043
1562
|
return `${address}?args=${encodeURIComponent(JSON.stringify(boundArgs))}`;
|
|
1044
1563
|
}
|
|
1045
1564
|
function parseServerFunctionUrl(url) {
|
|
1046
|
-
|
|
1565
|
+
const parsed = parseServerFunctionAddress(new URL(url, "http://localhost").pathname, config.endpoint);
|
|
1566
|
+
return parsed && parsed.id;
|
|
1047
1567
|
}
|
|
1048
1568
|
async function matchesOrigin(origin, request, matcher) {
|
|
1049
1569
|
if (matcher === undefined) return origin === new URL(request.url).origin;
|
|
1050
|
-
if (typeof matcher === "function") return
|
|
1570
|
+
if (typeof matcher === "function") return (await matcher(origin, request)) === true;
|
|
1051
1571
|
return Array.isArray(matcher) ? matcher.includes(origin) : origin === matcher;
|
|
1052
1572
|
}
|
|
1053
1573
|
async function allowsServerFunctionRequest(request, options) {
|
|
@@ -1103,10 +1623,24 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1103
1623
|
const codec = options.codec !== undefined ? options.codec : getServerFunctionsCodec();
|
|
1104
1624
|
const url = new URL(request.url);
|
|
1105
1625
|
const method = request.method;
|
|
1106
|
-
const
|
|
1626
|
+
const address = resolveAddress(url);
|
|
1627
|
+
const functionId = address && address.id;
|
|
1107
1628
|
const declaredRead = (method === "GET" || method === "HEAD") && functionId !== null && METHODS.get(functionId) === "GET";
|
|
1108
1629
|
const csrf = options.csrf !== undefined ? options.csrf : config.csrf;
|
|
1109
|
-
const protectsRequest = csrf !== false && !declaredRead;
|
|
1630
|
+
const protectsRequest = csrf !== false && (!declaredRead || typeof csrf === "object" && csrf.protectDeclaredReads === true);
|
|
1631
|
+
let serverFunction;
|
|
1632
|
+
if (functionId) {
|
|
1633
|
+
try {
|
|
1634
|
+
serverFunction = getServerFunction(functionId);
|
|
1635
|
+
} catch {
|
|
1636
|
+
return finalizeTransportResponse(new Response(DEV ? `Unknown server function: ${functionId}` : null, {
|
|
1637
|
+
status: 404,
|
|
1638
|
+
headers: {
|
|
1639
|
+
[UNKNOWN_HEADER]: "true"
|
|
1640
|
+
}
|
|
1641
|
+
}), method);
|
|
1642
|
+
}
|
|
1643
|
+
}
|
|
1110
1644
|
if (protectsRequest && !(await allowsServerFunctionRequest(request, csrf === true ? {} : csrf))) {
|
|
1111
1645
|
return finalizeTransportResponse(forbiddenResponse(), method);
|
|
1112
1646
|
}
|
|
@@ -1117,15 +1651,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1117
1651
|
});
|
|
1118
1652
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1119
1653
|
}
|
|
1120
|
-
|
|
1121
|
-
try {
|
|
1122
|
-
serverFunction = getServerFunction(functionId);
|
|
1123
|
-
} catch {
|
|
1124
|
-
const response = new Response(DEV ? `Unknown server function: ${functionId}` : null, {
|
|
1125
|
-
status: 404
|
|
1126
|
-
});
|
|
1127
|
-
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1128
|
-
}
|
|
1654
|
+
const scripted = address.data;
|
|
1129
1655
|
if (method !== "POST" && !declaredRead) {
|
|
1130
1656
|
const response = new Response(DEV ? `Method not allowed for server function: ${functionId}` : null, {
|
|
1131
1657
|
status: 405,
|
|
@@ -1135,25 +1661,81 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1135
1661
|
});
|
|
1136
1662
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1137
1663
|
}
|
|
1138
|
-
const
|
|
1664
|
+
const bodySizeLimit = options.bodySizeLimit !== undefined ? options.bodySizeLimit : config.bodySizeLimit;
|
|
1665
|
+
const argsEncoding = url.searchParams.get("args");
|
|
1666
|
+
if (argsEncoding !== null && argsEncoding.length > bodySizeLimit) {
|
|
1667
|
+
const response = new Response(DEV ? "Server function arguments exceed the configured bodySizeLimit" : null, {
|
|
1668
|
+
status: 413
|
|
1669
|
+
});
|
|
1670
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1671
|
+
}
|
|
1672
|
+
if (method === "POST" && request.body !== null && bodySizeLimit !== Infinity) {
|
|
1673
|
+
const raw = request.headers.get("content-length");
|
|
1674
|
+
const declared = raw !== null && /^\d+$/.test(raw) ? Number(raw) : NaN;
|
|
1675
|
+
if (declared > bodySizeLimit) {
|
|
1676
|
+
const response = new Response(DEV ? "Server function request body exceeds the configured bodySizeLimit" : null, {
|
|
1677
|
+
status: 413
|
|
1678
|
+
});
|
|
1679
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1680
|
+
}
|
|
1681
|
+
if (!(declared > 0)) {
|
|
1682
|
+
const bounded = await bufferBodyWithin(request, bodySizeLimit);
|
|
1683
|
+
if (bounded === null) {
|
|
1684
|
+
const response = new Response(DEV ? "Server function request body exceeds the configured bodySizeLimit" : null, {
|
|
1685
|
+
status: 413
|
|
1686
|
+
});
|
|
1687
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1688
|
+
}
|
|
1689
|
+
request = bounded;
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
let event = options.createEvent ? options.createEvent(request) : {
|
|
1139
1693
|
request,
|
|
1140
1694
|
locals: {}
|
|
1141
1695
|
};
|
|
1696
|
+
if (typeof event?.then === "function") event = await event;
|
|
1697
|
+
const refuseCommitted = raw => {
|
|
1698
|
+
const response = commitEventResponse(raw, event);
|
|
1699
|
+
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1700
|
+
};
|
|
1142
1701
|
const provide = options.provideEvent || provideEvent;
|
|
1143
1702
|
const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
|
|
1144
1703
|
const transformResult = options.transformResult !== undefined ? options.transformResult : config.transformResult;
|
|
1145
1704
|
const wrapInvocation = options.wrapInvocation !== undefined ? options.wrapInvocation : config.wrapInvocation;
|
|
1146
1705
|
const transformFlightResult = options.transformFlightResult !== undefined ? options.transformFlightResult : config.transformFlightResult;
|
|
1147
|
-
|
|
1148
|
-
|
|
1706
|
+
let handleNoJS = options.handleNoJS !== undefined ? options.handleNoJS : config.handleNoJS;
|
|
1707
|
+
if (handleNoJS === undefined && !scripted && isFormPost(request)) {
|
|
1708
|
+
const fetchMode = request.headers.get("Sec-Fetch-Mode");
|
|
1709
|
+
if (fetchMode === null || fetchMode === "navigate") {
|
|
1710
|
+
handleNoJS = defaultNoJSHandler || (defaultNoJSHandler = createNoJSHandler());
|
|
1711
|
+
} else {
|
|
1712
|
+
const response = new Response(DEV ? "The bare server-function address answers form navigations with the " + "no-JS redirect convention. Scripted callers use the data address " + `(…/data/${functionId}) or send the ${BODY_FORMAT_HEADER} tag.` : null, {
|
|
1713
|
+
status: 400
|
|
1714
|
+
});
|
|
1715
|
+
return refuseCommitted(response);
|
|
1716
|
+
}
|
|
1717
|
+
}
|
|
1718
|
+
const flightHeader = scripted && method === "POST" ? request.headers.get(SINGLE_FLIGHT_HEADER) : null;
|
|
1719
|
+
const flightHooks = flightHeader ? flightHeader.split(",").flatMap(source => {
|
|
1720
|
+
const hook = source === "true" ? flightHook : flightSources.get(source);
|
|
1721
|
+
return hook ? [[source, hook]] : [];
|
|
1722
|
+
}) : [];
|
|
1723
|
+
const collectsFlight = flightHooks.length > 0;
|
|
1149
1724
|
let parsed;
|
|
1150
1725
|
try {
|
|
1151
|
-
parsed = await parseArguments(request, url,
|
|
1726
|
+
parsed = await parseArguments(request, url, scripted, codec);
|
|
1152
1727
|
} catch {
|
|
1153
1728
|
const response = new Response(DEV ? "Malformed server function arguments" : null, {
|
|
1154
1729
|
status: 400
|
|
1155
1730
|
});
|
|
1156
|
-
return
|
|
1731
|
+
return refuseCommitted(response);
|
|
1732
|
+
}
|
|
1733
|
+
const maxArguments = options.maxArguments !== undefined ? options.maxArguments : config.maxArguments;
|
|
1734
|
+
if (parsed.length > maxArguments) {
|
|
1735
|
+
const response = new Response(DEV ? "Server function call exceeds the configured maxArguments" : null, {
|
|
1736
|
+
status: 400
|
|
1737
|
+
});
|
|
1738
|
+
return refuseCommitted(response);
|
|
1157
1739
|
}
|
|
1158
1740
|
const flightContext = {
|
|
1159
1741
|
id: functionId,
|
|
@@ -1190,25 +1772,29 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1190
1772
|
response,
|
|
1191
1773
|
value
|
|
1192
1774
|
} = result;
|
|
1193
|
-
if (!
|
|
1775
|
+
if (!scripted && !handleNoJS && response && response.body) {
|
|
1194
1776
|
return response;
|
|
1195
1777
|
}
|
|
1196
1778
|
if (response && response.headers) {
|
|
1197
1779
|
mergeResponseHeaders(headers, response.headers);
|
|
1198
1780
|
}
|
|
1199
|
-
if (response && response.status && (
|
|
1781
|
+
if (response && response.status && (!scripted || !validRedirectStatuses.has(response.status))) {
|
|
1200
1782
|
status = response.status;
|
|
1783
|
+
} else if (response && response.status) {
|
|
1784
|
+
maskRedirect(headers, response, request.url);
|
|
1201
1785
|
}
|
|
1202
1786
|
metadata = response;
|
|
1203
1787
|
result = value;
|
|
1204
1788
|
} else if (result instanceof Response) {
|
|
1205
1789
|
if (result.headers && result.headers.has("X-Content-Raw")) return result;
|
|
1206
|
-
if (
|
|
1790
|
+
if (scripted) {
|
|
1207
1791
|
if (result.headers) {
|
|
1208
1792
|
mergeResponseHeaders(headers, result.headers);
|
|
1209
1793
|
}
|
|
1210
|
-
if (result.status && (result.status
|
|
1794
|
+
if (result.status && !validRedirectStatuses.has(result.status)) {
|
|
1211
1795
|
status = result.status;
|
|
1796
|
+
} else if (result.status) {
|
|
1797
|
+
maskRedirect(headers, result, request.url);
|
|
1212
1798
|
}
|
|
1213
1799
|
metadata = result;
|
|
1214
1800
|
if (result.body == null) {
|
|
@@ -1217,7 +1803,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1217
1803
|
}
|
|
1218
1804
|
}
|
|
1219
1805
|
if (collectsFlight) {
|
|
1220
|
-
result = await foldFlightData(
|
|
1806
|
+
result = await foldFlightData(flightHooks, event, headers, {
|
|
1221
1807
|
id: functionId,
|
|
1222
1808
|
value: result,
|
|
1223
1809
|
response: metadata,
|
|
@@ -1226,19 +1812,37 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1226
1812
|
}, flightContext);
|
|
1227
1813
|
if (result instanceof Response && result.headers.has("X-Content-Raw")) return result;
|
|
1228
1814
|
}
|
|
1229
|
-
if (!
|
|
1230
|
-
if (handleNoJS) return handleNoJS(result, request, parsed);
|
|
1815
|
+
if (!scripted) {
|
|
1816
|
+
if (handleNoJS) return handleNoJS(result ?? metadata, request, parsed);
|
|
1231
1817
|
if (result instanceof Response) return result;
|
|
1232
|
-
return encodeResult(result, headers,
|
|
1818
|
+
return encodeResult(result, headers, status, codec, request.signal);
|
|
1233
1819
|
}
|
|
1820
|
+
if (status === 304) warnScripted304(functionId);
|
|
1234
1821
|
return encodeResult(result, headers, status, codec, request.signal);
|
|
1235
1822
|
} catch (x) {
|
|
1823
|
+
const respondThrown = value => {
|
|
1824
|
+
const safe = sanitizeServerError(value);
|
|
1825
|
+
if (!scripted) {
|
|
1826
|
+
if (handleNoJS) return handleNoJS(safe, request, parsed, true);
|
|
1827
|
+
const message = safe instanceof Error ? safe.message : String(safe);
|
|
1828
|
+
return new Response(DEV ? message : null, {
|
|
1829
|
+
status: 500
|
|
1830
|
+
});
|
|
1831
|
+
}
|
|
1832
|
+
const error = safe instanceof Error ? safe.message : typeof safe === "string" ? safe : "true";
|
|
1833
|
+
headers.set(ERROR_HEADER, boundedErrorHeaderValue(error));
|
|
1834
|
+
return encodeResult(safe, headers, 500, codec, request.signal);
|
|
1835
|
+
};
|
|
1236
1836
|
if (x instanceof Response || isResponseEnvelope(x)) {
|
|
1237
1837
|
if (transformResult) {
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
|
|
1241
|
-
|
|
1838
|
+
try {
|
|
1839
|
+
x = await transformResult(event, x, {
|
|
1840
|
+
...flightContext,
|
|
1841
|
+
thrown: true
|
|
1842
|
+
});
|
|
1843
|
+
} catch (hookError) {
|
|
1844
|
+
return respondThrown(hookError);
|
|
1845
|
+
}
|
|
1242
1846
|
}
|
|
1243
1847
|
let status = 200;
|
|
1244
1848
|
let metadata;
|
|
@@ -1250,8 +1854,10 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1250
1854
|
if (response && response.headers) {
|
|
1251
1855
|
mergeResponseHeaders(headers, response.headers);
|
|
1252
1856
|
}
|
|
1253
|
-
if (response && response.status && (!
|
|
1857
|
+
if (response && response.status && (!scripted || !validRedirectStatuses.has(response.status))) {
|
|
1254
1858
|
status = response.status;
|
|
1859
|
+
} else if (response && response.status) {
|
|
1860
|
+
maskRedirect(headers, response, request.url);
|
|
1255
1861
|
}
|
|
1256
1862
|
metadata = response;
|
|
1257
1863
|
x = value;
|
|
@@ -1259,8 +1865,10 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1259
1865
|
if (x.headers) {
|
|
1260
1866
|
mergeResponseHeaders(headers, x.headers);
|
|
1261
1867
|
}
|
|
1262
|
-
if (x.status && (!
|
|
1868
|
+
if (x.status && (!scripted || !validRedirectStatuses.has(x.status))) {
|
|
1263
1869
|
status = x.status;
|
|
1870
|
+
} else if (x.status) {
|
|
1871
|
+
maskRedirect(headers, x, request.url);
|
|
1264
1872
|
}
|
|
1265
1873
|
metadata = x;
|
|
1266
1874
|
if (x.body == null) {
|
|
@@ -1268,7 +1876,7 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1268
1876
|
}
|
|
1269
1877
|
}
|
|
1270
1878
|
if (collectsFlight) {
|
|
1271
|
-
x = await foldFlightData(
|
|
1879
|
+
x = await foldFlightData(flightHooks, event, headers, {
|
|
1272
1880
|
id: functionId,
|
|
1273
1881
|
value: x,
|
|
1274
1882
|
response: metadata,
|
|
@@ -1276,38 +1884,38 @@ async function handleServerFunctionRequest(request, options = {}) {
|
|
|
1276
1884
|
thrown: true
|
|
1277
1885
|
}, flightContext);
|
|
1278
1886
|
if (x instanceof Response && x.headers.has("X-Content-Raw")) {
|
|
1887
|
+
x = ownResponse(x);
|
|
1279
1888
|
x.headers.set(ERROR_HEADER, "true");
|
|
1280
1889
|
return x;
|
|
1281
1890
|
}
|
|
1282
1891
|
}
|
|
1283
1892
|
headers.set(ERROR_HEADER, "true");
|
|
1284
|
-
if (!
|
|
1893
|
+
if (!scripted) {
|
|
1285
1894
|
if (handleNoJS) return handleNoJS(x ?? metadata, request, parsed, true);
|
|
1286
1895
|
if (x instanceof Response) return x;
|
|
1287
1896
|
}
|
|
1897
|
+
if (scripted && status === 304) warnScripted304(functionId);
|
|
1288
1898
|
return encodeResult(x, headers, status, codec, request.signal);
|
|
1289
1899
|
}
|
|
1290
|
-
|
|
1291
|
-
if (!instance) {
|
|
1292
|
-
if (handleNoJS) return handleNoJS(safe, request, parsed, true);
|
|
1293
|
-
const message = safe instanceof Error ? safe.message : String(safe);
|
|
1294
|
-
return new Response(DEV ? message : null, {
|
|
1295
|
-
status: 500
|
|
1296
|
-
});
|
|
1297
|
-
}
|
|
1298
|
-
const error = safe instanceof Error ? safe.message : typeof safe === "string" ? safe : "true";
|
|
1299
|
-
headers.set(ERROR_HEADER, encodeErrorHeaderValue(error));
|
|
1300
|
-
return encodeResult(safe, headers, 200, codec, request.signal);
|
|
1900
|
+
return respondThrown(x);
|
|
1301
1901
|
}
|
|
1302
1902
|
};
|
|
1303
|
-
const response = commitEventResponse(await dispatch(), event);
|
|
1903
|
+
const response = commitEventResponse(enforceComposedHeaderInvariants(ownResponse(await dispatch())), event);
|
|
1304
1904
|
return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
|
|
1305
1905
|
}
|
|
1906
|
+
function ownResponse(response) {
|
|
1907
|
+
try {
|
|
1908
|
+
return new Response(response.body, response);
|
|
1909
|
+
} catch {
|
|
1910
|
+
return response;
|
|
1911
|
+
}
|
|
1912
|
+
}
|
|
1306
1913
|
function finalizeTransportResponse(response, method) {
|
|
1307
1914
|
const stripBody = method === "HEAD" && response.body !== null;
|
|
1308
|
-
|
|
1915
|
+
const defaultsCache = !response.headers.has("Cache-Control") && response.status !== 304;
|
|
1916
|
+
if (stripBody || defaultsCache) {
|
|
1309
1917
|
try {
|
|
1310
|
-
if (
|
|
1918
|
+
if (defaultsCache) {
|
|
1311
1919
|
response.headers.set("Cache-Control", "no-store");
|
|
1312
1920
|
}
|
|
1313
1921
|
if (!stripBody) return response;
|
|
@@ -1319,7 +1927,7 @@ function finalizeTransportResponse(response, method) {
|
|
|
1319
1927
|
});
|
|
1320
1928
|
} catch {
|
|
1321
1929
|
const headers = new Headers(response.headers);
|
|
1322
|
-
if (!headers.has("Cache-Control")) headers.set("Cache-Control", "no-store");
|
|
1930
|
+
if (defaultsCache && !headers.has("Cache-Control")) headers.set("Cache-Control", "no-store");
|
|
1323
1931
|
if (stripBody) response.body.cancel().catch(() => {});
|
|
1324
1932
|
return new Response(stripBody ? null : response.body, {
|
|
1325
1933
|
status: response.status,
|
|
@@ -1336,14 +1944,17 @@ exports.FLASH_COOKIE = FLASH_COOKIE;
|
|
|
1336
1944
|
exports.GENERIC_SERVER_ERROR_MESSAGE = GENERIC_SERVER_ERROR_MESSAGE;
|
|
1337
1945
|
exports.GET = GET;
|
|
1338
1946
|
exports.INSTANCE_HEADER = INSTANCE_HEADER;
|
|
1947
|
+
exports.REDIRECT_HEADER = REDIRECT_HEADER;
|
|
1339
1948
|
exports.SERVER_FUNCTION_INVOKE = SERVER_FUNCTION_INVOKE;
|
|
1340
1949
|
exports.SINGLE_FLIGHT_HEADER = SINGLE_FLIGHT_HEADER;
|
|
1950
|
+
exports.UNKNOWN_HEADER = UNKNOWN_HEADER;
|
|
1341
1951
|
exports.clearFlashCookie = clearFlashCookie;
|
|
1342
1952
|
exports.configureServerFunctionsServer = configureServerFunctionsServer;
|
|
1343
1953
|
exports.createNoJSHandler = createNoJSHandler;
|
|
1344
1954
|
exports.createServerReference = createServerReference;
|
|
1345
1955
|
exports.decodeErrorHeaderValue = decodeErrorHeaderValue;
|
|
1346
1956
|
exports.decodeFlashCookie = decodeFlashCookie;
|
|
1957
|
+
exports.decodeRedirectHeaderValue = decodeRedirectHeaderValue;
|
|
1347
1958
|
exports.decodeResponse = decodeResponse;
|
|
1348
1959
|
exports.decodeResponsePayload = decodeResponsePayload;
|
|
1349
1960
|
exports.encodeErrorHeaderValue = encodeErrorHeaderValue;
|
|
@@ -1353,6 +1964,7 @@ exports.getEventServerFunctionInvocation = getEventServerFunctionInvocation;
|
|
|
1353
1964
|
exports.getServerFunction = getServerFunction;
|
|
1354
1965
|
exports.getServerFunctionInvocation = getServerFunctionInvocation;
|
|
1355
1966
|
exports.getServerFunctionMetadata = getServerFunctionMetadata;
|
|
1967
|
+
exports.guardFailures = guardFailures;
|
|
1356
1968
|
exports.handleServerFunctionRequest = handleServerFunctionRequest;
|
|
1357
1969
|
exports.hasFlashCookie = hasFlashCookie;
|
|
1358
1970
|
exports.invoke = invoke;
|
|
@@ -1360,6 +1972,7 @@ exports.isServerFunction = isServerFunction;
|
|
|
1360
1972
|
exports.live = live;
|
|
1361
1973
|
exports.observeServerFunctionCalls = observeServerFunctionCalls;
|
|
1362
1974
|
exports.parseServerFunctionUrl = parseServerFunctionUrl;
|
|
1975
|
+
exports.registerFlightDataSource = registerFlightDataSource;
|
|
1363
1976
|
exports.registerServerFunction = registerServerFunction;
|
|
1364
1977
|
exports.registerServerReference = registerServerReference;
|
|
1365
1978
|
exports.sanitizeServerError = sanitizeServerError;
|