@solidjs/web 2.0.0-rc.4 → 2.0.0-rc.6

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.
Files changed (61) hide show
  1. package/dist/dev.cjs +163 -36
  2. package/dist/dev.js +161 -37
  3. package/dist/server.cjs +178 -37
  4. package/dist/server.js +177 -38
  5. package/dist/web.cjs +143 -36
  6. package/dist/web.js +141 -37
  7. package/frames/dist/client.cjs +41 -8
  8. package/frames/dist/client.dev.cjs +41 -8
  9. package/frames/dist/client.dev.js +41 -8
  10. package/frames/dist/client.js +41 -8
  11. package/frames/dist/server.cjs +497 -44
  12. package/frames/dist/server.js +497 -44
  13. package/package.json +2 -2
  14. package/serialization/dist/decode.cjs +4 -2
  15. package/serialization/dist/decode.js +4 -2
  16. package/serialization/dist/serialization.cjs +12 -8
  17. package/serialization/dist/serialization.js +12 -8
  18. package/serialization/types/index.d.ts +7 -0
  19. package/serialization/types/serializer-decode.d.ts +14 -1
  20. package/serialization/types/serializer.d.ts +7 -0
  21. package/serialization/types-cjs/index.d.cts +7 -0
  22. package/serialization/types-cjs/serializer-decode.d.cts +14 -1
  23. package/serialization/types-cjs/serializer.d.cts +7 -0
  24. package/server-functions/dist/client.cjs +164 -35
  25. package/server-functions/dist/client.js +161 -36
  26. package/server-functions/dist/server.cjs +899 -136
  27. package/server-functions/dist/server.dev.cjs +919 -136
  28. package/server-functions/dist/server.dev.js +915 -137
  29. package/server-functions/dist/server.js +895 -137
  30. package/types/client.d.ts +2 -1
  31. package/types/constants.d.ts +3 -1
  32. package/types/cookies.d.ts +6 -14
  33. package/types/frames/frame-client.d.ts +4 -0
  34. package/types/frames/serializer-decode.d.ts +14 -1
  35. package/types/frames/serializer.d.ts +7 -0
  36. package/types/jsx.d.ts +11 -16
  37. package/types/response.d.ts +11 -0
  38. package/types/serializer-decode.d.ts +14 -1
  39. package/types/serializer.d.ts +7 -0
  40. package/types/server-functions/client.d.ts +22 -2
  41. package/types/server-functions/flash.d.ts +9 -0
  42. package/types/server-functions/server.d.ts +131 -11
  43. package/types/server-functions/shared.d.ts +77 -14
  44. package/types/server-mock.d.ts +17 -2
  45. package/types/server.d.ts +16 -2
  46. package/types-cjs/client.d.cts +2 -1
  47. package/types-cjs/constants.d.cts +3 -1
  48. package/types-cjs/cookies.d.cts +6 -14
  49. package/types-cjs/frames/frame-client.d.cts +4 -0
  50. package/types-cjs/frames/serializer-decode.d.cts +14 -1
  51. package/types-cjs/frames/serializer.d.cts +7 -0
  52. package/types-cjs/jsx.d.cts +11 -16
  53. package/types-cjs/response.d.cts +11 -0
  54. package/types-cjs/serializer-decode.d.cts +14 -1
  55. package/types-cjs/serializer.d.cts +7 -0
  56. package/types-cjs/server-functions/client.d.cts +22 -2
  57. package/types-cjs/server-functions/flash.d.cts +9 -0
  58. package/types-cjs/server-functions/server.d.cts +131 -11
  59. package/types-cjs/server-functions/shared.d.cts +77 -14
  60. package/types-cjs/server-mock.d.cts +17 -2
  61. package/types-cjs/server.d.cts +16 -2
@@ -2,6 +2,16 @@
2
2
 
3
3
  var solidJs = require('solid-js');
4
4
 
5
+ const COMPOSED_BODY_FRAMING = /*#__PURE__*/new Set(["content-length", "content-encoding", "transfer-encoding"]);
6
+ function isHttpNavigationTarget(target) {
7
+ try {
8
+ const protocol = new URL(target, "http://base.invalid").protocol;
9
+ return protocol === "http:" || protocol === "https:";
10
+ } catch {
11
+ return false;
12
+ }
13
+ }
14
+
5
15
  const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
6
16
  function isResponseEnvelope(value) {
7
17
  return !!(value && typeof value === "object" && value[ENVELOPE]);
@@ -11,6 +21,8 @@ function isSafeError(value) {
11
21
  return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
12
22
  }
13
23
  const REVALIDATE_HEADER = "X-Revalidate";
24
+ const RESPONSE_HEADER_VALUE_LIMIT = 4096;
25
+ const NULL_BODY_STATUSES = new Set([204, 205, 304]);
14
26
 
15
27
  const SERVER_FUNCTION_METADATA = Symbol.for("solid.ServerFunctionMetadata");
16
28
  function getServerFunctionMetadata(fn) {
@@ -90,6 +102,7 @@ function serializeCookie(name, value, options = {}) {
90
102
  if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
91
103
  if (options.httpOnly) cookie += "; HttpOnly";
92
104
  if (options.secure) cookie += "; Secure";
105
+ if (options.partitioned) cookie += "; Partitioned";
93
106
  if (options.sameSite) {
94
107
  const sameSite = options.sameSite.toLowerCase();
95
108
  cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
@@ -114,8 +127,23 @@ function configureServerFunctionsCodec(codec) {
114
127
  function getServerFunctionsCodec() {
115
128
  return codecConfig.codec;
116
129
  }
117
- function subscribeFlightData(consumer) {
130
+ const UNNAMED_FLIGHT_SOURCE = "true";
131
+ const flightConfig = {
132
+ consumers: new Map()
133
+ };
134
+ function assertFlightSource(source) {
135
+ if (source === UNNAMED_FLIGHT_SOURCE || source === "" || source.includes(",")) {
136
+ 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).`);
137
+ }
138
+ }
139
+ function subscribeFlightData(sourceOrConsumer, maybeConsumer) {
140
+ const named = typeof sourceOrConsumer === "string";
141
+ if (named) assertFlightSource(sourceOrConsumer);
142
+ const source = named ? sourceOrConsumer : UNNAMED_FLIGHT_SOURCE;
143
+ const consumer = named ? maybeConsumer : sourceOrConsumer;
144
+ flightConfig.consumers.set(source, consumer);
118
145
  return () => {
146
+ if (flightConfig.consumers.get(source) === consumer) flightConfig.consumers.delete(source);
119
147
  };
120
148
  }
121
149
  function serverFunctionAddress(endpoint, id) {
@@ -127,10 +155,18 @@ function parseServerFunctionAddress(pathname, endpoint) {
127
155
  if (!pathname.startsWith(mount)) return null;
128
156
  const rest = pathname.slice(mount.length);
129
157
  if (!rest.startsWith("/")) return null;
130
- const segment = rest.slice(1);
158
+ let segment = rest.slice(1);
159
+ let data = false;
160
+ if (segment.startsWith("data/")) {
161
+ segment = segment.slice(5);
162
+ data = true;
163
+ }
131
164
  if (!segment || segment.includes("/")) return null;
132
165
  try {
133
- return decodeURIComponent(segment);
166
+ return {
167
+ id: decodeURIComponent(segment),
168
+ data
169
+ };
134
170
  } catch {
135
171
  return null;
136
172
  }
@@ -162,6 +198,28 @@ function decodeErrorHeaderValue(value) {
162
198
  }
163
199
  const INSTANCE_HEADER = "X-Server-Function-Instance";
164
200
  const BODY_FORMAT_HEADER = "X-Server-Function-Format";
201
+ const UNKNOWN_HEADER = "X-Server-Function-Unknown";
202
+ const REDIRECT_HEADER = "X-Server-Function-Redirect";
203
+ function decodeRedirectHeaderValue(value) {
204
+ if (typeof value !== "string") return undefined;
205
+ const at = value.indexOf(" ");
206
+ if (at < 0) return undefined;
207
+ const status = Number(value.slice(0, at));
208
+ const url = value.slice(at + 1);
209
+ if (!Number.isInteger(status) || !url) return undefined;
210
+ if (status !== 301 && status !== 302 && status !== 303 && status !== 307 && status !== 308) return undefined;
211
+ let parsed;
212
+ try {
213
+ parsed = new URL(url);
214
+ } catch {
215
+ return undefined;
216
+ }
217
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return undefined;
218
+ return {
219
+ status,
220
+ url
221
+ };
222
+ }
165
223
  const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
166
224
  const FILE_FORM_KEY = "__server_function_file__";
167
225
  const BodyFormat = {
@@ -204,7 +262,11 @@ function isJSONSafe(value) {
204
262
  const proto = Object.getPrototypeOf(v);
205
263
  if (proto !== Object.prototype && proto !== null) return false;
206
264
  if (Symbol.asyncIterator in v || Symbol.iterator in v) return false;
207
- for (const k in v) stack.push(v[k]);
265
+ for (const k in v) {
266
+ const descriptor = Object.getOwnPropertyDescriptor(v, k);
267
+ if (descriptor === undefined || !("value" in descriptor)) return false;
268
+ stack.push(descriptor.value);
269
+ }
208
270
  }
209
271
  }
210
272
  return true;
@@ -313,18 +375,34 @@ function createChunk(data) {
313
375
  class ChunkReader {
314
376
  constructor(stream) {
315
377
  this.reader = stream.getReader();
316
- this.buffer = new Uint8Array(0);
378
+ this.store = new Uint8Array(0);
379
+ this.buffer = this.store;
317
380
  this.done = false;
318
381
  }
319
382
  async readChunk() {
320
383
  const chunk = await this.reader.read();
321
- if (!chunk.done) {
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 {
384
+ if (chunk.done) {
327
385
  this.done = true;
386
+ return;
387
+ }
388
+ const incoming = chunk.value;
389
+ const store = this.store;
390
+ const start = this.buffer.byteOffset;
391
+ const end = start + this.buffer.length;
392
+ const needed = this.buffer.length + incoming.length;
393
+ if (end + incoming.length <= store.length) {
394
+ store.set(incoming, end);
395
+ this.buffer = store.subarray(start, end + incoming.length);
396
+ } else if (needed <= store.length) {
397
+ store.copyWithin(0, start, end);
398
+ store.set(incoming, this.buffer.length);
399
+ this.buffer = store.subarray(0, needed);
400
+ } else {
401
+ const grown = new Uint8Array(Math.max(needed, store.length * 2));
402
+ grown.set(this.buffer);
403
+ grown.set(incoming, this.buffer.length);
404
+ this.store = grown;
405
+ this.buffer = grown.subarray(0, needed);
328
406
  }
329
407
  }
330
408
  async next() {
@@ -366,6 +444,27 @@ class ChunkReader {
366
444
  }
367
445
  }
368
446
  }
447
+ const ERROR_TRAILER_PREFIX = "!";
448
+ function encodeErrorTrailer(error) {
449
+ const shaped = error instanceof Error ? error : new Error(String(error));
450
+ return ERROR_TRAILER_PREFIX + JSON.stringify(shaped.name && shaped.name !== "Error" ? {
451
+ name: shaped.name,
452
+ message: shaped.message
453
+ } : {
454
+ message: shaped.message
455
+ });
456
+ }
457
+ function errorFromTrailer(payload) {
458
+ let shape;
459
+ try {
460
+ shape = JSON.parse(payload.slice(1));
461
+ } catch {
462
+ shape = null;
463
+ }
464
+ const error = new Error(shape && typeof shape.message === "string" ? shape.message : "Server function result could not be delivered.");
465
+ if (shape && typeof shape.name === "string") error.name = shape.name;
466
+ return error;
467
+ }
369
468
  async function deserializeStream(source, codecOptions) {
370
469
  if (!source.body) {
371
470
  throw new Error("missing body");
@@ -373,11 +472,17 @@ async function deserializeStream(source, codecOptions) {
373
472
  const reader = new ChunkReader(source.body);
374
473
  const result = await reader.next();
375
474
  if (!result.done) {
475
+ if (result.value.startsWith(ERROR_TRAILER_PREFIX)) {
476
+ throw errorFromTrailer(result.value);
477
+ }
376
478
  const {
377
479
  createJSONDeserializer
378
480
  } = await import('@solidjs/web/serialization/decode');
379
481
  const deserializeChunk = createJSONDeserializer(codecOptions);
380
482
  function interpretChunk(chunk) {
483
+ if (chunk.startsWith(ERROR_TRAILER_PREFIX)) {
484
+ throw errorFromTrailer(chunk);
485
+ }
381
486
  return deserializeChunk(JSON.parse(chunk));
382
487
  }
383
488
  reader.drain(interpretChunk).then(() => deserializeChunk.abort(new Error("Server function stream ended unexpectedly.")), error => deserializeChunk.abort(error));
@@ -441,7 +546,8 @@ function copyInitHeaders(init) {
441
546
  for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
442
547
  return headers;
443
548
  }
444
- const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
549
+ const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, REDIRECT_HEADER, "Location",
550
+ ...COMPOSED_BODY_FRAMING].map(header => header.toLowerCase()));
445
551
  function fillsStubGap(key, headers, response) {
446
552
  if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
447
553
  if (response.body === null && (key === "content-type" || key === "content-length")) return false;
@@ -457,24 +563,16 @@ function commitEventResponse(response, event = getRequestEvent()) {
457
563
  if (fillsStubGap(key, response.headers, response)) hasGaps = true;
458
564
  });
459
565
  if (!cookies.length && !hasGaps) return response;
460
- try {
461
- for (const cookie of cookies) response.headers.append("Set-Cookie", cookie);
462
- stub.headers.forEach((value, key) => {
463
- if (fillsStubGap(key, response.headers, response)) response.headers.set(key, value);
464
- });
465
- return response;
466
- } catch {
467
- const headers = copyInitHeaders(response.headers);
468
- for (const cookie of cookies) headers.append("Set-Cookie", cookie);
469
- stub.headers.forEach((value, key) => {
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
- }
566
+ const headers = copyInitHeaders(response.headers);
567
+ for (const cookie of cookies) headers.append("Set-Cookie", cookie);
568
+ stub.headers.forEach((value, key) => {
569
+ if (fillsStubGap(key, headers, response)) headers.set(key, value);
570
+ });
571
+ return new Response(response.body, {
572
+ status: response.status,
573
+ statusText: response.statusText,
574
+ headers
575
+ });
478
576
  }
479
577
 
480
578
  function encodeInputValue(value) {
@@ -506,11 +604,35 @@ function encodeFlashCookie(url, result, input, thrown) {
506
604
  thrown: !!thrown,
507
605
  input: input.map(encodeInputValue)
508
606
  };
607
+ if (fitsCookie(payload)) return flashCookie(payload);
608
+ payload.truncated = true;
609
+ payload.input = [];
610
+ if (!fitsCookie(payload)) {
611
+ if (typeof payload.result === "string") {
612
+ let prefix = payload.result;
613
+ while (prefix.length > 0 && !fitsCookie({
614
+ ...payload,
615
+ result: prefix
616
+ })) {
617
+ prefix = prefix.slice(0, prefix.length >> 1);
618
+ }
619
+ payload.result = prefix.length > 0 ? prefix : true;
620
+ } else {
621
+ payload.result = true;
622
+ }
623
+ }
624
+ return flashCookie(payload);
625
+ }
626
+ function flashCookie(payload) {
509
627
  return serializeCookie(FLASH_COOKIE, JSON.stringify(payload), {
510
628
  secure: true,
511
629
  httpOnly: true
512
630
  });
513
631
  }
632
+ const COOKIE_PAIR_BUDGET = 4000;
633
+ function fitsCookie(payload) {
634
+ return FLASH_COOKIE.length + 1 + encodeURIComponent(JSON.stringify(payload)).length <= COOKIE_PAIR_BUDGET;
635
+ }
514
636
  function decodeFlashCookie(cookieHeader) {
515
637
  const match = parseCookieHeader(cookieHeader)[FLASH_COOKIE];
516
638
  if (!match) return;
@@ -518,12 +640,14 @@ function decodeFlashCookie(cookieHeader) {
518
640
  const payload = JSON.parse(match);
519
641
  if (!payload || !payload.result) return;
520
642
  const result = payload.error ? new Error(payload.result) : payload.result;
521
- return {
643
+ const submission = {
522
644
  input: Array.isArray(payload.input) ? payload.input.map(decodeInputValue) : [],
523
645
  url: payload.url,
524
646
  result: payload.thrown ? undefined : result,
525
647
  error: payload.thrown ? result : undefined
526
648
  };
649
+ if (payload.truncated) submission.truncated = true;
650
+ return submission;
527
651
  } catch (error) {
528
652
  console.error(error);
529
653
  }
@@ -538,7 +662,9 @@ const config = {
538
662
  transformDirectResult: undefined,
539
663
  handleNoJS: undefined,
540
664
  endpoint: "/_server",
541
- csrf: true
665
+ csrf: true,
666
+ bodySizeLimit: 1_048_576,
667
+ maxArguments: 1000
542
668
  };
543
669
  function configureServerFunctionsServer({
544
670
  provideEvent,
@@ -550,7 +676,9 @@ function configureServerFunctionsServer({
550
676
  handleNoJS,
551
677
  endpoint,
552
678
  csrf,
553
- codec
679
+ codec,
680
+ bodySizeLimit,
681
+ maxArguments
554
682
  } = {}) {
555
683
  if (provideEvent !== undefined) config.provideEvent = provideEvent;
556
684
  if (wrapInvocation !== undefined) config.wrapInvocation = wrapInvocation;
@@ -562,6 +690,16 @@ function configureServerFunctionsServer({
562
690
  if (endpoint !== undefined) config.endpoint = endpoint;
563
691
  if (csrf !== undefined) config.csrf = csrf;
564
692
  if (codec !== undefined) configureServerFunctionsCodec(codec);
693
+ if (bodySizeLimit !== undefined) config.bodySizeLimit = bodySizeLimit;
694
+ if (maxArguments !== undefined) config.maxArguments = maxArguments;
695
+ }
696
+ const flightSources = new Map();
697
+ function registerFlightDataSource(source, hook) {
698
+ assertFlightSource(source);
699
+ flightSources.set(source, hook);
700
+ return () => {
701
+ if (flightSources.get(source) === hook) flightSources.delete(source);
702
+ };
565
703
  }
566
704
  function provideEvent(event, fn) {
567
705
  if (config.provideEvent) return config.provideEvent(event, fn);
@@ -569,6 +707,52 @@ function provideEvent(event, fn) {
569
707
  if (ctx) return ctx.run(event, fn);
570
708
  throw new Error("No request event provider. Configure one with configureServerFunctionsServer({ provideEvent }).");
571
709
  }
710
+ function scopeDeferredResult(value, scope) {
711
+ if (value === null || typeof value !== "object" && typeof value !== "function") return value;
712
+ const promised = scope(() => nativePromise(value));
713
+ if (promised) {
714
+ return promised.then(result => scope(() => scopeDeferredResult(result, scope)));
715
+ }
716
+ if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) {
717
+ let reader;
718
+ return new ReadableStream({
719
+ async pull(controller) {
720
+ try {
721
+ const step = await scope(() => {
722
+ if (!reader) reader = value.getReader();
723
+ return reader.read();
724
+ });
725
+ if (step.done) controller.close();else controller.enqueue(step.value);
726
+ } catch (error) {
727
+ controller.error(error);
728
+ }
729
+ },
730
+ cancel(reason) {
731
+ return scope(() => reader ? reader.cancel(reason) : value.cancel(reason));
732
+ }
733
+ }, {
734
+ highWaterMark: 0
735
+ });
736
+ }
737
+ const scopedIterator = symbol => ({
738
+ [symbol]() {
739
+ const iterator = scope(() => value[symbol]());
740
+ return new Proxy(iterator, {
741
+ get(target, property) {
742
+ const member = Reflect.get(target, property, target);
743
+ return typeof member === "function" && (property === "next" || property === "return" || property === "throw") ? (...args) => scope(() => member.apply(target, args)) : member;
744
+ }
745
+ });
746
+ }
747
+ });
748
+ if (typeof value[Symbol.asyncIterator] === "function") {
749
+ return scopedIterator(Symbol.asyncIterator);
750
+ }
751
+ if (typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
752
+ return scopedIterator(Symbol.iterator);
753
+ }
754
+ return value;
755
+ }
572
756
  const REGISTRATIONS = new Map();
573
757
  const METHODS = new Map();
574
758
  const INVOCATIONS = new WeakMap();
@@ -583,6 +767,7 @@ function provideRPC() {
583
767
  }
584
768
  function registerServerFunction(id, callback) {
585
769
  provideRPC();
770
+ if (REGISTRATIONS.get(id) !== callback) METHODS.delete(id);
586
771
  REGISTRATIONS.set(id, callback);
587
772
  return callback;
588
773
  }
@@ -656,13 +841,17 @@ function createServerReference({
656
841
  const ogEvt = getRequestEvent();
657
842
  if (!ogEvt) throw new Error("Cannot call server function outside of a request");
658
843
  const evt = {
659
- ...ogEvt
844
+ ...ogEvt,
845
+ locals: {
846
+ ...ogEvt.locals
847
+ }
660
848
  };
661
849
  INVOCATIONS.set(evt, {
662
850
  id
663
851
  });
664
852
  evt.serverOnly = true;
665
- const result = provideEvent(evt, () => {
853
+ const scope = run => provideEvent(evt, run);
854
+ let result = provideEvent(evt, () => {
666
855
  const run = () => fn.apply(thisArg, args);
667
856
  return config.wrapInvocation ? config.wrapInvocation(run, {
668
857
  id,
@@ -671,19 +860,20 @@ function createServerReference({
671
860
  direct: true
672
861
  }) : run();
673
862
  });
863
+ result = scopeDeferredResult(result, scope);
674
864
  const transform = config.transformDirectResult;
675
865
  if (transform && result && typeof result.then === "function") {
676
- return result.then(value => transform(value, {
866
+ return result.then(value => scopeDeferredResult(transform(value, {
677
867
  id,
678
868
  args,
679
869
  event: evt
680
- }));
870
+ }), scope));
681
871
  }
682
- return transform ? transform(result, {
872
+ return transform ? scopeDeferredResult(transform(result, {
683
873
  id,
684
874
  args,
685
875
  event: evt
686
- }) : result;
876
+ }), scope) : result;
687
877
  }
688
878
  });
689
879
  return proxy;
@@ -727,18 +917,107 @@ function getServerFunctionInvocation() {
727
917
  function getEventServerFunctionInvocation(event) {
728
918
  return event && INVOCATIONS.get(event);
729
919
  }
730
- function resolveFunctionId(url) {
920
+ function resolveAddress(url) {
731
921
  return parseServerFunctionAddress(url.pathname, config.endpoint);
732
922
  }
733
- async function parseArguments(request, url, instance, codec) {
923
+ const DECODE_DEPTH_LIMIT = 64;
924
+ function assertDecodeDepth(value) {
925
+ let level = [value];
926
+ for (let depth = 0; level.length > 0; depth++) {
927
+ if (depth > DECODE_DEPTH_LIMIT) {
928
+ throw new TypeError("Server function arguments exceed the decode depth limit");
929
+ }
930
+ const next = [];
931
+ for (const node of level) {
932
+ if (node === null || typeof node !== "object") continue;
933
+ if (Array.isArray(node)) {
934
+ for (const child of node) next.push(child);
935
+ } else {
936
+ for (const key of Object.keys(node)) next.push(node[key]);
937
+ }
938
+ }
939
+ level = next;
940
+ }
941
+ }
942
+ const UNSAFE_ARGUMENT_KEYS = ["__proto__", "constructor", "prototype"];
943
+ function stripUnsafeArgumentKeys(value) {
944
+ const stack = [value];
945
+ const seen = new Set();
946
+ while (stack.length) {
947
+ const v = stack.pop();
948
+ if (v === null || typeof v !== "object" || seen.has(v)) continue;
949
+ seen.add(v);
950
+ for (const key of UNSAFE_ARGUMENT_KEYS) {
951
+ delete v[key];
952
+ }
953
+ for (const key of Object.keys(v)) stack.push(v[key]);
954
+ if (v instanceof Map) {
955
+ for (const [k, entry] of v) stack.push(k, entry);
956
+ } else if (v instanceof Set) {
957
+ for (const member of v) stack.push(member);
958
+ }
959
+ }
960
+ return value;
961
+ }
962
+ async function bufferBodyWithin(request, limit) {
963
+ const reader = request.body.getReader();
964
+ const signal = request.signal;
965
+ const chunks = [];
966
+ let total = 0;
967
+ const onAbort = () => {
968
+ reader.cancel(signal.reason).catch(() => {});
969
+ };
970
+ if (signal.aborted) onAbort();else signal.addEventListener("abort", onAbort, {
971
+ once: true
972
+ });
973
+ try {
974
+ for (;;) {
975
+ const {
976
+ done,
977
+ value
978
+ } = await reader.read();
979
+ if (signal.aborted) throw signal.reason;
980
+ if (done) break;
981
+ total += value.byteLength;
982
+ if (total > limit) {
983
+ reader.cancel().catch(() => {});
984
+ return null;
985
+ }
986
+ chunks.push(value);
987
+ }
988
+ } catch (error) {
989
+ reader.cancel(error).catch(() => {});
990
+ throw error;
991
+ } finally {
992
+ signal.removeEventListener("abort", onAbort);
993
+ reader.releaseLock();
994
+ }
995
+ const body = new Uint8Array(total);
996
+ let offset = 0;
997
+ for (const chunk of chunks) {
998
+ body.set(chunk, offset);
999
+ offset += chunk.byteLength;
1000
+ }
1001
+ return new Request(request, {
1002
+ body
1003
+ });
1004
+ }
1005
+ async function parseArguments(request, url, scripted, codec) {
734
1006
  const parsed = [];
735
1007
  const bodyFormat = request.method === "POST" ? request.headers.get(BODY_FORMAT_HEADER) : null;
736
1008
  const args = url.searchParams.get("args");
737
- if (args && (!instance || request.method === "GET" || bodyFormat !== BodyFormat.Serialized)) {
738
- const result = args.startsWith(";0x") ? await deserializeString(args, codec) : JSON.parse(args);
1009
+ if (args && (!scripted || request.method === "GET" || bodyFormat !== BodyFormat.Serialized)) {
1010
+ let result;
1011
+ if (args.startsWith(";0x")) {
1012
+ result = await deserializeString(args, codec);
1013
+ } else {
1014
+ result = JSON.parse(args);
1015
+ assertDecodeDepth(result);
1016
+ }
739
1017
  if (!Array.isArray(result)) {
740
1018
  throw new TypeError("Server function arguments must encode an array");
741
1019
  }
1020
+ stripUnsafeArgumentKeys(result);
742
1021
  for (const arg of result) {
743
1022
  parsed.push(arg);
744
1023
  }
@@ -748,18 +1027,37 @@ async function parseArguments(request, url, instance, codec) {
748
1027
  if (request.method === "POST" && request.body !== null) {
749
1028
  const decoded = await extractBody(request.clone(), codec);
750
1029
  if (bodyFormat === BodyFormat.Serialized || bodyFormat === BodyFormat.Json) {
751
- return decoded;
1030
+ if (bodyFormat === BodyFormat.Json) assertDecodeDepth(decoded);
1031
+ if (!Array.isArray(decoded)) {
1032
+ throw new TypeError("Server function arguments must encode an array");
1033
+ }
1034
+ return stripUnsafeArgumentKeys(decoded);
1035
+ }
1036
+ if (decoded === undefined) {
1037
+ if (bodyFormat === null && (await request.clone().arrayBuffer()).byteLength === 0) {
1038
+ return parsed;
1039
+ }
1040
+ throw new TypeError("Server function body carries no usable encoding");
752
1041
  }
753
1042
  parsed.push(decoded);
754
1043
  }
755
1044
  return parsed;
756
1045
  }
757
- async function foldFlightData(hook, event, headers, outcome, context = {}) {
1046
+ async function foldFlightData(hooks, event, headers, outcome, context = {}) {
758
1047
  if (outcome.value instanceof Response && outcome.value.body) return outcome.value;
759
1048
  digestOutcome(event, outcome);
760
- const data = await hook(event, outcome);
761
- if (data === undefined) return outcome.value;
762
- headers.set(SINGLE_FLIGHT_HEADER, "true");
1049
+ const folded = [];
1050
+ for (const [source, hook] of hooks) {
1051
+ try {
1052
+ const slice = await hook(event, outcome);
1053
+ if (slice !== undefined) folded.push([source, slice]);
1054
+ } catch (error) {
1055
+ console.error(`Error collecting flight data for source "${source}"`, error);
1056
+ }
1057
+ }
1058
+ if (folded.length === 0) return outcome.value;
1059
+ const data = Object.fromEntries(folded);
1060
+ headers.set(SINGLE_FLIGHT_HEADER, folded.map(([source]) => source).join(","));
763
1061
  if (context.transformFlightResult) {
764
1062
  const transformed = await context.transformFlightResult(event, {
765
1063
  value: outcome.value,
@@ -839,7 +1137,7 @@ function foldSetCookies(headers, setCookies) {
839
1137
  }
840
1138
  function mergeResponseHeaders(target, source) {
841
1139
  source.forEach((value, key) => {
842
- if (key !== "set-cookie") target.append(key, value);
1140
+ if (key !== "set-cookie" && !COMPOSED_BODY_FRAMING.has(key)) target.append(key, value);
843
1141
  });
844
1142
  if (source.getSetCookie) {
845
1143
  for (const cookie of source.getSetCookie()) target.append("Set-Cookie", cookie);
@@ -848,6 +1146,48 @@ function mergeResponseHeaders(target, source) {
848
1146
  }
849
1147
  }
850
1148
  const validRedirectStatuses = new Set([301, 302, 303, 307, 308]);
1149
+ function maskRedirect(headers, response, requestUrl) {
1150
+ const target = response.headers && response.headers.get("Location");
1151
+ if (target) {
1152
+ headers.set(REDIRECT_HEADER, `${response.status} ${new URL(target, requestUrl)}`);
1153
+ }
1154
+ headers.delete("Location");
1155
+ }
1156
+ const BOUNDED_COMPOSED_HEADERS = [REDIRECT_HEADER, "Location", REVALIDATE_HEADER];
1157
+ function enforceComposedHeaderInvariants(response) {
1158
+ for (const name of BOUNDED_COMPOSED_HEADERS) {
1159
+ const value = response.headers.get(name);
1160
+ if (value === null) continue;
1161
+ if (value.length > RESPONSE_HEADER_VALUE_LIMIT) {
1162
+ 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);
1163
+ }
1164
+ if (name === REVALIDATE_HEADER) continue;
1165
+ const target = name === REDIRECT_HEADER ? value.slice(value.indexOf(" ") + 1) : value;
1166
+ if (!isHttpNavigationTarget(target)) {
1167
+ 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);
1168
+ }
1169
+ }
1170
+ return response;
1171
+ }
1172
+ function refuseComposedHeader(response, name, headerMessage, body) {
1173
+ if (response.body) {
1174
+ try {
1175
+ const cancelled = response.body.cancel();
1176
+ if (cancelled && typeof cancelled.then === "function") cancelled.then(undefined, () => {});
1177
+ } catch {}
1178
+ }
1179
+ const headers = new Headers();
1180
+ headers.set(ERROR_HEADER, boundedErrorHeaderValue(DEV ? headerMessage : GENERIC_SERVER_ERROR_MESSAGE));
1181
+ return new Response(body, {
1182
+ status: 500,
1183
+ headers
1184
+ });
1185
+ }
1186
+ function warnScripted304(functionId) {
1187
+ if (DEV) {
1188
+ 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.`);
1189
+ }
1190
+ }
851
1191
  function createNoJSHandler({
852
1192
  base = ""
853
1193
  } = {}) {
@@ -891,44 +1231,291 @@ function isFormPost(request) {
891
1231
  const type = request.headers.get("content-type") || "";
892
1232
  return type.startsWith("application/x-www-form-urlencoded") || type.startsWith("multipart/form-data");
893
1233
  }
894
- function serializeResponseStream(value, codecOptions, signal) {
895
- let closeIterator = null;
896
- let closed = false;
897
- let cancelSerialize = null;
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();
1234
+ function guardFailures(value, state) {
1235
+ if (!state) state = {
1236
+ seen: new WeakMap(),
1237
+ cyclic: new WeakSet()
905
1238
  };
906
- if (value !== null && typeof value === "object" && typeof value[Symbol.asyncIterator] === "function") {
1239
+ const entered = enterGuard(value, state);
1240
+ if (!(entered instanceof Frame)) return entered;
1241
+ const stack = [entered];
1242
+ let delivered = NOTHING;
1243
+ for (;;) {
1244
+ const top = stack[stack.length - 1];
1245
+ const items = top.items;
1246
+ let pushed = null;
1247
+ while (top.i < items.length) {
1248
+ const i = top.i;
1249
+ let original;
1250
+ if (top.kind === OBJECT) {
1251
+ const descriptor = top.descriptors[items[i]];
1252
+ if ("value" in descriptor) {
1253
+ original = descriptor.value;
1254
+ } else if (typeof descriptor.get === "function") {
1255
+ if (top.accessorRead !== i) {
1256
+ try {
1257
+ top.accessorValue = descriptor.get.call(top.value);
1258
+ } catch (error) {
1259
+ throw sanitizeServerError(error);
1260
+ }
1261
+ top.accessorRead = i;
1262
+ }
1263
+ original = top.accessorValue;
1264
+ } else {
1265
+ top.i++;
1266
+ continue;
1267
+ }
1268
+ } else {
1269
+ original = items[i];
1270
+ }
1271
+ let guarded;
1272
+ if (delivered !== NOTHING) {
1273
+ guarded = delivered;
1274
+ delivered = NOTHING;
1275
+ } else {
1276
+ guarded = enterGuard(original, state);
1277
+ if (guarded instanceof Frame) {
1278
+ pushed = guarded;
1279
+ break;
1280
+ }
1281
+ }
1282
+ if (top.kind === ARRAY) {
1283
+ if (guarded !== original) {
1284
+ top.next[i] = guarded;
1285
+ top.changed = true;
1286
+ }
1287
+ } else if (top.kind === MAP) {
1288
+ if ((i & 1) === 0) top.pendingKey = guarded;else top.next.set(top.pendingKey, guarded);
1289
+ if (guarded !== original) top.changed = true;
1290
+ } else if (top.kind === SET) {
1291
+ top.next.add(guarded);
1292
+ if (guarded !== original) top.changed = true;
1293
+ } else if (guarded !== original || top.accessorRead === i) {
1294
+ Object.defineProperty(top.next, items[i], {
1295
+ value: guarded,
1296
+ writable: true,
1297
+ configurable: true,
1298
+ enumerable: top.descriptors[items[i]].enumerable
1299
+ });
1300
+ top.changed = true;
1301
+ }
1302
+ top.i++;
1303
+ }
1304
+ if (pushed !== null) {
1305
+ stack.push(pushed);
1306
+ continue;
1307
+ }
1308
+ stack.pop();
1309
+ const out = keepGuarded(top.value, top.next, top.changed, state);
1310
+ if (stack.length === 0) return out;
1311
+ delivered = out;
1312
+ }
1313
+ }
1314
+ const NOTHING = Symbol();
1315
+ const ARRAY = 0;
1316
+ const MAP = 1;
1317
+ const SET = 2;
1318
+ const OBJECT = 3;
1319
+ class Frame {
1320
+ constructor(kind, value, next, items, descriptors) {
1321
+ this.kind = kind;
1322
+ this.value = value;
1323
+ this.next = next;
1324
+ this.items = items;
1325
+ this.descriptors = descriptors;
1326
+ this.i = 0;
1327
+ this.changed = false;
1328
+ this.accessorRead = -1;
1329
+ this.accessorValue = undefined;
1330
+ this.pendingKey = undefined;
1331
+ }
1332
+ }
1333
+ function guardOperation(state, run) {
1334
+ return state.scope ? state.scope(run) : run();
1335
+ }
1336
+ function enterGuard(value, state) {
1337
+ if (value === null || typeof value !== "object") return value;
1338
+ if (state.seen.has(value)) {
1339
+ state.cyclic.add(value);
1340
+ return state.seen.get(value);
1341
+ }
1342
+ if (typeof ReadableStream !== "undefined" && value instanceof ReadableStream) {
1343
+ let reader;
1344
+ const gate = state.gate;
1345
+ let finished = false;
1346
+ const close = () => {
1347
+ if (finished) return;
1348
+ finished = true;
1349
+ try {
1350
+ const cancelled = guardOperation(state, () => reader ? reader.cancel() : value.cancel());
1351
+ if (cancelled && typeof cancelled.then === "function") cancelled.then(undefined, () => {});
1352
+ } catch {}
1353
+ };
1354
+ const guardedStream = new ReadableStream({
1355
+ async pull(controller) {
1356
+ try {
1357
+ if (gate && !finished && !gate.wantsMore()) await gate.awaitDemand();
1358
+ if (finished) {
1359
+ controller.close();
1360
+ return;
1361
+ }
1362
+ if (!reader) reader = guardOperation(state, () => value.getReader());
1363
+ const {
1364
+ done,
1365
+ value: chunk
1366
+ } = await guardOperation(state, () => reader.read());
1367
+ done ? controller.close() : controller.enqueue(guardOperation(state, () => guardFailures(chunk, state)));
1368
+ } catch (error) {
1369
+ controller.error(guardOperation(state, () => sanitizeServerError(error)));
1370
+ }
1371
+ },
1372
+ cancel(reason) {
1373
+ finished = true;
1374
+ return guardOperation(state, () => reader ? reader.cancel(reason) : value.cancel(reason));
1375
+ }
1376
+ });
1377
+ if (gate) gate.onOpen(close);
1378
+ state.seen.set(value, guardedStream);
1379
+ return guardedStream;
1380
+ }
1381
+ if (typeof value.then === "function") {
1382
+ const guardedPromise = Promise.resolve(value).then(resolved => guardOperation(state, () => guardFailures(resolved, state)), error => {
1383
+ throw guardOperation(state, () => sanitizeServerError(error));
1384
+ });
1385
+ guardedPromise.catch(() => {});
1386
+ state.seen.set(value, guardedPromise);
1387
+ return guardedPromise;
1388
+ }
1389
+ if (typeof value[Symbol.asyncIterator] === "function") {
907
1390
  const source = value;
908
- value = {
1391
+ const gate = state.gate;
1392
+ const guardedIterable = {
909
1393
  [Symbol.asyncIterator]() {
910
- const it = source[Symbol.asyncIterator]();
1394
+ const iterator = guardOperation(state, () => source[Symbol.asyncIterator]());
911
1395
  let finished = false;
912
- closeIterator = () => {
1396
+ const close = () => {
913
1397
  if (finished) return;
914
1398
  finished = true;
915
1399
  try {
916
- const returned = it.return && it.return();
1400
+ const returned = iterator.return && guardOperation(state, () => iterator.return());
917
1401
  if (returned && typeof returned.then === "function") returned.then(undefined, () => {});
918
1402
  } catch {}
919
1403
  };
920
- if (closed) closeIterator();
1404
+ if (gate) gate.onOpen(close);
1405
+ const step = () => finished ? Promise.resolve({
1406
+ done: true,
1407
+ value: undefined
1408
+ }) : guardOperation(state, () => iterator.next()).then(step => {
1409
+ if (step.done) {
1410
+ finished = true;
1411
+ return step;
1412
+ }
1413
+ return {
1414
+ done: false,
1415
+ value: guardOperation(state, () => guardFailures(step.value, state))
1416
+ };
1417
+ }, error => {
1418
+ throw guardOperation(state, () => sanitizeServerError(error));
1419
+ });
921
1420
  return {
922
- next: () => finished ? Promise.resolve({
923
- done: true,
924
- value: undefined
925
- }) : it.next()
1421
+ next: () => finished || !gate || gate.wantsMore() ? step() : gate.awaitDemand().then(step),
1422
+ return: () => {
1423
+ close();
1424
+ return Promise.resolve({
1425
+ done: true,
1426
+ value: undefined
1427
+ });
1428
+ }
926
1429
  };
927
1430
  }
928
1431
  };
1432
+ state.seen.set(value, guardedIterable);
1433
+ return guardedIterable;
1434
+ }
1435
+ if (state.scope && typeof value[Symbol.iterator] === "function" && !Array.isArray(value) && !(value instanceof Map) && !(value instanceof Set) && !ArrayBuffer.isView(value)) {
1436
+ const scopedIterable = scopeDeferredResult(value, state.scope);
1437
+ state.seen.set(value, scopedIterable);
1438
+ return scopedIterable;
1439
+ }
1440
+ if (Array.isArray(value)) {
1441
+ const next = value.slice();
1442
+ state.seen.set(value, next);
1443
+ return new Frame(ARRAY, value, next, value, null);
1444
+ }
1445
+ if (value instanceof Map) {
1446
+ const next = new Map();
1447
+ state.seen.set(value, next);
1448
+ const items = [];
1449
+ for (const entry of value) items.push(entry[0], entry[1]);
1450
+ return new Frame(MAP, value, next, items, null);
1451
+ }
1452
+ if (value instanceof Set) {
1453
+ const next = new Set();
1454
+ state.seen.set(value, next);
1455
+ return new Frame(SET, value, next, [...value], null);
1456
+ }
1457
+ const prototype = Object.getPrototypeOf(value);
1458
+ if (prototype !== Object.prototype && prototype !== null) {
1459
+ state.seen.set(value, value);
1460
+ return value;
929
1461
  }
1462
+ const descriptors = Object.getOwnPropertyDescriptors(value);
1463
+ for (const key of Object.keys(descriptors)) {
1464
+ descriptors[key].configurable = true;
1465
+ if ("value" in descriptors[key]) descriptors[key].writable = true;
1466
+ }
1467
+ const next = Object.create(prototype, descriptors);
1468
+ state.seen.set(value, next);
1469
+ return new Frame(OBJECT, value, next, Object.keys(value), descriptors);
1470
+ }
1471
+ function keepGuarded(value, next, changed, state) {
1472
+ if (changed || state.cyclic.has(value)) return next;
1473
+ state.seen.set(value, value);
1474
+ return value;
1475
+ }
1476
+ function serializeResponseStream(value, codecOptions, signal, scope) {
1477
+ let closed = false;
1478
+ let streamController = null;
1479
+ let demandWaiters = null;
1480
+ const wantsMore = () => streamController !== null && streamController.desiredSize > 0;
1481
+ const awaitDemand = () => new Promise(resolve => (demandWaiters ??= []).push(resolve));
1482
+ const supplyDemand = () => {
1483
+ const resolvers = demandWaiters;
1484
+ demandWaiters = null;
1485
+ if (resolvers) for (const resolve of resolvers) resolve();
1486
+ };
1487
+ const sourceClosers = new Set();
1488
+ const gate = {
1489
+ wantsMore,
1490
+ awaitDemand,
1491
+ onOpen(close) {
1492
+ if (closed) close();else sourceClosers.add(close);
1493
+ }
1494
+ };
1495
+ const guardState = {
1496
+ seen: new WeakMap(),
1497
+ cyclic: new WeakSet(),
1498
+ gate,
1499
+ scope
1500
+ };
1501
+ value = guardOperation(guardState, () => guardFailures(value, guardState));
1502
+ let cancelSerialize = null;
1503
+ let onAbort = null;
1504
+ const finishSource = () => {
1505
+ for (const close of sourceClosers) close();
1506
+ sourceClosers.clear();
1507
+ supplyDemand();
1508
+ };
1509
+ const teardown = () => {
1510
+ if (closed) return;
1511
+ closed = true;
1512
+ if (onAbort) signal.removeEventListener("abort", onAbort);
1513
+ if (cancelSerialize) cancelSerialize();
1514
+ finishSource();
1515
+ };
930
1516
  return new ReadableStream({
931
1517
  async start(controller) {
1518
+ streamController = controller;
932
1519
  if (signal) {
933
1520
  if (signal.aborted) {
934
1521
  teardown();
@@ -964,29 +1551,54 @@ function serializeResponseStream(value, codecOptions, signal) {
964
1551
  if (closed) return;
965
1552
  closed = true;
966
1553
  if (onAbort) signal.removeEventListener("abort", onAbort);
1554
+ finishSource();
967
1555
  controller.close();
968
1556
  },
969
1557
  onError(error) {
970
1558
  if (closed) return;
971
1559
  closed = true;
972
1560
  if (onAbort) signal.removeEventListener("abort", onAbort);
973
- controller.error(error);
1561
+ finishSource();
1562
+ try {
1563
+ const delivered = sanitizeServerError(DEV && error instanceof Error ? new Error(`Server function result could not be encoded: ${error.message}`) : error);
1564
+ controller.enqueue(createChunk(encodeErrorTrailer(delivered)));
1565
+ controller.close();
1566
+ } catch {
1567
+ try {
1568
+ controller.error(error);
1569
+ } catch {}
1570
+ }
974
1571
  }
975
1572
  });
976
1573
  },
1574
+ pull() {
1575
+ supplyDemand();
1576
+ },
977
1577
  cancel() {
978
1578
  teardown();
979
1579
  }
980
1580
  });
981
1581
  }
982
- function serializedResponse(value, headers, codec, signal) {
1582
+ function serializedResponse(value, headers, codec, signal, scope) {
983
1583
  headers.set(BODY_FORMAT_HEADER, BodyFormat.Serialized);
984
1584
  headers.set("Content-Type", "text/plain");
985
- return new Response(serializeResponseStream(value, codec, signal), {
1585
+ return new Response(serializeResponseStream(value, codec, signal, scope), {
986
1586
  headers
987
1587
  });
988
1588
  }
989
- function encodeResult(value, headers, status, codec, signal) {
1589
+ function encodeResult(value, headers, status, codec, signal, scope) {
1590
+ if (NULL_BODY_STATUSES.has(status)) {
1591
+ if (value === undefined || value === null) {
1592
+ headers.set(BODY_FORMAT_HEADER, BodyFormat.Void);
1593
+ return new Response(null, {
1594
+ status,
1595
+ headers
1596
+ });
1597
+ }
1598
+ 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.`);
1599
+ headers.set(ERROR_HEADER, encodeErrorHeaderValue(error.message));
1600
+ return encodeResult(error, headers, 500, codec, signal, scope);
1601
+ }
990
1602
  const direct = getHeadersAndBody(value);
991
1603
  if (direct) {
992
1604
  for (const [key, val] of Object.entries(direct.headers || {})) {
@@ -1005,21 +1617,37 @@ function encodeResult(value, headers, status, codec, signal) {
1005
1617
  });
1006
1618
  }
1007
1619
  try {
1008
- if (isJSONSafe(value)) {
1620
+ const jsonSafe = scope ? scope(() => isJSONSafe(value)) : isJSONSafe(value);
1621
+ if (jsonSafe) {
1009
1622
  headers.set(BODY_FORMAT_HEADER, BodyFormat.Json);
1010
1623
  headers.set("Content-Type", "application/json");
1011
- return new Response(JSON.stringify(value), {
1624
+ const body = scope ? scope(() => JSON.stringify(value)) : JSON.stringify(value);
1625
+ return new Response(body, {
1012
1626
  status,
1013
1627
  headers
1014
1628
  });
1015
1629
  }
1016
1630
  } catch {
1017
1631
  }
1018
- const response = serializedResponse(value, headers, codec, signal);
1019
- return status === 200 ? response : new Response(response.body, {
1020
- status,
1021
- headers
1022
- });
1632
+ try {
1633
+ const response = serializedResponse(value, headers, codec, signal, scope);
1634
+ return status === 200 ? response : new Response(response.body, {
1635
+ status,
1636
+ headers
1637
+ });
1638
+ } catch (error) {
1639
+ throw DEV && error instanceof Error ? new Error(`Server function result could not be encoded: ${error.message}`) : error;
1640
+ }
1641
+ }
1642
+ const ERROR_HEADER_VALUE_LIMIT = 1024;
1643
+ function boundedErrorHeaderValue(message) {
1644
+ let label = message.length > 256 ? message.slice(0, 256) : message;
1645
+ let encoded = encodeErrorHeaderValue(label);
1646
+ while (encoded.length > ERROR_HEADER_VALUE_LIMIT && label.length > 1) {
1647
+ label = label.slice(0, Math.ceil(label.length / 2));
1648
+ encoded = encodeErrorHeaderValue(label);
1649
+ }
1650
+ return encoded;
1023
1651
  }
1024
1652
  const GENERIC_SERVER_ERROR_MESSAGE = "Internal Server Error";
1025
1653
  let DEV = false === true;
@@ -1043,11 +1671,12 @@ function serverFunctionUrl(id, boundArgs) {
1043
1671
  return `${address}?args=${encodeURIComponent(JSON.stringify(boundArgs))}`;
1044
1672
  }
1045
1673
  function parseServerFunctionUrl(url) {
1046
- return parseServerFunctionAddress(new URL(url, "http://localhost").pathname, config.endpoint);
1674
+ const parsed = parseServerFunctionAddress(new URL(url, "http://localhost").pathname, config.endpoint);
1675
+ return parsed && parsed.id;
1047
1676
  }
1048
1677
  async function matchesOrigin(origin, request, matcher) {
1049
1678
  if (matcher === undefined) return origin === new URL(request.url).origin;
1050
- if (typeof matcher === "function") return !!(await matcher(origin, request));
1679
+ if (typeof matcher === "function") return (await matcher(origin, request)) === true;
1051
1680
  return Array.isArray(matcher) ? matcher.includes(origin) : origin === matcher;
1052
1681
  }
1053
1682
  async function allowsServerFunctionRequest(request, options) {
@@ -1099,14 +1728,37 @@ function forbiddenResponse() {
1099
1728
  }
1100
1729
  }));
1101
1730
  }
1731
+ function nativePromise(value) {
1732
+ if (value instanceof Promise) return value;
1733
+ try {
1734
+ if (Object.prototype.toString.call(value) === "[object Promise]") return Promise.prototype.then.call(value, value => value);
1735
+ } catch {}
1736
+ }
1102
1737
  async function handleServerFunctionRequest(request, options = {}) {
1103
- const codec = options.codec !== undefined ? options.codec : getServerFunctionsCodec();
1738
+ const codec = {
1739
+ ...(options.codec !== undefined ? options.codec : getServerFunctionsCodec())
1740
+ };
1741
+ codec.serializeErrorStacks ??= DEV;
1104
1742
  const url = new URL(request.url);
1105
1743
  const method = request.method;
1106
- const functionId = resolveFunctionId(url);
1744
+ const address = resolveAddress(url);
1745
+ const functionId = address && address.id;
1107
1746
  const declaredRead = (method === "GET" || method === "HEAD") && functionId !== null && METHODS.get(functionId) === "GET";
1108
1747
  const csrf = options.csrf !== undefined ? options.csrf : config.csrf;
1109
- const protectsRequest = csrf !== false && !declaredRead;
1748
+ const protectsRequest = csrf !== false && (!declaredRead || typeof csrf === "object" && csrf.protectDeclaredReads === true);
1749
+ let serverFunction;
1750
+ if (functionId) {
1751
+ try {
1752
+ serverFunction = getServerFunction(functionId);
1753
+ } catch {
1754
+ return finalizeTransportResponse(new Response(DEV ? `Unknown server function: ${functionId}` : null, {
1755
+ status: 404,
1756
+ headers: {
1757
+ [UNKNOWN_HEADER]: "true"
1758
+ }
1759
+ }), method);
1760
+ }
1761
+ }
1110
1762
  if (protectsRequest && !(await allowsServerFunctionRequest(request, csrf === true ? {} : csrf))) {
1111
1763
  return finalizeTransportResponse(forbiddenResponse(), method);
1112
1764
  }
@@ -1117,15 +1769,7 @@ async function handleServerFunctionRequest(request, options = {}) {
1117
1769
  });
1118
1770
  return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1119
1771
  }
1120
- let serverFunction;
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
- }
1772
+ const scripted = address.data;
1129
1773
  if (method !== "POST" && !declaredRead) {
1130
1774
  const response = new Response(DEV ? `Method not allowed for server function: ${functionId}` : null, {
1131
1775
  status: 405,
@@ -1135,25 +1779,103 @@ async function handleServerFunctionRequest(request, options = {}) {
1135
1779
  });
1136
1780
  return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1137
1781
  }
1138
- const event = options.createEvent ? options.createEvent(request) : {
1139
- request,
1140
- locals: {}
1782
+ const bodySizeLimit = options.bodySizeLimit !== undefined ? options.bodySizeLimit : config.bodySizeLimit;
1783
+ const argsEncoding = url.searchParams.get("args");
1784
+ if (argsEncoding !== null && argsEncoding.length > bodySizeLimit) {
1785
+ const response = new Response(DEV ? "Server function arguments exceed the configured bodySizeLimit" : null, {
1786
+ status: 413
1787
+ });
1788
+ return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1789
+ }
1790
+ if (method === "POST" && request.body !== null && bodySizeLimit !== Infinity) {
1791
+ const raw = request.headers.get("content-length");
1792
+ const declared = raw !== null && /^\d+$/.test(raw) ? Number(raw) : NaN;
1793
+ if (declared > bodySizeLimit) {
1794
+ const response = new Response(DEV ? "Server function request body exceeds the configured bodySizeLimit" : null, {
1795
+ status: 413
1796
+ });
1797
+ return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1798
+ }
1799
+ if (!(declared > 0)) {
1800
+ let bounded;
1801
+ try {
1802
+ bounded = await bufferBodyWithin(request, bodySizeLimit);
1803
+ } catch {
1804
+ const response = new Response(DEV ? "Malformed server function arguments" : null, {
1805
+ status: 400
1806
+ });
1807
+ return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1808
+ }
1809
+ if (bounded === null) {
1810
+ const response = new Response(DEV ? "Server function request body exceeds the configured bodySizeLimit" : null, {
1811
+ status: 413
1812
+ });
1813
+ return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1814
+ }
1815
+ request = bounded;
1816
+ }
1817
+ }
1818
+ let event;
1819
+ try {
1820
+ event = options.createEvent ? options.createEvent(request) : {
1821
+ request,
1822
+ locals: {}
1823
+ };
1824
+ const promised = nativePromise(event);
1825
+ if (promised) event = await promised;
1826
+ } catch (error) {
1827
+ const safe = sanitizeServerError(error);
1828
+ const message = safe instanceof Error ? safe.message : String(safe);
1829
+ const headers = new Headers();
1830
+ headers.set(ERROR_HEADER, boundedErrorHeaderValue(message));
1831
+ const response = scripted ? encodeResult(safe, headers, 500, codec, request.signal) : new Response(DEV ? message : null, {
1832
+ status: 500
1833
+ });
1834
+ return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1835
+ }
1836
+ const refuseCommitted = raw => {
1837
+ const response = commitEventResponse(raw, event);
1838
+ return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1141
1839
  };
1142
1840
  const provide = options.provideEvent || provideEvent;
1841
+ const scope = run => provide(event, run);
1143
1842
  const flightHook = options.collectFlightData !== undefined ? options.collectFlightData : config.collectFlightData;
1144
1843
  const transformResult = options.transformResult !== undefined ? options.transformResult : config.transformResult;
1145
1844
  const wrapInvocation = options.wrapInvocation !== undefined ? options.wrapInvocation : config.wrapInvocation;
1146
1845
  const transformFlightResult = options.transformFlightResult !== undefined ? options.transformFlightResult : config.transformFlightResult;
1147
- const handleNoJS = options.handleNoJS !== undefined ? options.handleNoJS : config.handleNoJS !== undefined ? config.handleNoJS : isFormPost(request) ? defaultNoJSHandler || (defaultNoJSHandler = createNoJSHandler()) : undefined;
1148
- const collectsFlight = !!(flightHook && instance && request.headers.has(SINGLE_FLIGHT_HEADER));
1846
+ let handleNoJS = options.handleNoJS !== undefined ? options.handleNoJS : config.handleNoJS;
1847
+ if (handleNoJS === undefined && !scripted && isFormPost(request)) {
1848
+ const fetchMode = request.headers.get("Sec-Fetch-Mode");
1849
+ if (fetchMode === null || fetchMode === "navigate") {
1850
+ handleNoJS = defaultNoJSHandler || (defaultNoJSHandler = createNoJSHandler());
1851
+ } else {
1852
+ 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, {
1853
+ status: 400
1854
+ });
1855
+ return refuseCommitted(response);
1856
+ }
1857
+ }
1858
+ const flightHeader = scripted && method === "POST" ? request.headers.get(SINGLE_FLIGHT_HEADER) : null;
1859
+ const flightHooks = flightHeader ? flightHeader.split(",").flatMap(source => {
1860
+ const hook = source === "true" ? flightHook : flightSources.get(source);
1861
+ return hook ? [[source, hook]] : [];
1862
+ }) : [];
1863
+ const collectsFlight = flightHooks.length > 0;
1149
1864
  let parsed;
1150
1865
  try {
1151
- parsed = await parseArguments(request, url, instance, codec);
1866
+ parsed = await parseArguments(request, url, scripted, codec);
1152
1867
  } catch {
1153
1868
  const response = new Response(DEV ? "Malformed server function arguments" : null, {
1154
1869
  status: 400
1155
1870
  });
1156
- return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1871
+ return refuseCommitted(response);
1872
+ }
1873
+ const maxArguments = options.maxArguments !== undefined ? options.maxArguments : config.maxArguments;
1874
+ if (parsed.length > maxArguments) {
1875
+ const response = new Response(DEV ? "Server function call exceeds the configured maxArguments" : null, {
1876
+ status: 400
1877
+ });
1878
+ return refuseCommitted(response);
1157
1879
  }
1158
1880
  const flightContext = {
1159
1881
  id: functionId,
@@ -1167,7 +1889,8 @@ async function handleServerFunctionRequest(request, options = {}) {
1167
1889
  const headers = new Headers();
1168
1890
  const dispatch = async () => {
1169
1891
  try {
1170
- let result = await provide(event, async () => {
1892
+ let invocations = 0;
1893
+ const invokeOnce = async () => {
1171
1894
  INVOCATIONS.set(event, {
1172
1895
  id: functionId
1173
1896
  });
@@ -1179,7 +1902,16 @@ async function handleServerFunctionRequest(request, options = {}) {
1179
1902
  request,
1180
1903
  direct: false
1181
1904
  }) : run();
1905
+ };
1906
+ let result = await provide(event, () => {
1907
+ if (++invocations > 1) {
1908
+ throw new Error("provideEvent invoked the server function callback more than once: a second " + "invocation would commit the call's side effects twice. The hook must call " + "fn exactly once and return its result.");
1909
+ }
1910
+ return invokeOnce();
1182
1911
  });
1912
+ if (invocations !== 1) {
1913
+ throw new Error(invocations === 0 ? "provideEvent returned without invoking the server function callback: the call " + "would have answered as a void success without running the function. The hook " + "must call fn exactly once and return its result." : "provideEvent invoked the server function callback more than once: a second " + "invocation would commit the call's side effects twice. The hook must call " + "fn exactly once and return its result.");
1914
+ }
1183
1915
  if (transformResult) {
1184
1916
  result = await transformResult(event, result, flightContext);
1185
1917
  }
@@ -1190,25 +1922,29 @@ async function handleServerFunctionRequest(request, options = {}) {
1190
1922
  response,
1191
1923
  value
1192
1924
  } = result;
1193
- if (!instance && !handleNoJS && response && response.body) {
1925
+ if (!scripted && !handleNoJS && response && response.body) {
1194
1926
  return response;
1195
1927
  }
1196
1928
  if (response && response.headers) {
1197
1929
  mergeResponseHeaders(headers, response.headers);
1198
1930
  }
1199
- if (response && response.status && (response.status < 300 || response.status >= 400)) {
1931
+ if (response && response.status && (!scripted || !validRedirectStatuses.has(response.status))) {
1200
1932
  status = response.status;
1933
+ } else if (response && response.status) {
1934
+ maskRedirect(headers, response, request.url);
1201
1935
  }
1202
1936
  metadata = response;
1203
1937
  result = value;
1204
1938
  } else if (result instanceof Response) {
1205
1939
  if (result.headers && result.headers.has("X-Content-Raw")) return result;
1206
- if (instance) {
1940
+ if (scripted) {
1207
1941
  if (result.headers) {
1208
1942
  mergeResponseHeaders(headers, result.headers);
1209
1943
  }
1210
- if (result.status && (result.status < 300 || result.status >= 400)) {
1944
+ if (result.status && !validRedirectStatuses.has(result.status)) {
1211
1945
  status = result.status;
1946
+ } else if (result.status) {
1947
+ maskRedirect(headers, result, request.url);
1212
1948
  }
1213
1949
  metadata = result;
1214
1950
  if (result.body == null) {
@@ -1217,7 +1953,7 @@ async function handleServerFunctionRequest(request, options = {}) {
1217
1953
  }
1218
1954
  }
1219
1955
  if (collectsFlight) {
1220
- result = await foldFlightData(flightHook, event, headers, {
1956
+ result = await foldFlightData(flightHooks, event, headers, {
1221
1957
  id: functionId,
1222
1958
  value: result,
1223
1959
  response: metadata,
@@ -1226,19 +1962,37 @@ async function handleServerFunctionRequest(request, options = {}) {
1226
1962
  }, flightContext);
1227
1963
  if (result instanceof Response && result.headers.has("X-Content-Raw")) return result;
1228
1964
  }
1229
- if (!instance) {
1230
- if (handleNoJS) return handleNoJS(result, request, parsed);
1965
+ if (!scripted) {
1966
+ if (handleNoJS) return handleNoJS(result ?? metadata, request, parsed);
1231
1967
  if (result instanceof Response) return result;
1232
- return encodeResult(result, headers, 200, codec, request.signal);
1968
+ return encodeResult(result, headers, status, codec, request.signal, scope);
1233
1969
  }
1234
- return encodeResult(result, headers, status, codec, request.signal);
1970
+ if (status === 304) warnScripted304(functionId);
1971
+ return encodeResult(result, headers, status, codec, request.signal, scope);
1235
1972
  } catch (x) {
1973
+ const respondThrown = value => {
1974
+ const safe = sanitizeServerError(value);
1975
+ if (!scripted) {
1976
+ if (handleNoJS) return handleNoJS(safe, request, parsed, true);
1977
+ const message = safe instanceof Error ? safe.message : String(safe);
1978
+ return new Response(DEV ? message : null, {
1979
+ status: 500
1980
+ });
1981
+ }
1982
+ const error = safe instanceof Error ? safe.message : typeof safe === "string" ? safe : "true";
1983
+ headers.set(ERROR_HEADER, boundedErrorHeaderValue(error));
1984
+ return encodeResult(safe, headers, 500, codec, request.signal, scope);
1985
+ };
1236
1986
  if (x instanceof Response || isResponseEnvelope(x)) {
1237
1987
  if (transformResult) {
1238
- x = await transformResult(event, x, {
1239
- ...flightContext,
1240
- thrown: true
1241
- });
1988
+ try {
1989
+ x = await transformResult(event, x, {
1990
+ ...flightContext,
1991
+ thrown: true
1992
+ });
1993
+ } catch (hookError) {
1994
+ return respondThrown(hookError);
1995
+ }
1242
1996
  }
1243
1997
  let status = 200;
1244
1998
  let metadata;
@@ -1250,8 +2004,10 @@ async function handleServerFunctionRequest(request, options = {}) {
1250
2004
  if (response && response.headers) {
1251
2005
  mergeResponseHeaders(headers, response.headers);
1252
2006
  }
1253
- if (response && response.status && (!instance || response.status < 300 || response.status >= 400)) {
2007
+ if (response && response.status && (!scripted || !validRedirectStatuses.has(response.status))) {
1254
2008
  status = response.status;
2009
+ } else if (response && response.status) {
2010
+ maskRedirect(headers, response, request.url);
1255
2011
  }
1256
2012
  metadata = response;
1257
2013
  x = value;
@@ -1259,8 +2015,10 @@ async function handleServerFunctionRequest(request, options = {}) {
1259
2015
  if (x.headers) {
1260
2016
  mergeResponseHeaders(headers, x.headers);
1261
2017
  }
1262
- if (x.status && (!instance || x.status < 300 || x.status >= 400)) {
2018
+ if (x.status && (!scripted || !validRedirectStatuses.has(x.status))) {
1263
2019
  status = x.status;
2020
+ } else if (x.status) {
2021
+ maskRedirect(headers, x, request.url);
1264
2022
  }
1265
2023
  metadata = x;
1266
2024
  if (x.body == null) {
@@ -1268,7 +2026,7 @@ async function handleServerFunctionRequest(request, options = {}) {
1268
2026
  }
1269
2027
  }
1270
2028
  if (collectsFlight) {
1271
- x = await foldFlightData(flightHook, event, headers, {
2029
+ x = await foldFlightData(flightHooks, event, headers, {
1272
2030
  id: functionId,
1273
2031
  value: x,
1274
2032
  response: metadata,
@@ -1276,38 +2034,38 @@ async function handleServerFunctionRequest(request, options = {}) {
1276
2034
  thrown: true
1277
2035
  }, flightContext);
1278
2036
  if (x instanceof Response && x.headers.has("X-Content-Raw")) {
2037
+ x = ownResponse(x);
1279
2038
  x.headers.set(ERROR_HEADER, "true");
1280
2039
  return x;
1281
2040
  }
1282
2041
  }
1283
2042
  headers.set(ERROR_HEADER, "true");
1284
- if (!instance) {
2043
+ if (!scripted) {
1285
2044
  if (handleNoJS) return handleNoJS(x ?? metadata, request, parsed, true);
1286
2045
  if (x instanceof Response) return x;
1287
2046
  }
1288
- return encodeResult(x, headers, status, codec, request.signal);
1289
- }
1290
- const safe = sanitizeServerError(x);
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
- });
2047
+ if (scripted && status === 304) warnScripted304(functionId);
2048
+ return encodeResult(x, headers, status, codec, request.signal, scope);
1297
2049
  }
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);
2050
+ return respondThrown(x);
1301
2051
  }
1302
2052
  };
1303
- const response = commitEventResponse(await dispatch(), event);
2053
+ const response = commitEventResponse(enforceComposedHeaderInvariants(ownResponse(await dispatch())), event);
1304
2054
  return finalizeTransportResponse(protectsRequest ? withCSRFVary(response) : response, method);
1305
2055
  }
2056
+ function ownResponse(response) {
2057
+ try {
2058
+ return new Response(response.body, response);
2059
+ } catch {
2060
+ return response;
2061
+ }
2062
+ }
1306
2063
  function finalizeTransportResponse(response, method) {
1307
2064
  const stripBody = method === "HEAD" && response.body !== null;
1308
- if (stripBody || !response.headers.has("Cache-Control")) {
2065
+ const defaultsCache = !response.headers.has("Cache-Control") && response.status !== 304;
2066
+ if (stripBody || defaultsCache) {
1309
2067
  try {
1310
- if (!response.headers.has("Cache-Control")) {
2068
+ if (defaultsCache) {
1311
2069
  response.headers.set("Cache-Control", "no-store");
1312
2070
  }
1313
2071
  if (!stripBody) return response;
@@ -1319,7 +2077,7 @@ function finalizeTransportResponse(response, method) {
1319
2077
  });
1320
2078
  } catch {
1321
2079
  const headers = new Headers(response.headers);
1322
- if (!headers.has("Cache-Control")) headers.set("Cache-Control", "no-store");
2080
+ if (defaultsCache && !headers.has("Cache-Control")) headers.set("Cache-Control", "no-store");
1323
2081
  if (stripBody) response.body.cancel().catch(() => {});
1324
2082
  return new Response(stripBody ? null : response.body, {
1325
2083
  status: response.status,
@@ -1336,14 +2094,17 @@ exports.FLASH_COOKIE = FLASH_COOKIE;
1336
2094
  exports.GENERIC_SERVER_ERROR_MESSAGE = GENERIC_SERVER_ERROR_MESSAGE;
1337
2095
  exports.GET = GET;
1338
2096
  exports.INSTANCE_HEADER = INSTANCE_HEADER;
2097
+ exports.REDIRECT_HEADER = REDIRECT_HEADER;
1339
2098
  exports.SERVER_FUNCTION_INVOKE = SERVER_FUNCTION_INVOKE;
1340
2099
  exports.SINGLE_FLIGHT_HEADER = SINGLE_FLIGHT_HEADER;
2100
+ exports.UNKNOWN_HEADER = UNKNOWN_HEADER;
1341
2101
  exports.clearFlashCookie = clearFlashCookie;
1342
2102
  exports.configureServerFunctionsServer = configureServerFunctionsServer;
1343
2103
  exports.createNoJSHandler = createNoJSHandler;
1344
2104
  exports.createServerReference = createServerReference;
1345
2105
  exports.decodeErrorHeaderValue = decodeErrorHeaderValue;
1346
2106
  exports.decodeFlashCookie = decodeFlashCookie;
2107
+ exports.decodeRedirectHeaderValue = decodeRedirectHeaderValue;
1347
2108
  exports.decodeResponse = decodeResponse;
1348
2109
  exports.decodeResponsePayload = decodeResponsePayload;
1349
2110
  exports.encodeErrorHeaderValue = encodeErrorHeaderValue;
@@ -1353,6 +2114,7 @@ exports.getEventServerFunctionInvocation = getEventServerFunctionInvocation;
1353
2114
  exports.getServerFunction = getServerFunction;
1354
2115
  exports.getServerFunctionInvocation = getServerFunctionInvocation;
1355
2116
  exports.getServerFunctionMetadata = getServerFunctionMetadata;
2117
+ exports.guardFailures = guardFailures;
1356
2118
  exports.handleServerFunctionRequest = handleServerFunctionRequest;
1357
2119
  exports.hasFlashCookie = hasFlashCookie;
1358
2120
  exports.invoke = invoke;
@@ -1360,6 +2122,7 @@ exports.isServerFunction = isServerFunction;
1360
2122
  exports.live = live;
1361
2123
  exports.observeServerFunctionCalls = observeServerFunctionCalls;
1362
2124
  exports.parseServerFunctionUrl = parseServerFunctionUrl;
2125
+ exports.registerFlightDataSource = registerFlightDataSource;
1363
2126
  exports.registerServerFunction = registerServerFunction;
1364
2127
  exports.registerServerReference = registerServerReference;
1365
2128
  exports.sanitizeServerError = sanitizeServerError;