@solidjs/web 2.0.0-beta.26 → 2.0.0-beta.28

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 (43) hide show
  1. package/dist/dev.cjs +3 -1
  2. package/dist/dev.js +3 -2
  3. package/dist/server.cjs +64 -84
  4. package/dist/server.js +65 -86
  5. package/dist/web.cjs +3 -1
  6. package/dist/web.js +3 -2
  7. package/frames/dist/client.cjs +69 -21
  8. package/frames/dist/client.dev.cjs +69 -21
  9. package/frames/dist/client.dev.js +70 -22
  10. package/frames/dist/client.js +70 -22
  11. package/frames/dist/server.cjs +55 -50
  12. package/frames/dist/server.js +55 -50
  13. package/package.json +4 -4
  14. package/serialization/dist/serialization.cjs +6 -3
  15. package/serialization/dist/serialization.js +6 -3
  16. package/serialization/types/index.d.ts +7 -1
  17. package/serialization/types-cjs/index.d.cts +7 -1
  18. package/server-functions/dist/client.cjs +28 -2
  19. package/server-functions/dist/client.js +25 -3
  20. package/server-functions/dist/server.cjs +194 -5
  21. package/server-functions/dist/server.js +187 -6
  22. package/types/client.d.ts +3 -3
  23. package/types/frames/client.d.ts +1 -0
  24. package/types/frames/serializer.d.ts +7 -1
  25. package/types/frames/server.d.ts +28 -0
  26. package/types/jsx.d.ts +1 -1
  27. package/types/response.d.ts +10 -0
  28. package/types/serializer.d.ts +7 -1
  29. package/types/server-functions/client.d.ts +4 -0
  30. package/types/server-functions/flash.d.ts +38 -0
  31. package/types/server-functions/server.d.ts +109 -6
  32. package/types/server-functions/shared.d.ts +48 -0
  33. package/types-cjs/client.d.cts +3 -3
  34. package/types-cjs/frames/client.d.cts +1 -0
  35. package/types-cjs/frames/serializer.d.cts +7 -1
  36. package/types-cjs/frames/server.d.cts +28 -0
  37. package/types-cjs/jsx.d.cts +1 -1
  38. package/types-cjs/response.d.cts +10 -0
  39. package/types-cjs/serializer.d.cts +7 -1
  40. package/types-cjs/server-functions/client.d.cts +4 -0
  41. package/types-cjs/server-functions/flash.d.cts +38 -0
  42. package/types-cjs/server-functions/server.d.cts +109 -6
  43. package/types-cjs/server-functions/shared.d.cts +48 -0
@@ -9,6 +9,7 @@ const runWithHydrationScope = (id, fn) => solidJs.runWithOwner(solidJs.createOwn
9
9
  }), fn);
10
10
 
11
11
  const DEFAULT_DISABLED_FEATURES = seroval.Feature.AggregateError | seroval.Feature.BigIntTypedArray;
12
+ const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : seroval.Feature.ErrorPrototypeStack;
12
13
  const HYDRATION_GLOBAL = "_$HY.r";
13
14
  const DEFAULT_WEB_PLUGINS = Object.freeze([web.AbortSignalPlugin,
14
15
  web.CustomEventPlugin, web.DOMExceptionPlugin, web.EventPlugin,
@@ -20,7 +21,7 @@ function createSerializer(options) {
20
21
  return new seroval.Serializer({
21
22
  ...options,
22
23
  plugins: resolveSerializerPlugins(options.plugins),
23
- disabledFeatures: options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures
24
+ disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures()
24
25
  });
25
26
  }
26
27
  function createHydrationSerializer({
@@ -88,7 +89,7 @@ function createJSONSerializer({
88
89
  const stream = seroval.toCrossJSONStream(value, {
89
90
  refs,
90
91
  plugins: resolved.plugins,
91
- disabledFeatures: resolved.disabledFeatures,
92
+ disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures(),
92
93
  onParse(node, initial) {
93
94
  onData({
94
95
  key,
@@ -219,7 +220,24 @@ function createAssetTracking() {
219
220
  }
220
221
  };
221
222
  }
222
- function applyAssetTracking(context, tracking, manifest) {
223
+ function warnUnresolvedModuleAssets(moduleUrl, warned) {
224
+ if (warned.has(moduleUrl)) return;
225
+ warned.add(moduleUrl);
226
+ console.error(`Asset manifest returned no client assets for module "${moduleUrl}". ` + "If this module is a server-rendered lazy() component, its entry will be missing from " + "the serialized hydration asset map, the client will be unable to preload it, and " + "hydration will fail with 'lazy() module \"…\" was not preloaded before hydration'. " + "This means the integration's asset resolver (dev manifest bridge or build client " + "manifest) failed to answer for this module — check the integration's server logs, " + "restart the dev server, or verify the module is included in the client build.");
227
+ }
228
+ function guardResolvedAssets(moduleUrl, result, warned) {
229
+ if (result && typeof result.then === "function") {
230
+ return result.then(assets => {
231
+ if (!assets || !assets.js || !assets.js.length) warnUnresolvedModuleAssets(moduleUrl, warned);
232
+ return assets;
233
+ });
234
+ }
235
+ if (!result || !result.js || !result.js.length) warnUnresolvedModuleAssets(moduleUrl, warned);
236
+ return result;
237
+ }
238
+ function applyAssetTracking(context, tracking, manifest, noScripts) {
239
+ const warned = new Set();
240
+ const guard = noScripts ? resolve => resolve : resolve => moduleUrl => guardResolvedAssets(moduleUrl, resolve(moduleUrl), warned);
223
241
  Object.defineProperty(context, "_currentBoundaryId", {
224
242
  get() {
225
243
  return tracking.currentBoundaryId;
@@ -233,19 +251,19 @@ function applyAssetTracking(context, tracking, manifest) {
233
251
  context.registerModule = tracking.registerModule;
234
252
  context.getBoundaryModules = tracking.getBoundaryModules;
235
253
  if (typeof manifest === "function") {
236
- context.resolveAssets = manifest;
254
+ context.resolveAssets = guard(manifest);
237
255
  } else if (manifest && typeof manifest.resolve === "function") {
238
- context.resolveAssets = key => manifest.resolve(key);
256
+ context.resolveAssets = guard(key => manifest.resolve(key));
239
257
  if (typeof manifest.resolveSync === "function") {
240
258
  context.resolveAssetsSync = key => manifest.resolveSync(key);
241
259
  }
242
260
  } else if (manifest) {
243
261
  const resolve = moduleUrl => resolveAssets(moduleUrl, manifest);
244
- context.resolveAssets = resolve;
262
+ context.resolveAssets = guard(resolve);
245
263
  context.resolveAssetsSync = resolve;
246
264
  }
247
265
  }
248
- const REPLACE_SCRIPT = `function $df(e,n,o,t){if(!(n=document.getElementById(e)))return 0;if(!(o=document.getElementById("pl-"+e)))return(_$HY.dq=_$HY.dq||{})[e]=1,0;for(;o&&(8!==o.nodeType||o.nodeValue!=="pl-"+e);)t=o.nextSibling,o.remove(),o=t;_$HY.done?o.remove():o.replaceWith(n.content),n.remove(),_$HY.fe(e),$dfd();return 1}function $dfl(e,o,n){if(!(o=document.getElementById("pl-"+e)))return(_$HY.dlq=_$HY.dlq||{})[e]=1,0;if(o._$fl)return 1;for(n=o.nextSibling;n;){if(8===n.nodeType&&n.nodeValue==="pl-"+e){o.parentNode&&o.parentNode.insertBefore(o.content.cloneNode(!0),n),o._$fl=1,$dfd();return 1}n=n.nextSibling}return 0}function $dflj(e,i){for(i=0;i<e.length;i++)$dfl(e[i])}function $dfd(e,i){if(e=_$HY.dq){_$HY.dq=0;for(i in e)$df(i)}if(e=_$HY.dlq){_$HY.dlq=0;for(i in e)$dfl(i)}}function $dfs(e,c,d){(_$HY.sc=_$HY.sc||{})[e]=c,d&&((_$HY.sd=_$HY.sd||{})[e]=1)}function $dfg(e,g,i,k){if(!(g=_$HY.sg&&_$HY.sg[e]))return;for(i=0;i<g.length;i++)if(_$HY.sc&&_$HY.sc[g[i]]>0)return;for(i=0;i<g.length;i++)k=g[i],delete _$HY.sg[k],$df(k)}function $dfc(e){if(--_$HY.sc[e]<=0){delete _$HY.sc[e],_$HY.sg&&_$HY.sg[e]?$dfg(e):!(_$HY.sd&&_$HY.sd[e])&&$df(e);_$HY.sd&&delete _$HY.sd[e]}}function $dfj(e,i,n){for(i=0;i<e.length;i++)if(_$HY.sc&&_$HY.sc[e[i]]>0){for(n=0;n<e.length;n++)(_$HY.sg=_$HY.sg||{})[e[n]]=e;return}for(i=0;i<e.length;i++)$df(e[i])}`;
266
+ const REPLACE_SCRIPT = `function $df(e,n,o,t){if(!(n=document.getElementById(e)))return 0;if(!(o=document.getElementById("pl-"+e)))return(_$HY.dq=_$HY.dq||{})[e]=1,0;for(;o&&(8!==o.nodeType||o.nodeValue!=="pl-"+e);)t=o.nextSibling,o.remove(),o=t;t=o.parentNode,_$HY.done?o.remove():o.replaceWith(n.content),n.remove(),_$HY.fe(e,t),$dfd();return 1}function $dfl(e,o,n){if(!(o=document.getElementById("pl-"+e)))return(_$HY.dlq=_$HY.dlq||{})[e]=1,0;if(o._$fl)return 1;for(n=o.nextSibling;n;){if(8===n.nodeType&&n.nodeValue==="pl-"+e){o.parentNode&&o.parentNode.insertBefore(o.content.cloneNode(!0),n),o._$fl=1,$dfd();return 1}n=n.nextSibling}return 0}function $dflj(e,i){for(i=0;i<e.length;i++)$dfl(e[i])}function $dfd(e,i){if(e=_$HY.dq){_$HY.dq=0;for(i in e)$df(i)}if(e=_$HY.dlq){_$HY.dlq=0;for(i in e)$dfl(i)}}function $dfs(e,c,d){(_$HY.sc=_$HY.sc||{})[e]=c,d&&((_$HY.sd=_$HY.sd||{})[e]=1)}function $dfg(e,g,i,k){if(!(g=_$HY.sg&&_$HY.sg[e]))return;for(i=0;i<g.length;i++)if(_$HY.sc&&_$HY.sc[g[i]]>0)return;for(i=0;i<g.length;i++)k=g[i],delete _$HY.sg[k],$df(k)}function $dfc(e){if(--_$HY.sc[e]<=0){delete _$HY.sc[e],_$HY.sg&&_$HY.sg[e]?$dfg(e):!(_$HY.sd&&_$HY.sd[e])&&$df(e);_$HY.sd&&delete _$HY.sd[e]}}function $dfj(e,i,n){for(i=0;i<e.length;i++)if(_$HY.sc&&_$HY.sc[e[i]]>0){for(n=0;n<e.length;n++)(_$HY.sg=_$HY.sg||{})[e[n]]=e;return}for(i=0;i<e.length;i++)$df(e[i])}`;
249
267
  function renderToStream(code, options = {}) {
250
268
  let {
251
269
  nonce,
@@ -317,11 +335,7 @@ function renderToStream(code, options = {}) {
317
335
  }
318
336
  },
319
337
  shell(shellHtml, meta) {
320
- shellHtml = injectBeforeHead(shellHtml, meta.assets);
321
- shellHtml = injectPreloadLinks(meta.preloads, shellHtml);
322
- shellHtml = injectInlineStyles(meta.inlineStyles, shellHtml, nonce);
323
- if (meta.tasks.length) shellHtml = injectScripts(shellHtml, meta.tasks, nonce);
324
- buffer.write(shellHtml);
338
+ buffer.write(assembleDocument(shellHtml, meta.assets, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce));
325
339
  },
326
340
  ...options.sink
327
341
  };
@@ -524,7 +538,7 @@ function renderToStream(code, options = {}) {
524
538
  });
525
539
  }
526
540
  };
527
- applyAssetTracking(context, tracking, manifest);
541
+ applyAssetTracking(context, tracking, manifest, noScripts);
528
542
  registerEntryAssets(manifest);
529
543
  let html = solidJs.createRoot(d => {
530
544
  dispose = d;
@@ -952,25 +966,36 @@ function resolveAssetsHtml(assets) {
952
966
  for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
953
967
  return out;
954
968
  }
955
- function injectBeforeHead(html, content) {
956
- if (!content) return html;
957
- const index = html.indexOf("</head>");
958
- if (index === -1) return html;
959
- return html.slice(0, index) + content + html.slice(index);
960
- }
961
- function injectPreloadLinks(emittedAssets, html, nonce) {
962
- if (!emittedAssets.size) return html;
963
- let links = "";
964
- for (const url of emittedAssets) {
965
- if (url.endsWith(".css")) {
966
- links += `<link rel="stylesheet" href="${url}">`;
967
- } else {
968
- links += `<link rel="modulepreload" href="${url}">`;
969
+ function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts, nonce) {
970
+ const scriptTag = scripts ? `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>` : "";
971
+ if (!assetsHtml && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
972
+ if (!scriptTag) return html;
973
+ const xs = html.indexOf("<!--xs-->");
974
+ return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
975
+ }
976
+ const headIdx = html.indexOf("</head>");
977
+ if (headIdx === -1) {
978
+ if (!scriptTag) return html;
979
+ const xs = html.indexOf("<!--xs-->");
980
+ return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
981
+ }
982
+ let head = assetsHtml || "";
983
+ if (emittedAssets && emittedAssets.size) {
984
+ for (const url of emittedAssets) {
985
+ head += url.endsWith(".css") ? `<link rel="stylesheet" href="${url}">` : `<link rel="modulepreload" href="${url}">`;
969
986
  }
970
987
  }
971
- const index = html.indexOf("</head>");
972
- if (index === -1) return html;
973
- return html.slice(0, index) + links + html.slice(index);
988
+ if (inlineStyles && inlineStyles.size) {
989
+ for (const entry of inlineStyles.values()) {
990
+ if (entry.emitted) continue;
991
+ entry.emitted = true;
992
+ head += renderInlineStyle(entry, nonce);
993
+ }
994
+ }
995
+ if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
996
+ const xsIdx = html.indexOf("<!--xs-->");
997
+ if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
998
+ return xsIdx < headIdx ? html.slice(0, xsIdx) + scriptTag + html.slice(xsIdx, headIdx) + head + html.slice(headIdx) : html.slice(0, headIdx) + head + html.slice(headIdx, xsIdx) + scriptTag + html.slice(xsIdx);
974
999
  }
975
1000
  function serializeFragmentAssets(key, boundaryModules, context) {
976
1001
  const map = boundaryModules.get(key);
@@ -1022,26 +1047,6 @@ function renderInlineStyle(entry, nonce) {
1022
1047
  }
1023
1048
  return `<style${nonce ? ` nonce="${nonce}"` : ""} data-asset="${escape(entry.id, true)}"${attrs}>${escapeStyleContent(entry.content)}</style>`;
1024
1049
  }
1025
- function injectInlineStyles(inlineStyles, html, nonce) {
1026
- if (!inlineStyles.size) return html;
1027
- const index = html.indexOf("</head>");
1028
- if (index === -1) return html;
1029
- let out = "";
1030
- for (const entry of inlineStyles.values()) {
1031
- if (entry.emitted) continue;
1032
- entry.emitted = true;
1033
- out += renderInlineStyle(entry, nonce);
1034
- }
1035
- return out ? html.slice(0, index) + out + html.slice(index) : html;
1036
- }
1037
- function injectScripts(html, scripts, nonce) {
1038
- const tag = `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>`;
1039
- const index = html.indexOf("<!--xs-->");
1040
- if (index > -1) {
1041
- return html.slice(0, index) + tag + html.slice(index);
1042
- }
1043
- return html + tag;
1044
- }
1045
1050
  function waitForFragments(registry, key) {
1046
1051
  for (const k of [...registry.keys()].reverse()) {
1047
1052
  if (key.startsWith(k)) return k;
@@ -7,6 +7,7 @@ const runWithHydrationScope = (id, fn) => runWithOwner(createOwner({
7
7
  }), fn);
8
8
 
9
9
  const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
10
+ const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
10
11
  const HYDRATION_GLOBAL = "_$HY.r";
11
12
  const DEFAULT_WEB_PLUGINS = Object.freeze([AbortSignalPlugin,
12
13
  CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
@@ -18,7 +19,7 @@ function createSerializer(options) {
18
19
  return new Serializer({
19
20
  ...options,
20
21
  plugins: resolveSerializerPlugins(options.plugins),
21
- disabledFeatures: options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures
22
+ disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures()
22
23
  });
23
24
  }
24
25
  function createHydrationSerializer({
@@ -86,7 +87,7 @@ function createJSONSerializer({
86
87
  const stream = toCrossJSONStream(value, {
87
88
  refs,
88
89
  plugins: resolved.plugins,
89
- disabledFeatures: resolved.disabledFeatures,
90
+ disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures(),
90
91
  onParse(node, initial) {
91
92
  onData({
92
93
  key,
@@ -217,7 +218,24 @@ function createAssetTracking() {
217
218
  }
218
219
  };
219
220
  }
220
- function applyAssetTracking(context, tracking, manifest) {
221
+ function warnUnresolvedModuleAssets(moduleUrl, warned) {
222
+ if (warned.has(moduleUrl)) return;
223
+ warned.add(moduleUrl);
224
+ console.error(`Asset manifest returned no client assets for module "${moduleUrl}". ` + "If this module is a server-rendered lazy() component, its entry will be missing from " + "the serialized hydration asset map, the client will be unable to preload it, and " + "hydration will fail with 'lazy() module \"…\" was not preloaded before hydration'. " + "This means the integration's asset resolver (dev manifest bridge or build client " + "manifest) failed to answer for this module — check the integration's server logs, " + "restart the dev server, or verify the module is included in the client build.");
225
+ }
226
+ function guardResolvedAssets(moduleUrl, result, warned) {
227
+ if (result && typeof result.then === "function") {
228
+ return result.then(assets => {
229
+ if (!assets || !assets.js || !assets.js.length) warnUnresolvedModuleAssets(moduleUrl, warned);
230
+ return assets;
231
+ });
232
+ }
233
+ if (!result || !result.js || !result.js.length) warnUnresolvedModuleAssets(moduleUrl, warned);
234
+ return result;
235
+ }
236
+ function applyAssetTracking(context, tracking, manifest, noScripts) {
237
+ const warned = new Set();
238
+ const guard = noScripts ? resolve => resolve : resolve => moduleUrl => guardResolvedAssets(moduleUrl, resolve(moduleUrl), warned);
221
239
  Object.defineProperty(context, "_currentBoundaryId", {
222
240
  get() {
223
241
  return tracking.currentBoundaryId;
@@ -231,19 +249,19 @@ function applyAssetTracking(context, tracking, manifest) {
231
249
  context.registerModule = tracking.registerModule;
232
250
  context.getBoundaryModules = tracking.getBoundaryModules;
233
251
  if (typeof manifest === "function") {
234
- context.resolveAssets = manifest;
252
+ context.resolveAssets = guard(manifest);
235
253
  } else if (manifest && typeof manifest.resolve === "function") {
236
- context.resolveAssets = key => manifest.resolve(key);
254
+ context.resolveAssets = guard(key => manifest.resolve(key));
237
255
  if (typeof manifest.resolveSync === "function") {
238
256
  context.resolveAssetsSync = key => manifest.resolveSync(key);
239
257
  }
240
258
  } else if (manifest) {
241
259
  const resolve = moduleUrl => resolveAssets(moduleUrl, manifest);
242
- context.resolveAssets = resolve;
260
+ context.resolveAssets = guard(resolve);
243
261
  context.resolveAssetsSync = resolve;
244
262
  }
245
263
  }
246
- const REPLACE_SCRIPT = `function $df(e,n,o,t){if(!(n=document.getElementById(e)))return 0;if(!(o=document.getElementById("pl-"+e)))return(_$HY.dq=_$HY.dq||{})[e]=1,0;for(;o&&(8!==o.nodeType||o.nodeValue!=="pl-"+e);)t=o.nextSibling,o.remove(),o=t;_$HY.done?o.remove():o.replaceWith(n.content),n.remove(),_$HY.fe(e),$dfd();return 1}function $dfl(e,o,n){if(!(o=document.getElementById("pl-"+e)))return(_$HY.dlq=_$HY.dlq||{})[e]=1,0;if(o._$fl)return 1;for(n=o.nextSibling;n;){if(8===n.nodeType&&n.nodeValue==="pl-"+e){o.parentNode&&o.parentNode.insertBefore(o.content.cloneNode(!0),n),o._$fl=1,$dfd();return 1}n=n.nextSibling}return 0}function $dflj(e,i){for(i=0;i<e.length;i++)$dfl(e[i])}function $dfd(e,i){if(e=_$HY.dq){_$HY.dq=0;for(i in e)$df(i)}if(e=_$HY.dlq){_$HY.dlq=0;for(i in e)$dfl(i)}}function $dfs(e,c,d){(_$HY.sc=_$HY.sc||{})[e]=c,d&&((_$HY.sd=_$HY.sd||{})[e]=1)}function $dfg(e,g,i,k){if(!(g=_$HY.sg&&_$HY.sg[e]))return;for(i=0;i<g.length;i++)if(_$HY.sc&&_$HY.sc[g[i]]>0)return;for(i=0;i<g.length;i++)k=g[i],delete _$HY.sg[k],$df(k)}function $dfc(e){if(--_$HY.sc[e]<=0){delete _$HY.sc[e],_$HY.sg&&_$HY.sg[e]?$dfg(e):!(_$HY.sd&&_$HY.sd[e])&&$df(e);_$HY.sd&&delete _$HY.sd[e]}}function $dfj(e,i,n){for(i=0;i<e.length;i++)if(_$HY.sc&&_$HY.sc[e[i]]>0){for(n=0;n<e.length;n++)(_$HY.sg=_$HY.sg||{})[e[n]]=e;return}for(i=0;i<e.length;i++)$df(e[i])}`;
264
+ const REPLACE_SCRIPT = `function $df(e,n,o,t){if(!(n=document.getElementById(e)))return 0;if(!(o=document.getElementById("pl-"+e)))return(_$HY.dq=_$HY.dq||{})[e]=1,0;for(;o&&(8!==o.nodeType||o.nodeValue!=="pl-"+e);)t=o.nextSibling,o.remove(),o=t;t=o.parentNode,_$HY.done?o.remove():o.replaceWith(n.content),n.remove(),_$HY.fe(e,t),$dfd();return 1}function $dfl(e,o,n){if(!(o=document.getElementById("pl-"+e)))return(_$HY.dlq=_$HY.dlq||{})[e]=1,0;if(o._$fl)return 1;for(n=o.nextSibling;n;){if(8===n.nodeType&&n.nodeValue==="pl-"+e){o.parentNode&&o.parentNode.insertBefore(o.content.cloneNode(!0),n),o._$fl=1,$dfd();return 1}n=n.nextSibling}return 0}function $dflj(e,i){for(i=0;i<e.length;i++)$dfl(e[i])}function $dfd(e,i){if(e=_$HY.dq){_$HY.dq=0;for(i in e)$df(i)}if(e=_$HY.dlq){_$HY.dlq=0;for(i in e)$dfl(i)}}function $dfs(e,c,d){(_$HY.sc=_$HY.sc||{})[e]=c,d&&((_$HY.sd=_$HY.sd||{})[e]=1)}function $dfg(e,g,i,k){if(!(g=_$HY.sg&&_$HY.sg[e]))return;for(i=0;i<g.length;i++)if(_$HY.sc&&_$HY.sc[g[i]]>0)return;for(i=0;i<g.length;i++)k=g[i],delete _$HY.sg[k],$df(k)}function $dfc(e){if(--_$HY.sc[e]<=0){delete _$HY.sc[e],_$HY.sg&&_$HY.sg[e]?$dfg(e):!(_$HY.sd&&_$HY.sd[e])&&$df(e);_$HY.sd&&delete _$HY.sd[e]}}function $dfj(e,i,n){for(i=0;i<e.length;i++)if(_$HY.sc&&_$HY.sc[e[i]]>0){for(n=0;n<e.length;n++)(_$HY.sg=_$HY.sg||{})[e[n]]=e;return}for(i=0;i<e.length;i++)$df(e[i])}`;
247
265
  function renderToStream(code, options = {}) {
248
266
  let {
249
267
  nonce,
@@ -315,11 +333,7 @@ function renderToStream(code, options = {}) {
315
333
  }
316
334
  },
317
335
  shell(shellHtml, meta) {
318
- shellHtml = injectBeforeHead(shellHtml, meta.assets);
319
- shellHtml = injectPreloadLinks(meta.preloads, shellHtml);
320
- shellHtml = injectInlineStyles(meta.inlineStyles, shellHtml, nonce);
321
- if (meta.tasks.length) shellHtml = injectScripts(shellHtml, meta.tasks, nonce);
322
- buffer.write(shellHtml);
336
+ buffer.write(assembleDocument(shellHtml, meta.assets, meta.preloads, meta.inlineStyles, meta.tasks.length ? meta.tasks : "", nonce));
323
337
  },
324
338
  ...options.sink
325
339
  };
@@ -522,7 +536,7 @@ function renderToStream(code, options = {}) {
522
536
  });
523
537
  }
524
538
  };
525
- applyAssetTracking(context, tracking, manifest);
539
+ applyAssetTracking(context, tracking, manifest, noScripts);
526
540
  registerEntryAssets(manifest);
527
541
  let html = createRoot(d => {
528
542
  dispose = d;
@@ -950,25 +964,36 @@ function resolveAssetsHtml(assets) {
950
964
  for (let i = 0, len = assets.length; i < len; i++) out += assets[i]();
951
965
  return out;
952
966
  }
953
- function injectBeforeHead(html, content) {
954
- if (!content) return html;
955
- const index = html.indexOf("</head>");
956
- if (index === -1) return html;
957
- return html.slice(0, index) + content + html.slice(index);
958
- }
959
- function injectPreloadLinks(emittedAssets, html, nonce) {
960
- if (!emittedAssets.size) return html;
961
- let links = "";
962
- for (const url of emittedAssets) {
963
- if (url.endsWith(".css")) {
964
- links += `<link rel="stylesheet" href="${url}">`;
965
- } else {
966
- links += `<link rel="modulepreload" href="${url}">`;
967
+ function assembleDocument(html, assetsHtml, emittedAssets, inlineStyles, scripts, nonce) {
968
+ const scriptTag = scripts ? `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>` : "";
969
+ if (!assetsHtml && !(emittedAssets && emittedAssets.size) && !(inlineStyles && inlineStyles.size)) {
970
+ if (!scriptTag) return html;
971
+ const xs = html.indexOf("<!--xs-->");
972
+ return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
973
+ }
974
+ const headIdx = html.indexOf("</head>");
975
+ if (headIdx === -1) {
976
+ if (!scriptTag) return html;
977
+ const xs = html.indexOf("<!--xs-->");
978
+ return xs === -1 ? html + scriptTag : html.slice(0, xs) + scriptTag + html.slice(xs);
979
+ }
980
+ let head = assetsHtml || "";
981
+ if (emittedAssets && emittedAssets.size) {
982
+ for (const url of emittedAssets) {
983
+ head += url.endsWith(".css") ? `<link rel="stylesheet" href="${url}">` : `<link rel="modulepreload" href="${url}">`;
967
984
  }
968
985
  }
969
- const index = html.indexOf("</head>");
970
- if (index === -1) return html;
971
- return html.slice(0, index) + links + html.slice(index);
986
+ if (inlineStyles && inlineStyles.size) {
987
+ for (const entry of inlineStyles.values()) {
988
+ if (entry.emitted) continue;
989
+ entry.emitted = true;
990
+ head += renderInlineStyle(entry, nonce);
991
+ }
992
+ }
993
+ if (!scriptTag) return html.slice(0, headIdx) + head + html.slice(headIdx);
994
+ const xsIdx = html.indexOf("<!--xs-->");
995
+ if (xsIdx === -1) return html.slice(0, headIdx) + head + html.slice(headIdx) + scriptTag;
996
+ return xsIdx < headIdx ? html.slice(0, xsIdx) + scriptTag + html.slice(xsIdx, headIdx) + head + html.slice(headIdx) : html.slice(0, headIdx) + head + html.slice(headIdx, xsIdx) + scriptTag + html.slice(xsIdx);
972
997
  }
973
998
  function serializeFragmentAssets(key, boundaryModules, context) {
974
999
  const map = boundaryModules.get(key);
@@ -1020,26 +1045,6 @@ function renderInlineStyle(entry, nonce) {
1020
1045
  }
1021
1046
  return `<style${nonce ? ` nonce="${nonce}"` : ""} data-asset="${escape(entry.id, true)}"${attrs}>${escapeStyleContent(entry.content)}</style>`;
1022
1047
  }
1023
- function injectInlineStyles(inlineStyles, html, nonce) {
1024
- if (!inlineStyles.size) return html;
1025
- const index = html.indexOf("</head>");
1026
- if (index === -1) return html;
1027
- let out = "";
1028
- for (const entry of inlineStyles.values()) {
1029
- if (entry.emitted) continue;
1030
- entry.emitted = true;
1031
- out += renderInlineStyle(entry, nonce);
1032
- }
1033
- return out ? html.slice(0, index) + out + html.slice(index) : html;
1034
- }
1035
- function injectScripts(html, scripts, nonce) {
1036
- const tag = `<script${nonce ? ` nonce="${nonce}"` : ""}>${scripts}</script>`;
1037
- const index = html.indexOf("<!--xs-->");
1038
- if (index > -1) {
1039
- return html.slice(0, index) + tag + html.slice(index);
1040
- }
1041
- return html + tag;
1042
- }
1043
1048
  function waitForFragments(registry, key) {
1044
1049
  for (const k of [...registry.keys()].reverse()) {
1045
1050
  if (key.startsWith(k)) return k;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@solidjs/web",
3
3
  "description": "Solid's web runtime: client rendering, hydration, SSR, and DOM-specific control flow (Portal, Dynamic).",
4
- "version": "2.0.0-beta.26",
4
+ "version": "2.0.0-beta.28",
5
5
  "author": "Ryan Carniato",
6
6
  "license": "MIT",
7
7
  "homepage": "https://solidjs.com",
@@ -316,10 +316,10 @@
316
316
  "seroval-plugins": "~1.5.4"
317
317
  },
318
318
  "peerDependencies": {
319
- "solid-js": "^2.0.0-beta.26"
319
+ "solid-js": "^2.0.0-beta.28"
320
320
  },
321
321
  "devDependencies": {
322
- "solid-js": "2.0.0-beta.26"
322
+ "solid-js": "2.0.0-beta.28"
323
323
  },
324
324
  "scripts": {
325
325
  "build": "npm-run-all -nl build:clean types:copy-jsx build:js",
@@ -334,7 +334,7 @@
334
334
  "types:web-storage": "tsc --project ./storage/tsconfig.build.json",
335
335
  "types:web-frames": "tsc --project ./frames/tsconfig.build.json",
336
336
  "types:copy-serialization": "node -e \"fs.mkdirSync('./serialization/types', { recursive: true }); fs.copyFileSync('../../node_modules/@dom-expressions/runtime/src/serializer.d.ts', './serialization/types/index.d.ts');\"",
337
- "types:copy-server-functions": "node -e \"fs.mkdirSync('./types/server-functions', { recursive: true }); for (const f of ['shared', 'client', 'server']) fs.copyFileSync('../../node_modules/@dom-expressions/runtime/src/server-functions/' + f + '.d.ts', './types/server-functions/' + f + '.d.ts');\"",
337
+ "types:copy-server-functions": "node -e \"fs.mkdirSync('./types/server-functions', { recursive: true }); for (const f of ['shared', 'flash', 'client', 'server']) fs.copyFileSync('../../node_modules/@dom-expressions/runtime/src/server-functions/' + f + '.d.ts', './types/server-functions/' + f + '.d.ts');\"",
338
338
  "types:copy-frames": "node -e \"fs.mkdirSync('./types/frames', { recursive: true }); for (const f of ['frame-client', 'frame-transport', 'frame-sink', 'serializer']) fs.copyFileSync('../../node_modules/@dom-expressions/runtime/src/' + f + '.d.ts', './types/frames/' + f + '.d.ts'); for (const f of ['client', 'server']) fs.writeFileSync('./types/frames/' + f + '.d.ts', fs.readFileSync('./frames/types/' + f + '.d.ts', 'utf8').replaceAll('@dom-expressions/runtime/src/', './'));\"",
339
339
  "types:cjs": "node ../../scripts/sync-dual-types.mjs ./types ./types-cjs ./storage/types ./storage/types-cjs ./serialization/types ./serialization/types-cjs",
340
340
  "test": "vitest run && vitest run --config vite.config.server.mjs && vitest run --config vite.config.hydrate.mjs",
@@ -4,6 +4,7 @@ var seroval = require('seroval');
4
4
  var web = require('seroval-plugins/web');
5
5
 
6
6
  const DEFAULT_DISABLED_FEATURES = seroval.Feature.AggregateError | seroval.Feature.BigIntTypedArray;
7
+ const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : seroval.Feature.ErrorPrototypeStack;
7
8
  const HYDRATION_GLOBAL = "_$HY.r";
8
9
  const DEFAULT_WEB_PLUGINS = Object.freeze([web.AbortSignalPlugin,
9
10
  web.CustomEventPlugin, web.DOMExceptionPlugin, web.EventPlugin,
@@ -15,7 +16,7 @@ function createSerializer(options) {
15
16
  return new seroval.Serializer({
16
17
  ...options,
17
18
  plugins: resolveSerializerPlugins(options.plugins),
18
- disabledFeatures: options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures
19
+ disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures()
19
20
  });
20
21
  }
21
22
  function createHydrationSerializer({
@@ -56,11 +57,13 @@ function serializeJSON(value, {
56
57
  onError,
57
58
  ...codecOptions
58
59
  }) {
60
+ const resolved = resolveCodecOptions(codecOptions);
59
61
  return seroval.toCrossJSONStream(value, {
60
62
  onParse,
61
63
  onDone,
62
64
  onError,
63
- ...resolveCodecOptions(codecOptions)
65
+ ...resolved,
66
+ disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
64
67
  });
65
68
  }
66
69
  function createJSONDeserializer(options) {
@@ -106,7 +109,7 @@ function createJSONSerializer({
106
109
  const stream = seroval.toCrossJSONStream(value, {
107
110
  refs,
108
111
  plugins: resolved.plugins,
109
- disabledFeatures: resolved.disabledFeatures,
112
+ disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures(),
110
113
  onParse(node, initial) {
111
114
  onData({
112
115
  key,
@@ -2,6 +2,7 @@ import { Feature, Serializer, getCrossReferenceHeader, toCrossJSONStream, fromCr
2
2
  import { AbortSignalPlugin, CustomEventPlugin, DOMExceptionPlugin, EventPlugin, FormDataPlugin, HeadersPlugin, ReadableStreamPlugin, RequestPlugin, ResponsePlugin, URLSearchParamsPlugin, URLPlugin } from 'seroval-plugins/web';
3
3
 
4
4
  const DEFAULT_DISABLED_FEATURES = Feature.AggregateError | Feature.BigIntTypedArray;
5
+ const serializeOnlyDisabledFeatures = () => process.env.NODE_ENV === "development" ? 0 : Feature.ErrorPrototypeStack;
5
6
  const HYDRATION_GLOBAL = "_$HY.r";
6
7
  const DEFAULT_WEB_PLUGINS = Object.freeze([AbortSignalPlugin,
7
8
  CustomEventPlugin, DOMExceptionPlugin, EventPlugin,
@@ -13,7 +14,7 @@ function createSerializer(options) {
13
14
  return new Serializer({
14
15
  ...options,
15
16
  plugins: resolveSerializerPlugins(options.plugins),
16
- disabledFeatures: options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures
17
+ disabledFeatures: (options.disabledFeatures === undefined ? DEFAULT_DISABLED_FEATURES : options.disabledFeatures) | serializeOnlyDisabledFeatures()
17
18
  });
18
19
  }
19
20
  function createHydrationSerializer({
@@ -54,11 +55,13 @@ function serializeJSON(value, {
54
55
  onError,
55
56
  ...codecOptions
56
57
  }) {
58
+ const resolved = resolveCodecOptions(codecOptions);
57
59
  return toCrossJSONStream(value, {
58
60
  onParse,
59
61
  onDone,
60
62
  onError,
61
- ...resolveCodecOptions(codecOptions)
63
+ ...resolved,
64
+ disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures()
62
65
  });
63
66
  }
64
67
  function createJSONDeserializer(options) {
@@ -104,7 +107,7 @@ function createJSONSerializer({
104
107
  const stream = toCrossJSONStream(value, {
105
108
  refs,
106
109
  plugins: resolved.plugins,
107
- disabledFeatures: resolved.disabledFeatures,
110
+ disabledFeatures: resolved.disabledFeatures | serializeOnlyDisabledFeatures(),
108
111
  onParse(node, initial) {
109
112
  onData({
110
113
  key,
@@ -37,7 +37,9 @@ export interface WebSerializerOptions {
37
37
  scopeId?: string;
38
38
  /**
39
39
  * Seroval feature bitflags to exclude from output. Defaults to disabling
40
- * post-ES2017 features (AggregateError, BigInt typed arrays).
40
+ * post-ES2017 features (AggregateError, BigInt typed arrays). Outside
41
+ * development, `Error.prototype.stack` is additionally stripped on top of
42
+ * any override — serialized stacks leak server paths to the client.
41
43
  */
42
44
  disabledFeatures?: number;
43
45
  /** Extra plugins, composed ahead of `DEFAULT_WEB_PLUGINS`. */
@@ -101,6 +103,10 @@ export interface JSONCodecOptions {
101
103
  /**
102
104
  * Seroval feature bitflags to exclude. Defaults to disabling `RegExp`
103
105
  * (payloads may come from an untrusted peer). Must match on both peers.
106
+ * Outside development, the encoding side additionally strips
107
+ * `Error.prototype.stack` on top of any override — serialized stacks leak
108
+ * server paths to the client. Decoding stays permissive, so payloads from
109
+ * a development peer still round-trip.
104
110
  */
105
111
  disabledFeatures?: number;
106
112
  /** Maximum parse/deserialize depth. Defaults to 64. Must match on both peers. */
@@ -37,7 +37,9 @@ export interface WebSerializerOptions {
37
37
  scopeId?: string;
38
38
  /**
39
39
  * Seroval feature bitflags to exclude from output. Defaults to disabling
40
- * post-ES2017 features (AggregateError, BigInt typed arrays).
40
+ * post-ES2017 features (AggregateError, BigInt typed arrays). Outside
41
+ * development, `Error.prototype.stack` is additionally stripped on top of
42
+ * any override — serialized stacks leak server paths to the client.
41
43
  */
42
44
  disabledFeatures?: number;
43
45
  /** Extra plugins, composed ahead of `DEFAULT_WEB_PLUGINS`. */
@@ -101,6 +103,10 @@ export interface JSONCodecOptions {
101
103
  /**
102
104
  * Seroval feature bitflags to exclude. Defaults to disabling `RegExp`
103
105
  * (payloads may come from an untrusted peer). Must match on both peers.
106
+ * Outside development, the encoding side additionally strips
107
+ * `Error.prototype.stack` on top of any override — serialized stacks leak
108
+ * server paths to the client. Decoding stays permissive, so payloads from
109
+ * a development peer still round-trip.
104
110
  */
105
111
  disabledFeatures?: number;
106
112
  /** Maximum parse/deserialize depth. Defaults to 64. Must match on both peers. */
@@ -3,6 +3,8 @@
3
3
  var seroval = require('seroval');
4
4
  var web = require('seroval-plugins/web');
5
5
 
6
+ const REVALIDATE_HEADER = "X-Revalidate";
7
+
6
8
  seroval.Feature.AggregateError | seroval.Feature.BigIntTypedArray;
7
9
  const DEFAULT_WEB_PLUGINS = Object.freeze([web.AbortSignalPlugin,
8
10
  web.CustomEventPlugin, web.DOMExceptionPlugin, web.EventPlugin,
@@ -98,6 +100,14 @@ const INSTANCE_HEADER = "X-Server-Function-Instance";
98
100
  const BODY_FORMAT_HEADER = "X-Server-Function-Format";
99
101
  const SINGLE_FLIGHT_HEADER = "X-Single-Flight";
100
102
  const FILE_FORM_KEY = "__server_function_file__";
103
+ const FLASH_COOKIE = "flash";
104
+ const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
105
+ function hasFlashCookie(cookieHeader) {
106
+ return !!cookieHeader && FLASH_MATCHER.test(cookieHeader);
107
+ }
108
+ function clearFlashCookie() {
109
+ return `${FLASH_COOKIE}=; Max-Age=0; Path=/`;
110
+ }
101
111
  const BodyFormat = {
102
112
  Serialized: "0",
103
113
  String: "1",
@@ -277,6 +287,18 @@ async function decodeResponse(response, codecOptions) {
277
287
  if (!response.body) return undefined;
278
288
  return await extractBody(response, codecOptions === undefined ? codecConfig.codec : codecOptions);
279
289
  }
290
+ async function decodeResponsePayload(response, codecOptions) {
291
+ const decoded = await decodeResponse(response, codecOptions);
292
+ if (decoded !== undefined && response.headers.has(SINGLE_FLIGHT_HEADER)) {
293
+ return {
294
+ value: decoded.value,
295
+ flightData: decoded.data
296
+ };
297
+ }
298
+ return {
299
+ value: decoded
300
+ };
301
+ }
280
302
 
281
303
  const config = {
282
304
  endpoint: "/_server",
@@ -403,13 +425,13 @@ async function fetchServerFunction(base, id, options, args, meta) {
403
425
  await consumer(payload.data, {
404
426
  response
405
427
  });
406
- if (response.headers.has(ERROR_HEADER) && !response.headers.has("Location") && !response.headers.has("X-Revalidate")) {
428
+ if (response.headers.has(ERROR_HEADER) && !response.headers.has("Location") && !response.headers.has(REVALIDATE_HEADER)) {
407
429
  throw payload.value;
408
430
  }
409
431
  return payload.value;
410
432
  }
411
433
  }
412
- if (response.headers.has("Location") || response.headers.has("X-Revalidate") || response.headers.has(SINGLE_FLIGHT_HEADER)) {
434
+ if (response.headers.has("Location") || response.headers.has(REVALIDATE_HEADER) || response.headers.has(SINGLE_FLIGHT_HEADER)) {
413
435
  return response;
414
436
  }
415
437
  const result = await decodeResponse(response.clone());
@@ -487,16 +509,20 @@ function registerServerReference() {
487
509
  }
488
510
 
489
511
  exports.ERROR_HEADER = ERROR_HEADER;
512
+ exports.FLASH_COOKIE = FLASH_COOKIE;
490
513
  exports.FUNCTION_HEADER = FUNCTION_HEADER;
491
514
  exports.GET = GET;
492
515
  exports.INSTANCE_HEADER = INSTANCE_HEADER;
493
516
  exports.SINGLE_FLIGHT_HEADER = SINGLE_FLIGHT_HEADER;
517
+ exports.clearFlashCookie = clearFlashCookie;
494
518
  exports.configureServerFunctionsClient = configureServerFunctionsClient;
495
519
  exports.createServerReference = createServerReference;
496
520
  exports.decodeErrorHeaderValue = decodeErrorHeaderValue;
497
521
  exports.decodeResponse = decodeResponse;
522
+ exports.decodeResponsePayload = decodeResponsePayload;
498
523
  exports.encodeErrorHeaderValue = encodeErrorHeaderValue;
499
524
  exports.getServerFunctionMetadata = getServerFunctionMetadata;
525
+ exports.hasFlashCookie = hasFlashCookie;
500
526
  exports.isServerFunction = isServerFunction;
501
527
  exports.registerServerReference = registerServerReference;
502
528
  exports.subscribeFlightData = subscribeFlightData;