@solidjs/web 2.0.0-beta.31 → 2.0.0-beta.32

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 (64) hide show
  1. package/README.md +1 -6
  2. package/dist/dev.cjs +234 -45
  3. package/dist/dev.js +221 -42
  4. package/dist/server.cjs +456 -123
  5. package/dist/server.js +445 -120
  6. package/dist/web.cjs +234 -45
  7. package/dist/web.js +221 -42
  8. package/frames/dist/client.cjs +217 -112
  9. package/frames/dist/client.dev.cjs +217 -112
  10. package/frames/dist/client.dev.js +218 -113
  11. package/frames/dist/client.js +218 -113
  12. package/frames/dist/server.cjs +488 -177
  13. package/frames/dist/server.js +489 -179
  14. package/package.json +55 -4
  15. package/serialization/dist/serialization.cjs +8 -0
  16. package/serialization/dist/serialization.js +1 -0
  17. package/serialization/types/index.d.ts +173 -6
  18. package/serialization/types-cjs/index.d.cts +173 -6
  19. package/server-functions/dist/client.cjs +46 -9
  20. package/server-functions/dist/client.js +47 -11
  21. package/server-functions/dist/rich-args.cjs +11 -0
  22. package/server-functions/dist/rich-args.js +9 -0
  23. package/server-functions/dist/server.cjs +275 -126
  24. package/server-functions/dist/server.dev.cjs +1053 -0
  25. package/server-functions/dist/server.dev.js +1021 -0
  26. package/server-functions/dist/server.js +273 -127
  27. package/server-functions/package.json +10 -0
  28. package/server-functions/rich-args/package.json +20 -0
  29. package/storage/types/index.d.ts +1 -1
  30. package/storage/types-cjs/index.d.cts +1 -1
  31. package/types/client.d.ts +127 -6
  32. package/types/core.d.ts +3 -1
  33. package/types/frames/client.d.ts +15 -1
  34. package/types/frames/frame-client.d.ts +37 -7
  35. package/types/frames/frame-sink.d.ts +26 -3
  36. package/types/frames/frame-transport.d.ts +39 -7
  37. package/types/frames/serializer.d.ts +173 -6
  38. package/types/frames/server.d.ts +22 -0
  39. package/types/index.d.ts +2 -3
  40. package/types/response.d.ts +45 -0
  41. package/types/serializer.d.ts +173 -6
  42. package/types/server-functions/client.d.ts +1 -0
  43. package/types/server-functions/rich-args.d.ts +10 -0
  44. package/types/server-functions/server.d.ts +98 -0
  45. package/types/server-functions/shared.d.ts +22 -0
  46. package/types/server-mock.d.ts +171 -59
  47. package/types/server.d.ts +188 -36
  48. package/types-cjs/client.d.cts +127 -6
  49. package/types-cjs/core.d.cts +3 -1
  50. package/types-cjs/frames/client.d.cts +15 -1
  51. package/types-cjs/frames/frame-client.d.cts +37 -7
  52. package/types-cjs/frames/frame-sink.d.cts +26 -3
  53. package/types-cjs/frames/frame-transport.d.cts +39 -7
  54. package/types-cjs/frames/serializer.d.cts +173 -6
  55. package/types-cjs/frames/server.d.cts +22 -0
  56. package/types-cjs/index.d.cts +2 -3
  57. package/types-cjs/response.d.cts +45 -0
  58. package/types-cjs/serializer.d.cts +173 -6
  59. package/types-cjs/server-functions/client.d.cts +1 -0
  60. package/types-cjs/server-functions/rich-args.d.cts +10 -0
  61. package/types-cjs/server-functions/server.d.cts +98 -0
  62. package/types-cjs/server-functions/shared.d.cts +22 -0
  63. package/types-cjs/server-mock.d.cts +171 -59
  64. package/types-cjs/server.d.cts +188 -36
package/dist/server.js CHANGED
@@ -100,6 +100,141 @@ function getLocalHeaderScript(id) {
100
100
  }
101
101
  Feature.RegExp;
102
102
 
103
+ const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
104
+ class ResponseEnvelope {
105
+ constructor(response, value) {
106
+ this.response = response;
107
+ this.value = value;
108
+ }
109
+ }
110
+ ResponseEnvelope.prototype[ENVELOPE] = true;
111
+ function isResponseEnvelope(value) {
112
+ return !!(value && typeof value === "object" && value[ENVELOPE]);
113
+ }
114
+ const HREF = Symbol.for("solid.Href");
115
+ function isHref(value) {
116
+ return !!(value && (typeof value === "object" || typeof value === "function") && value[HREF]);
117
+ }
118
+ const SAFE_ERROR = Symbol.for("solid.SafeError");
119
+ function markSafeError(error) {
120
+ if (error && (typeof error === "object" || typeof error === "function")) {
121
+ Object.defineProperty(error, SAFE_ERROR, {
122
+ value: true,
123
+ enumerable: false,
124
+ configurable: true
125
+ });
126
+ }
127
+ return error;
128
+ }
129
+ function isSafeError(value) {
130
+ return !!(value && (typeof value === "object" || typeof value === "function") && value[SAFE_ERROR]);
131
+ }
132
+ const REVALIDATE_HEADER = "X-Revalidate";
133
+ function initWithRevalidate(init) {
134
+ const {
135
+ revalidate,
136
+ ...responseInit
137
+ } = init;
138
+ let headers;
139
+ if (responseInit.headers && responseInit.headers.getSetCookie) {
140
+ headers = new Headers();
141
+ responseInit.headers.forEach((value, key) => {
142
+ if (key !== "set-cookie") headers.append(key, value);
143
+ });
144
+ for (const cookie of responseInit.headers.getSetCookie()) {
145
+ headers.append("Set-Cookie", cookie);
146
+ }
147
+ } else {
148
+ headers = new Headers(responseInit.headers);
149
+ }
150
+ revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
151
+ return {
152
+ responseInit,
153
+ headers
154
+ };
155
+ }
156
+ function redirect(url, init = 302) {
157
+ if (typeof url !== "string" && !isHref(url)) {
158
+ throw new TypeError("redirect() expects a string URL or an Href-branded value (Symbol.for('solid.Href')).");
159
+ }
160
+ const {
161
+ responseInit,
162
+ headers
163
+ } = initWithRevalidate(typeof init === "number" ? {
164
+ status: init
165
+ } : init);
166
+ if (responseInit.status === undefined) {
167
+ responseInit.status = 302;
168
+ }
169
+ headers.set("Location", String(url));
170
+ return new Response(null, {
171
+ ...responseInit,
172
+ headers
173
+ });
174
+ }
175
+ function reload(init = {}) {
176
+ const {
177
+ responseInit,
178
+ headers
179
+ } = initWithRevalidate(init);
180
+ return new Response(null, {
181
+ ...responseInit,
182
+ headers
183
+ });
184
+ }
185
+ function respond(value, init = {}) {
186
+ const {
187
+ responseInit,
188
+ headers
189
+ } = initWithRevalidate(init);
190
+ headers.set("Content-Type", "application/json");
191
+ return new ResponseEnvelope(new Response(JSON.stringify(value), {
192
+ ...responseInit,
193
+ headers
194
+ }), value);
195
+ }
196
+
197
+ const ERROR_HEADER = "X-Server-Function-Error";
198
+ const BODY_FORMAT_HEADER = "X-Server-Function-Format";
199
+ const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
200
+
201
+ function parseCookieHeader(header) {
202
+ const cookies = {};
203
+ if (!header) return cookies;
204
+ for (const part of header.split(";")) {
205
+ const eq = part.indexOf("=");
206
+ if (eq < 0) continue;
207
+ const name = decodeSafe(part.slice(0, eq).trim());
208
+ let value = part.slice(eq + 1).trim();
209
+ if (value.length > 1 && value[0] === '"' && value[value.length - 1] === '"') {
210
+ value = value.slice(1, -1);
211
+ }
212
+ cookies[name] = decodeSafe(value);
213
+ }
214
+ return cookies;
215
+ }
216
+ function decodeSafe(text) {
217
+ try {
218
+ return decodeURIComponent(text);
219
+ } catch {
220
+ return text;
221
+ }
222
+ }
223
+ function serializeCookie(name, value, options = {}) {
224
+ let cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}`;
225
+ cookie += `; Path=${options.path === undefined ? "/" : options.path}`;
226
+ if (options.domain) cookie += `; Domain=${options.domain}`;
227
+ if (options.maxAge !== undefined) cookie += `; Max-Age=${Math.trunc(options.maxAge)}`;
228
+ if (options.expires) cookie += `; Expires=${options.expires.toUTCString()}`;
229
+ if (options.httpOnly) cookie += "; HttpOnly";
230
+ if (options.secure) cookie += "; Secure";
231
+ if (options.sameSite) {
232
+ const sameSite = options.sameSite.toLowerCase();
233
+ cookie += `; SameSite=${sameSite === "none" ? "None" : sameSite === "strict" ? "Strict" : "Lax"}`;
234
+ }
235
+ return cookie;
236
+ }
237
+
103
238
  const HEAD_ELIGIBLE_TAGS = new Set(["title", "meta", "link", "style", "script", "base"]);
104
239
  const HEAD_ATTR_NAME = /^[a-zA-Z_][a-zA-Z0-9_:.-]*$/;
105
240
  const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "stylesheet"]);
@@ -340,7 +475,8 @@ function createHeadRegistry() {
340
475
  resources: new Set(),
341
476
  eagerHtml: "",
342
477
  flushed: null,
343
- shellFlushed: false
478
+ shellFlushed: false,
479
+ parkedResources: []
344
480
  };
345
481
  }
346
482
  function registerHeadTags(registry, context, tracking, emitResource, nonce, tags) {
@@ -354,6 +490,7 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
354
490
  return;
355
491
  }
356
492
  if (!Array.isArray(tags)) tags = [tags];
493
+ const probe = sharedConfig.context && sharedConfig.context._loadingPhase;
357
494
  let replaceable = null;
358
495
  for (let i = 0; i < tags.length; i++) {
359
496
  const desc = tags[i];
@@ -362,6 +499,16 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
362
499
  continue;
363
500
  }
364
501
  const cls = classifyHeadTag(desc);
502
+ if (probe && !cls.resource) {
503
+ try {
504
+ evalHeadProps(desc.props || {}, cls.rel !== undefined ? {
505
+ rel: cls.rel
506
+ } : undefined);
507
+ evalHeadValue(desc.key);
508
+ } catch (err) {
509
+ if (ssrHandleError(err)) throw err;
510
+ }
511
+ }
365
512
  if (cls.resource) {
366
513
  emitHeadResource(registry, context, tracking, emitResource, nonce, desc, cls.rel);
367
514
  } else {
@@ -378,6 +525,52 @@ function registerHeadTags(registry, context, tracking, emitResource, nonce, tags
378
525
  tags: replaceable
379
526
  });
380
527
  }
528
+ function headShellReady(registry, block) {
529
+ let ready = true;
530
+ const pends = err => {
531
+ const source = ssrHandleError(err, true);
532
+ if (!source) return false;
533
+ block(source);
534
+ ready = false;
535
+ return true;
536
+ };
537
+ const parked = registry.parkedResources;
538
+ for (let i = parked.length - 1; i >= 0; i--) {
539
+ const {
540
+ desc,
541
+ rel,
542
+ emit
543
+ } = parked[i];
544
+ try {
545
+ evalHeadProps(desc.props || {}, rel !== undefined ? {
546
+ rel
547
+ } : undefined);
548
+ } catch (err) {
549
+ if (pends(err)) continue;
550
+ console.warn(`useHead: error evaluating resource tag props`, err);
551
+ parked.splice(i, 1);
552
+ continue;
553
+ }
554
+ parked.splice(i, 1);
555
+ emit();
556
+ }
557
+ for (let i = 0; i < registry.pending.length; i++) {
558
+ const reg = registry.pending[i];
559
+ if (reg.boundary !== "" || reg.list) continue;
560
+ for (let j = 0; j < reg.tags.length; j++) {
561
+ const desc = reg.tags[j];
562
+ try {
563
+ evalHeadProps(desc.props || {}, desc.rel !== undefined ? {
564
+ rel: desc.rel
565
+ } : undefined);
566
+ evalHeadValue(desc.key);
567
+ } catch (err) {
568
+ pends(err);
569
+ }
570
+ }
571
+ }
572
+ return ready;
573
+ }
381
574
  function emitHeadResource(registry, context, tracking, emitResource, nonce, desc, rel) {
382
575
  let props;
383
576
  try {
@@ -385,6 +578,16 @@ function emitHeadResource(registry, context, tracking, emitResource, nonce, desc
385
578
  rel
386
579
  } : undefined);
387
580
  } catch (err) {
581
+ const loadingPhase = sharedConfig.context && sharedConfig.context._loadingPhase;
582
+ if (loadingPhase && ssrHandleError(err)) throw err;
583
+ if (!loadingPhase && !context._currentBoundaryId && !registry.shellFlushed && typeof context.block === "function" && ssrHandleError(err, true)) {
584
+ registry.parkedResources.push({
585
+ desc,
586
+ rel,
587
+ emit: () => emitHeadResource(registry, context, tracking, emitResource, nonce, desc, rel)
588
+ });
589
+ return;
590
+ }
388
591
  console.warn(`useHead: error evaluating resource tag props`, err);
389
592
  return;
390
593
  }
@@ -651,7 +854,6 @@ function renderToString(code, options = {}) {
651
854
  const tracking = createAssetTracking();
652
855
  const headRegistry = createHeadRegistry();
653
856
  sharedConfig.context = {
654
- assets: [],
655
857
  nonce,
656
858
  escape: escape,
657
859
  resolve: resolveSSRNode,
@@ -693,9 +895,8 @@ function renderToString(code, options = {}) {
693
895
  serializeFragmentAssets("", tracking.boundaryModules, sharedConfig.context);
694
896
  sharedConfig.context.noHydrate = true;
695
897
  serializer.close();
696
- const assetsHtml = resolveAssetsHtml(sharedConfig.context.assets);
697
898
  const head = renderShellHead(headRegistry, nonce, null);
698
- return assembleDocument(html, assetsHtml, tracking.emittedAssets, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
899
+ return assembleDocument(html, tracking.emittedAssets, tracking.inlineStyles, scripts.length ? scripts : "", nonce, head, onHead);
699
900
  }
700
901
  function renderToStream(code, options = {}) {
701
902
  let {
@@ -806,7 +1007,7 @@ function renderToStream(code, options = {}) {
806
1007
  }
807
1008
  },
808
1009
  shell(shellHtml, meta) {
809
- buffer.write(assembleDocument(shellHtml, meta.assets, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
1010
+ buffer.write(assembleDocument(shellHtml, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce, meta.head, onHead));
810
1011
  },
811
1012
  ...options.sink
812
1013
  };
@@ -886,7 +1087,6 @@ function renderToStream(code, options = {}) {
886
1087
  };
887
1088
  sharedConfig.context = context = {
888
1089
  async: true,
889
- assets: [],
890
1090
  nonce,
891
1091
  registerHeadTags(tags) {
892
1092
  registerHeadTags(headRegistry, context, tracking,
@@ -1088,7 +1288,7 @@ function renderToStream(code, options = {}) {
1088
1288
  if (shellCompleted) return;
1089
1289
  sharedConfig.context = context;
1090
1290
  if (!resolveRootHoles()) return;
1091
- const assetsHtml = resolveAssetsHtml(context.assets);
1291
+ if (!headShellReady(headRegistry, p => blockingPromises.add(p))) return;
1092
1292
  headStyles = new Set();
1093
1293
  for (const url of tracking.emittedAssets) {
1094
1294
  if (isCssUrl(url)) headStyles.add(url);
@@ -1096,7 +1296,6 @@ function renderToStream(code, options = {}) {
1096
1296
  serializeRootAssets();
1097
1297
  const head = renderShellHead(headRegistry, nonce, k => registry.has(k));
1098
1298
  sink.shell(html, {
1099
- assets: assetsHtml,
1100
1299
  preloads: tracking.emittedAssets,
1101
1300
  inlineStyles: tracking.inlineStyles,
1102
1301
  tasks,
@@ -1186,27 +1385,30 @@ function renderToStream(code, options = {}) {
1186
1385
  return p;
1187
1386
  };
1188
1387
  return {
1189
- then(fn) {
1190
- function complete() {
1191
- dispose();
1192
- fn(tmp);
1193
- }
1194
- if (onCompleteAll) {
1195
- let ogComplete = onCompleteAll;
1196
- onCompleteAll = options => {
1197
- ogComplete(options);
1198
- complete();
1199
- };
1200
- } else onCompleteAll = complete;
1201
- function flush() {
1202
- allSettled(blockingPromises).then(() => {
1203
- scheduleFlush(() => {
1204
- if (!resolveRootHoles()) return flush();
1205
- queue(flushEnd);
1388
+ then(onFulfilled, onRejected) {
1389
+ const p = new Promise(resolve => {
1390
+ function complete() {
1391
+ dispose();
1392
+ resolve(tmp);
1393
+ }
1394
+ if (onCompleteAll) {
1395
+ let ogComplete = onCompleteAll;
1396
+ onCompleteAll = options => {
1397
+ ogComplete(options);
1398
+ complete();
1399
+ };
1400
+ } else onCompleteAll = complete;
1401
+ function flush() {
1402
+ allSettled(blockingPromises).then(() => {
1403
+ scheduleFlush(() => {
1404
+ if (!resolveRootHoles() || !headShellReady(headRegistry, p => blockingPromises.add(p))) return flush();
1405
+ queue(flushEnd);
1406
+ });
1206
1407
  });
1207
- });
1208
- }
1209
- flush();
1408
+ }
1409
+ flush();
1410
+ });
1411
+ return p.then(onFulfilled, onRejected);
1210
1412
  },
1211
1413
  pipe(w) {
1212
1414
  claimConsumer("pipe");
@@ -1577,18 +1779,6 @@ function getHydrationKey() {
1577
1779
  function applyRef(r, element) {
1578
1780
  Array.isArray(r) ? r.flat(Infinity).forEach(f => f && f(element)) : r(element);
1579
1781
  }
1580
- function useAssets(fn) {
1581
- sharedConfig.context.assets.push(() => resolveSSRSync(escape(fn())));
1582
- }
1583
- function getAssets() {
1584
- const assets = sharedConfig.context.assets;
1585
- let out = "";
1586
- for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
1587
- return out;
1588
- }
1589
- function Assets(props) {
1590
- useAssets(() => props.children);
1591
- }
1592
1782
  function generateHydrationScript({
1593
1783
  eventNames = ["click", "input"],
1594
1784
  nonce
@@ -1605,17 +1795,11 @@ function allSettled(promises) {
1605
1795
  return;
1606
1796
  });
1607
1797
  }
1608
- function resolveAssetsHtml(assets) {
1609
- if (!assets || !assets.length) return "";
1610
- let out = "";
1611
- for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
1612
- return out;
1613
- }
1614
- function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
1798
+ function assembleDocument(html, emittedAssets, inlineStyles, scripts, nonce, headTags, onHead) {
1615
1799
  const scriptTag = scripts ? `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>` : "";
1616
1800
  const headTagsHtml = headTags ? headTags.html : "";
1617
1801
  const headPrelude = headTags ? headTags.prelude : "";
1618
- if (!onHead && !assetsHtml && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
1802
+ if (!onHead && !headTagsHtml && !headPrelude && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
1619
1803
  if (!scriptTag) return html;
1620
1804
  const xs = html.indexOf("<!--xs-->");
1621
1805
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
@@ -1630,13 +1814,13 @@ function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts
1630
1814
  const headIdx = html.indexOf("</head>");
1631
1815
  if (headIdx === -1) {
1632
1816
  if (onHead) {
1633
- onHead(headPrelude + headTagsHtml + (assetsHtml || "") + renderHeadAssets(emittedAssets, inlineStyles, nonce));
1817
+ onHead(headPrelude + headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce));
1634
1818
  }
1635
1819
  if (!scriptTag) return html;
1636
1820
  const xs = html.indexOf("<!--xs-->");
1637
1821
  return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
1638
1822
  }
1639
- const head = headTagsHtml + (assetsHtml || "") + renderHeadAssets(emittedAssets, inlineStyles, nonce);
1823
+ const head = headTagsHtml + renderHeadAssets(emittedAssets, inlineStyles, nonce);
1640
1824
  if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
1641
1825
  const xsIdx = html.indexOf("<!--xs-->");
1642
1826
  if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
@@ -1836,90 +2020,226 @@ const RequestContext = Symbol.for("solid.RequestContext");
1836
2020
  function getRequestEvent() {
1837
2021
  return globalThis[RequestContext] ? globalThis[RequestContext].getStore() || sharedConfig.context && sharedConfig.context.event || console.warn("RequestEvent is missing. This is most likely due to accessing `getRequestEvent` non-managed async scope in a partially polyfilled environment. Try moving it above all `await` calls.") : undefined;
1838
2022
  }
1839
- function renderToStringAsync(code, options = {}) {
1840
- return new Promise(resolve => renderToStream(code, options).then(resolve));
1841
- }
1842
- function registerElementClaim() {
1843
- return noopCleanup;
1844
- }
1845
- function noopCleanup() {}
1846
- function claimElement(node) {
1847
- return node;
2023
+ function createResponseStub() {
2024
+ return {
2025
+ status: undefined,
2026
+ statusText: undefined,
2027
+ headers: new Headers(),
2028
+ committed: false
2029
+ };
1848
2030
  }
1849
- function claimElementTree(root) {
1850
- return root;
2031
+ function createRequestEvent(request, init) {
2032
+ return {
2033
+ request,
2034
+ locals: {},
2035
+ response: createResponseStub(),
2036
+ ...init
2037
+ };
1851
2038
  }
1852
- function notSup() {
1853
- throw new Error("Client-only API called on the server side. Run client-only code in onMount, or conditionally run client-only component with <Show>.");
2039
+ function reportLostHeaderWrite(method, name) {
2040
+ const message = `Response header write dropped: headers.${method}(${JSON.stringify(String(name))}) ` + "ran after the response head was sent. Write headers before the shell flushes " + "(or before the handler returns).";
2041
+ throw new Error(message);
1854
2042
  }
1855
-
1856
- const ENVELOPE = Symbol.for("solid.ResponseEnvelope");
1857
- class ResponseEnvelope {
1858
- constructor(response, value) {
1859
- this.response = response;
1860
- this.value = value;
2043
+ function commitResponseStub(stub, {
2044
+ allowLateLocation = false
2045
+ } = {}) {
2046
+ if (!stub || stub.committed) return stub;
2047
+ stub.committed = true;
2048
+ const headers = stub.headers;
2049
+ if (!headers || typeof headers.set !== "function") return stub;
2050
+ for (const method of ["set", "append", "delete"]) {
2051
+ const original = headers[method].bind(headers);
2052
+ headers[method] = function (name, ...rest) {
2053
+ if (allowLateLocation && method === "set" && String(name).toLowerCase() === "location") {
2054
+ return original(name, ...rest);
2055
+ }
2056
+ reportLostHeaderWrite(method, name);
2057
+ };
1861
2058
  }
2059
+ return stub;
1862
2060
  }
1863
- ResponseEnvelope.prototype[ENVELOPE] = true;
1864
- function isResponseEnvelope(value) {
1865
- return !!(value && typeof value === "object" && value[ENVELOPE]);
2061
+ const validRedirectStatuses = /*#__PURE__*/new Set([301, 302, 303, 307, 308]);
2062
+ function getExpectedRedirectStatus(response) {
2063
+ if (response.status && validRedirectStatuses.has(response.status)) return response.status;
2064
+ return 302;
1866
2065
  }
1867
- const HREF = Symbol.for("solid.Href");
1868
- function isHref(value) {
1869
- return !!(value && (typeof value === "object" || typeof value === "function") && value[HREF]);
2066
+ function mergeStubHeaders(target, stub) {
2067
+ if (!stub) return target;
2068
+ stub.headers.forEach((value, key) => {
2069
+ if (key !== "set-cookie") target.set(key, value);
2070
+ });
2071
+ const setCookies = stub.headers.getSetCookie ? stub.headers.getSetCookie() : [];
2072
+ for (const cookie of setCookies) target.append("set-cookie", cookie);
2073
+ return target;
2074
+ }
2075
+ function copyInitHeaders(init) {
2076
+ if (!init || !init.getSetCookie) return new Headers(init);
2077
+ const headers = new Headers();
2078
+ init.forEach((value, key) => {
2079
+ if (key !== "set-cookie") headers.append(key, value);
2080
+ });
2081
+ for (const cookie of init.getSetCookie()) headers.append("Set-Cookie", cookie);
2082
+ return headers;
2083
+ }
2084
+ const STUB_GAP_FILL_EXCLUDED = /*#__PURE__*/new Set([ERROR_HEADER, BODY_FORMAT_HEADER, SINGLE_FLIGHT_HEADER, REVALIDATE_HEADER, "Location"].map(header => header.toLowerCase()));
2085
+ function fillsStubGap(key, headers, response) {
2086
+ if (key === "set-cookie" || STUB_GAP_FILL_EXCLUDED.has(key)) return false;
2087
+ if (response.body === null && (key === "content-type" || key === "content-length")) return false;
2088
+ return !headers.has(key);
2089
+ }
2090
+ function commitEventResponse(response, event = getRequestEvent()) {
2091
+ const stub = event && event.response;
2092
+ if (!stub || !stub.headers || stub.committed) return response;
2093
+ const cookies = stub.headers.getSetCookie ? stub.headers.getSetCookie() : [];
2094
+ commitResponseStub(stub);
2095
+ let hasGaps = false;
2096
+ stub.headers.forEach((value, key) => {
2097
+ if (fillsStubGap(key, response.headers, response)) hasGaps = true;
2098
+ });
2099
+ if (!cookies.length && !hasGaps) return response;
2100
+ try {
2101
+ for (const cookie of cookies) response.headers.append("Set-Cookie", cookie);
2102
+ stub.headers.forEach((value, key) => {
2103
+ if (fillsStubGap(key, response.headers, response)) response.headers.set(key, value);
2104
+ });
2105
+ return response;
2106
+ } catch {
2107
+ const headers = copyInitHeaders(response.headers);
2108
+ for (const cookie of cookies) headers.append("Set-Cookie", cookie);
2109
+ stub.headers.forEach((value, key) => {
2110
+ if (fillsStubGap(key, headers, response)) headers.set(key, value);
2111
+ });
2112
+ return new Response(response.body, {
2113
+ status: response.status,
2114
+ statusText: response.statusText,
2115
+ headers
2116
+ });
2117
+ }
1870
2118
  }
1871
- const REVALIDATE_HEADER = "X-Revalidate";
1872
- function initWithRevalidate(init) {
1873
- const {
1874
- revalidate,
1875
- ...responseInit
1876
- } = init;
1877
- const headers = new Headers(responseInit.headers);
1878
- revalidate !== undefined && headers.set(REVALIDATE_HEADER, revalidate.toString());
2119
+ function deriveHead(stub, responseInit = {}) {
2120
+ const headers = mergeStubHeaders(copyInitHeaders(responseInit.headers), stub);
2121
+ const status = stub && stub.status || responseInit.status || 200;
2122
+ const statusText = stub && stub.statusText || responseInit.statusText || undefined;
1879
2123
  return {
1880
- responseInit,
2124
+ status,
2125
+ statusText,
1881
2126
  headers
1882
2127
  };
1883
2128
  }
1884
- function redirect(url, init = 302) {
1885
- if (typeof url !== "string" && !isHref(url)) {
1886
- throw new TypeError("redirect() expects a string URL or an Href-branded value (Symbol.for('solid.Href')).");
1887
- }
2129
+ function escapeAttribute(value) {
2130
+ return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;");
2131
+ }
2132
+ function createSSRResponse(result, event, options = {}) {
2133
+ const stub = event && event.response;
1888
2134
  const {
1889
2135
  responseInit,
1890
- headers
1891
- } = initWithRevalidate(typeof init === "number" ? {
1892
- status: init
1893
- } : init);
1894
- if (responseInit.status === undefined) {
1895
- responseInit.status = 302;
2136
+ nonce,
2137
+ transformChunk
2138
+ } = options;
2139
+ if (typeof result === "string") {
2140
+ if (stub) commitResponseStub(stub);
2141
+ const head = deriveHead(stub, responseInit);
2142
+ if (stub && stub.headers.get("Location")) {
2143
+ return new Response(null, {
2144
+ status: getExpectedRedirectStatus(stub),
2145
+ headers: head.headers
2146
+ });
2147
+ }
2148
+ if (!head.headers.has("content-type")) {
2149
+ head.headers.set("content-type", "text/html; charset=utf-8");
2150
+ }
2151
+ return new Response(transformChunk ? transformChunk(result) : result, {
2152
+ status: head.status,
2153
+ statusText: head.statusText,
2154
+ headers: head.headers
2155
+ });
1896
2156
  }
1897
- headers.set("Location", String(url));
1898
- return new Response(null, {
1899
- ...responseInit,
1900
- headers
2157
+ const encoder = new TextEncoder();
2158
+ return new Promise(resolve => {
2159
+ let controller;
2160
+ let closed = false;
2161
+ let flushed = false;
2162
+ const enqueue = value => {
2163
+ if (closed || !controller) return;
2164
+ try {
2165
+ controller.enqueue(encoder.encode(value));
2166
+ } catch {
2167
+ closed = true;
2168
+ }
2169
+ };
2170
+ result.pipe({
2171
+ write(chunk) {
2172
+ if (!flushed) {
2173
+ flushed = true;
2174
+ if (stub) commitResponseStub(stub, {
2175
+ allowLateLocation: true
2176
+ });
2177
+ const head = deriveHead(stub, responseInit);
2178
+ if (stub && stub.headers.get("Location")) {
2179
+ closed = true;
2180
+ resolve(new Response(null, {
2181
+ status: getExpectedRedirectStatus(stub),
2182
+ headers: head.headers
2183
+ }));
2184
+ return;
2185
+ }
2186
+ if (!head.headers.has("content-type")) {
2187
+ head.headers.set("content-type", "text/html; charset=utf-8");
2188
+ }
2189
+ resolve(new Response(new ReadableStream({
2190
+ start(c) {
2191
+ controller = c;
2192
+ },
2193
+ cancel() {
2194
+ closed = true;
2195
+ }
2196
+ }), {
2197
+ status: head.status,
2198
+ statusText: head.statusText,
2199
+ headers: head.headers
2200
+ }));
2201
+ }
2202
+ enqueue(transformChunk ? transformChunk(chunk) : chunk);
2203
+ },
2204
+ end() {
2205
+ if (closed || !controller) return;
2206
+ const location = stub && stub.headers.get("Location");
2207
+ if (location) {
2208
+ const attr = nonce ? ` nonce="${escapeAttribute(nonce)}"` : "";
2209
+ enqueue(`<script${attr}>window.location=${JSON.stringify(location).replace(/</g, "\\u003c")}</script>`);
2210
+ }
2211
+ closed = true;
2212
+ try {
2213
+ controller.close();
2214
+ } catch {}
2215
+ }
2216
+ });
1901
2217
  });
1902
2218
  }
1903
- function reload(init = {}) {
1904
- const {
1905
- responseInit,
1906
- headers
1907
- } = initWithRevalidate(init);
1908
- return new Response(null, {
1909
- ...responseInit,
1910
- headers
1911
- });
2219
+ function composeMiddleware(middlewares) {
2220
+ return function run(request, next) {
2221
+ let index = -1;
2222
+ function dispatch(i, req) {
2223
+ if (i <= index) return Promise.reject(new Error("next() called multiple times"));
2224
+ index = i;
2225
+ if (i === middlewares.length) return Promise.resolve(next(req));
2226
+ return Promise.resolve(middlewares[i](req, override => dispatch(i + 1, override || req)));
2227
+ }
2228
+ return dispatch(0, request);
2229
+ };
1912
2230
  }
1913
- function respond(value, init = {}) {
1914
- const {
1915
- responseInit,
1916
- headers
1917
- } = initWithRevalidate(init);
1918
- headers.set("Content-Type", "application/json");
1919
- return new ResponseEnvelope(new Response(JSON.stringify(value), {
1920
- ...responseInit,
1921
- headers
1922
- }), value);
2231
+ function registerElementClaim() {
2232
+ return noopCleanup;
2233
+ }
2234
+ function noopCleanup() {}
2235
+ function claimElement(node) {
2236
+ return node;
2237
+ }
2238
+ function claimElementTree(root) {
2239
+ return root;
2240
+ }
2241
+ function notSup() {
2242
+ throw new Error("Client-only API called on the server side. Run client-only code in onMount, or conditionally run client-only component with <Show>.");
1923
2243
  }
1924
2244
 
1925
2245
  const isServer = true;
@@ -2007,13 +2327,18 @@ function httpHeader(name, value, options) {
2007
2327
  const response = event && event.response;
2008
2328
  if (response && !response.committed) {
2009
2329
  const headers = response.headers;
2010
- const prev = headers.get(name);
2330
+ const setCookie = name.toLowerCase() === "set-cookie";
2331
+ const prevCookies = setCookie ? headers.getSetCookie() : undefined;
2332
+ const prev = setCookie ? null : headers.get(name);
2011
2333
  if (options && options.append) headers.append(name, value);else headers.set(name, value);
2012
2334
  onCleanup(() => {
2013
2335
  if (response.committed) return;
2014
- if (prev === null) headers.delete(name);else headers.set(name, prev);
2336
+ if (setCookie) {
2337
+ headers.delete(name);
2338
+ for (const cookie of prevCookies) headers.append(name, cookie);
2339
+ } else if (prev === null) headers.delete(name);else headers.set(name, prev);
2015
2340
  });
2016
2341
  }
2017
2342
  }
2018
2343
 
2019
- export { Assets, ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HREF, HydrationScript, MathMLElements, Namespaces, Portal, REVALIDATE_HEADER, RawTextElements, RequestContext, ResponseEnvelope, SVGElements, VoidElements, notSup as acquireAsset, notSup as addEvent, applyRef, notSup as assign, claimElement, claimElementTree, notSup as className, clientOnly, notSup as delegateEvents, dynamic, notSup as dynamicProperty, effect, escape, generateHydrationScript, getAssets, notSup as getDelegatedRoot, getHydrationKey, notSup as getNextElement, notSup as getNextMarker, notSup as getNextMatch, getRequestEvent, httpHeader, httpStatus, notSup as hydrate, notSup as insert, isDev, isHref, isResponseEnvelope, isServer, memo, redirect, notSup as ref, notSup as registerDelegatedContainer, notSup as registerDelegatedRoot, registerElementClaim, reload, notSup as render, renderToStream, renderToString, renderToStringAsync, respond, notSup as runHydrationEvents, notSup as setAttribute, notSup as setAttributeNS, notSup as setProperty, notSup as setStyleProperty, notSup as spread, ssr, ssrAttribute, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrStyle, ssrStyleProperty, notSup as style, notSup as template, notSup as unregisterDelegatedContainer, notSup as unregisterDelegatedRoot, useAssets, useHead };
2344
+ export { ChildProperties, DOMElements, DOMWithState, DelegatedEvents, Dynamic, HREF, HydrationScript, MathMLElements, Namespaces, Portal, REVALIDATE_HEADER, RawTextElements, RequestContext, ResponseEnvelope, SAFE_ERROR, SVGElements, VoidElements, notSup as acquireAsset, notSup as addEvent, applyRef, notSup as assign, claimElement, claimElementTree, notSup as className, clientOnly, commitEventResponse, commitResponseStub, composeMiddleware, createRequestEvent, createResponseStub, createSSRResponse, notSup as delegateEvents, dynamic, notSup as dynamicProperty, effect, escape, generateHydrationScript, notSup as getDelegatedRoot, getExpectedRedirectStatus, getHydrationKey, notSup as getNextElement, notSup as getNextMarker, notSup as getNextMatch, getRequestEvent, httpHeader, httpStatus, notSup as hydrate, notSup as insert, isDev, isHref, isResponseEnvelope, isSafeError, isServer, markSafeError, memo, parseCookieHeader, redirect, notSup as ref, notSup as registerDelegatedContainer, notSup as registerDelegatedRoot, registerElementClaim, reload, notSup as render, renderToStream, renderToString, respond, notSup as runHydrationEvents, serializeCookie, notSup as setAttribute, notSup as setAttributeNS, notSup as setProperty, notSup as setStyleProperty, notSup as spread, ssr, ssrAttribute, ssrClassName, ssrElement, ssrGroup, ssrHydrationKey, ssrStyle, ssrStyleProperty, notSup as style, notSup as template, notSup as unregisterDelegatedContainer, notSup as unregisterDelegatedRoot, useHead };