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