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