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

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 (52) hide show
  1. package/dist/dev.cjs +58 -16
  2. package/dist/dev.js +54 -17
  3. package/dist/server.cjs +714 -75
  4. package/dist/server.js +711 -78
  5. package/dist/web.cjs +58 -16
  6. package/dist/web.js +54 -17
  7. package/frames/dist/client.cjs +181 -64
  8. package/frames/dist/client.dev.cjs +185 -64
  9. package/frames/dist/client.dev.js +183 -62
  10. package/frames/dist/client.js +179 -62
  11. package/frames/dist/server.cjs +972 -136
  12. package/frames/dist/server.js +974 -138
  13. package/package.json +17 -6
  14. package/serialization/decode/package.json +20 -0
  15. package/serialization/dist/decode.cjs +110 -0
  16. package/serialization/dist/decode.js +104 -0
  17. package/serialization/dist/serialization.cjs +98 -43
  18. package/serialization/dist/serialization.js +99 -44
  19. package/serialization/types/index.d.ts +18 -160
  20. package/serialization/types/serializer-decode.d.ts +182 -0
  21. package/serialization/types-cjs/index.d.cts +18 -160
  22. package/serialization/types-cjs/serializer-decode.d.cts +182 -0
  23. package/server-functions/dist/client.cjs +101 -105
  24. package/server-functions/dist/client.js +101 -105
  25. package/server-functions/dist/server.cjs +131 -107
  26. package/server-functions/dist/server.dev.cjs +131 -107
  27. package/server-functions/dist/server.dev.js +132 -108
  28. package/server-functions/dist/server.js +132 -108
  29. package/types/client.d.ts +23 -1
  30. package/types/cookies.d.ts +93 -0
  31. package/types/core.d.ts +1 -1
  32. package/types/frames/frame-client.d.ts +26 -0
  33. package/types/frames/frame-transport.d.ts +1 -1
  34. package/types/frames/serializer.d.ts +18 -160
  35. package/types/serializer-decode.d.ts +182 -0
  36. package/types/serializer.d.ts +18 -160
  37. package/types/server-functions/client.d.ts +1 -1
  38. package/types/server-functions/server.d.ts +1 -1
  39. package/types/server-functions/shared.d.ts +57 -1
  40. package/types/server.d.ts +21 -1
  41. package/types-cjs/client.d.cts +23 -1
  42. package/types-cjs/cookies.d.cts +93 -0
  43. package/types-cjs/core.d.cts +1 -1
  44. package/types-cjs/frames/frame-client.d.cts +26 -0
  45. package/types-cjs/frames/frame-transport.d.cts +1 -1
  46. package/types-cjs/frames/serializer.d.cts +18 -160
  47. package/types-cjs/serializer-decode.d.cts +182 -0
  48. package/types-cjs/serializer.d.cts +18 -160
  49. package/types-cjs/server-functions/client.d.cts +1 -1
  50. package/types-cjs/server-functions/server.d.cts +1 -1
  51. package/types-cjs/server-functions/shared.d.cts +57 -1
  52. package/types-cjs/server.d.cts +21 -1
@@ -1,10 +1,8 @@
1
1
  'use strict';
2
2
 
3
3
  var solidJs = require('solid-js');
4
- var web$1 = require('@solidjs/web');
5
- var seroval = require('seroval');
4
+ var web = require('@solidjs/web');
6
5
  var client = require('@solidjs/web/server-functions/client');
7
- var web = require('seroval-plugins/web');
8
6
 
9
7
  const ELEMENT_NODE = 1;
10
8
  const TEXT_NODE = 3;
@@ -67,16 +65,32 @@ function chunkToRecords(chunk) {
67
65
  args: chunk.args
68
66
  }
69
67
  };
68
+ case "hole":
69
+ return {
70
+ [`hole:${chunk.key}`]: {
71
+ kind: "html",
72
+ value: chunk.html
73
+ }
74
+ };
75
+ case "attr":
76
+ return {
77
+ [`attr:${chunk.key}`]: {
78
+ kind: "attrs",
79
+ value: chunk.attrs,
80
+ removed: chunk.removed
81
+ }
82
+ };
70
83
  case "complete":
71
84
  return {
72
85
  ":complete": true
73
86
  };
74
87
  case "error":
75
- return chunk.key ? {
76
- [`seg:${chunk.key}:error`]: chunk.error
77
- } : {
88
+ if (!chunk.key) return {
78
89
  ":error": chunk.error
79
90
  };
91
+ return {
92
+ [`${/^lha?:/.test(chunk.key) ? "hole" : "seg"}:${chunk.key}:error`]: chunk.error
93
+ };
80
94
  default:
81
95
  return {};
82
96
  }
@@ -161,7 +175,10 @@ function createFrameHost(options = {}) {
161
175
  },
162
176
  resolve(ref, frameId) {
163
177
  return options.resolve ? options.resolve(ref, frameId) : undefined;
164
- }
178
+ },
179
+ revive: options.revive,
180
+ isContainer: options.isContainer,
181
+ prepareData: options.prepareData
165
182
  };
166
183
  }
167
184
  const FRAME_APPLIED_EVENT = "frame:applied";
@@ -177,6 +194,7 @@ class FrameImpl {
177
194
  #errorNotified = false;
178
195
  #revealed = new Set();
179
196
  #fallbackShown = new Set();
197
+ #appliedHoles = new Map();
180
198
  #slots;
181
199
  #mountedSlots = new Set();
182
200
  #slotCleanups = new Map();
@@ -277,6 +295,7 @@ class FrameImpl {
277
295
  #resetStreamState(root) {
278
296
  this.#revealed.clear();
279
297
  this.#fallbackShown.clear();
298
+ this.#appliedHoles.clear();
280
299
  this.#errorNotified = false;
281
300
  clearStreamRecords(this.#store, root);
282
301
  }
@@ -318,6 +337,23 @@ class FrameImpl {
318
337
  }
319
338
  }
320
339
  }
340
+ for (const key in this.#store) {
341
+ const record = this.#store[key];
342
+ if (!record || this.#appliedHoles.get(key) === record) continue;
343
+ if (key.startsWith("hole:")) {
344
+ if (key.endsWith(":error")) {
345
+ this.#appliedHoles.set(key, record);
346
+ } else if (this.#applyHole(key.slice(5), record.value)) {
347
+ this.#appliedHoles.set(key, record);
348
+ this.#applied(version, "morph");
349
+ }
350
+ } else if (key.startsWith("attr:")) {
351
+ if (this.#applyAttrs(key.slice(5), record.value, record.removed)) {
352
+ this.#appliedHoles.set(key, record);
353
+ this.#applied(version, "morph");
354
+ }
355
+ }
356
+ }
321
357
  for (const key in this.#store) {
322
358
  if (this.#processedAssets.has(key) || !key.endsWith(":assets")) continue;
323
359
  this.#processedAssets.add(key);
@@ -494,7 +530,7 @@ class FrameImpl {
494
530
  }
495
531
  props[key] = entry.element;
496
532
  } else {
497
- props[key] = value;
533
+ props[key] = host && host.revive ? host.revive(value) : value;
498
534
  }
499
535
  }
500
536
  return props;
@@ -522,6 +558,10 @@ class FrameImpl {
522
558
  if (isDataRef(va) && isDataRef(vb) && cache && key in cache) {
523
559
  const host = this.#options.host;
524
560
  const next = host ? host.resolve(vb, this.#options.id) : undefined;
561
+ if (host && host.isContainer && (host.isContainer(next) || host.isContainer(cache[key]))) {
562
+ if (next === cache[key]) continue;
563
+ return false;
564
+ }
525
565
  if (isAsyncLike(next) || isAsyncLike(cache[key])) return false;
526
566
  try {
527
567
  if (JSON.stringify(next) === JSON.stringify(cache[key])) continue;
@@ -630,6 +670,35 @@ class FrameImpl {
630
670
  if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
631
671
  }
632
672
  }
673
+ #applyHole(marker, html) {
674
+ if (!this.#hasContent) return false;
675
+ const open = findLiveTarget(this.#firstContent(), this.#end, n => n.nodeType === COMMENT_NODE && n.data === marker);
676
+ if (!open) return false;
677
+ const close = rangeClose(open, "lh:/" + marker.slice(3));
678
+ if (!close) {
679
+ return false;
680
+ }
681
+ const claim = claimHandlers() ? this.#claimTree : null;
682
+ reconcileChildren(open.parentNode, parseFragment(html), open, close, claim);
683
+ return true;
684
+ }
685
+ #applyAttrs(addr, text, removed) {
686
+ if (!this.#hasContent) return false;
687
+ const el = findLiveTarget(this.#firstContent(), this.#end, n => n.nodeType === ELEMENT_NODE && n.getAttribute("data-lha") === addr);
688
+ if (!el) return false;
689
+ const parsed = parseFragment(`<i${text}></i>`).firstChild;
690
+ if (parsed) {
691
+ for (let i = 0; i < parsed.attributes.length; i++) {
692
+ const {
693
+ name,
694
+ value
695
+ } = parsed.attributes[i];
696
+ if (el.getAttribute(name) !== value) el.setAttribute(name, value);
697
+ }
698
+ }
699
+ if (removed) for (const name of removed) el.removeAttribute(name);
700
+ return true;
701
+ }
633
702
  #clearContent() {
634
703
  removeUntil(this.#parent(), this.#firstContent(), this.#end);
635
704
  }
@@ -822,6 +891,20 @@ function rangeClose(start, id) {
822
891
  }
823
892
  return null;
824
893
  }
894
+ function findLiveTarget(n, end, test) {
895
+ while (n && n !== end) {
896
+ if (n.nodeType === ELEMENT_NODE) {
897
+ const fid = isFrameElement(n) ? n.getAttribute(FRAME_ID_ATTR) : null;
898
+ if (fid === null || fid.includes(".")) {
899
+ if (test(n)) return n;
900
+ const found = findLiveTarget(n.firstChild, null, test);
901
+ if (found) return found;
902
+ }
903
+ } else if (test(n)) return n;
904
+ n = n.nextSibling;
905
+ }
906
+ return null;
907
+ }
825
908
  function findPlaceholder(n, end, id) {
826
909
  while (n && n !== end) {
827
910
  if (isPlaceholderStart(n, id)) return n;
@@ -880,7 +963,9 @@ function eachInRange(start, key, cb) {
880
963
  }
881
964
  function clearStreamRecords(records, root) {
882
965
  for (const key in records) {
883
- if (key.startsWith("seg:") || key === ":error" || root && key === "") delete records[key];
966
+ if (/^(seg|hole|attr):/.test(key) || key === ":error" || root && key === "") {
967
+ delete records[key];
968
+ }
884
969
  }
885
970
  }
886
971
  function argsEquivalent(a, b) {
@@ -1136,6 +1221,7 @@ async function applyFrameResponse(response, host, options = {}) {
1136
1221
  if (v === undefined) perFrame.set(chunk.id, v = version(chunk.id));
1137
1222
  chunk.version = v;
1138
1223
  } else if (version !== undefined) chunk.version = version;
1224
+ if (chunk.type === "data" && host.prepareData) await host.prepareData();
1139
1225
  host.apply(chunk);
1140
1226
  }
1141
1227
  result = await reader.next();
@@ -1152,7 +1238,7 @@ function parseServerComponent(value, ctx) {
1152
1238
  address: ctx.parse(value[SERVER_COMPONENT_ADDRESS])
1153
1239
  };
1154
1240
  }
1155
- const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
1241
+ const ServerComponentPlugin = {
1156
1242
  tag: "dom-expressions/server-component",
1157
1243
  test(value) {
1158
1244
  return typeof value === "function" && SERVER_COMPONENT in value;
@@ -1179,12 +1265,10 @@ const ServerComponentPlugin = /*#__PURE__*/seroval.createPlugin({
1179
1265
  }
1180
1266
  return globalThis._$SC.r(id);
1181
1267
  }
1182
- });
1268
+ };
1183
1269
  function flightCodec(codec) {
1184
1270
  const plugins = codec && codec.plugins || [];
1185
- for (const plugin of plugins) {
1186
- if (plugin && plugin.tag === "dom-expressions/server-component") return codec;
1187
- }
1271
+ if (plugins.some(plugin => plugin && plugin.tag === ServerComponentPlugin.tag)) return codec;
1188
1272
  return {
1189
1273
  ...codec,
1190
1274
  plugins: [...plugins, ServerComponentPlugin]
@@ -1301,72 +1385,74 @@ function createServerComponentHandler({
1301
1385
  }
1302
1386
  }
1303
1387
 
1304
- seroval.Feature.AggregateError | seroval.Feature.BigIntTypedArray;
1305
- const DEFAULT_WEB_PLUGINS = Object.freeze([web.AbortSignalPlugin,
1306
- web.CustomEventPlugin, web.DOMExceptionPlugin, web.EventPlugin,
1307
- web.FormDataPlugin, web.HeadersPlugin, web.ReadableStreamPlugin, web.RequestPlugin, web.ResponsePlugin, web.URLSearchParamsPlugin, web.URLPlugin]);
1308
- function resolveSerializerPlugins(customPlugins) {
1309
- return customPlugins ? [...customPlugins, ...DEFAULT_WEB_PLUGINS] : [...DEFAULT_WEB_PLUGINS];
1310
- }
1311
- const JSON_CODEC_DISABLED_FEATURES = seroval.Feature.RegExp;
1312
- const JSON_CODEC_DEPTH_LIMIT = 64;
1313
- function resolveCodecOptions({
1314
- plugins,
1315
- disabledFeatures,
1316
- depthLimit
1317
- } = {}) {
1318
- return {
1319
- plugins: resolveSerializerPlugins(plugins),
1320
- disabledFeatures: disabledFeatures === undefined ? JSON_CODEC_DISABLED_FEATURES : disabledFeatures,
1321
- depthLimit: depthLimit === undefined ? JSON_CODEC_DEPTH_LIMIT : depthLimit
1322
- };
1388
+ const STATE = Symbol.for("dom-expressions.container-trace-state");
1389
+ const state = globalThis[STATE] || (globalThis[STATE] = {
1390
+ materialized: new WeakMap(),
1391
+ materializedValues: new WeakSet()
1392
+ });
1393
+ function setContainerTraceMaterializer(fn) {
1394
+ state.materializeTrace = fn;
1323
1395
  }
1324
- function createJSONDeserializer(options) {
1325
- const refs = new Map();
1326
- const resolved = resolveCodecOptions(options);
1327
- return function deserializeJSONChunk(node) {
1328
- return seroval.fromCrossJSON(node, {
1329
- refs,
1330
- ...resolved
1331
- });
1332
- };
1396
+ function materialize(marker) {
1397
+ let value = state.materialized.get(marker.$tr);
1398
+ if (value === undefined) {
1399
+ value = state.materializeTrace(marker);
1400
+ state.materialized.set(marker.$tr, value);
1401
+ if (value !== null && typeof value === "object") state.materializedValues.add(value);
1402
+ }
1403
+ return value;
1333
1404
  }
1334
- function createJSONDataTable(options) {
1335
- const deserialize = createJSONDeserializer(options);
1336
- const table = new Map();
1337
- return {
1338
- apply(record) {
1339
- const value = deserialize(record.node);
1340
- if (record.initial) table.set(record.key, value);
1341
- },
1342
- get(key) {
1343
- return table.get(key);
1344
- },
1345
- resolve(ref) {
1346
- return table.get(ref.$ref);
1347
- }
1348
- };
1405
+ function isMaterializedContainer(value) {
1406
+ return value !== null && typeof value === "object" && state.materializedValues.has(value);
1407
+ }
1408
+ function isContainerTraceMarker(value) {
1409
+ return value != null && typeof value === "object" && value.$tr != null && typeof value.$tr[Symbol.asyncIterator] === "function";
1410
+ }
1411
+ function reviveContainerTraces(value) {
1412
+ if (!state.materializeTrace || value == null || typeof value !== "object") return value;
1413
+ if (isContainerTraceMarker(value)) return materialize(value);
1414
+ if (Array.isArray(value)) {
1415
+ for (let i = 0; i < value.length; i++) value[i] = reviveContainerTraces(value[i]);
1416
+ } else if (Object.getPrototypeOf(value) === Object.prototype) {
1417
+ for (const key of Object.keys(value)) value[key] = reviveContainerTraces(value[key]);
1418
+ }
1419
+ return value;
1349
1420
  }
1350
1421
 
1422
+ setContainerTraceMaterializer(solidJs.materializeContainerTrace);
1351
1423
  function asyncArg(value) {
1352
1424
  return value;
1353
1425
  }
1354
1426
  let sharedHost;
1427
+ let codec;
1428
+ let codecLoading;
1429
+ function loadCodec() {
1430
+ return codecLoading ??= import('@solidjs/web/serialization/decode').then(m => {
1431
+ codec = m;
1432
+ });
1433
+ }
1355
1434
  const tables = new Map();
1435
+ function ensureTable(root) {
1436
+ let table = tables.get(root);
1437
+ if (!table && codec) tables.set(root, table = codec.createJSONDataTable());
1438
+ return table;
1439
+ }
1356
1440
  function tableFor(id) {
1357
- const table = tables.get(id);
1358
- if (table) return table;
1359
- for (const [root, t] of tables) if (id.startsWith(root + ".")) return t;
1441
+ if (tables.has(id)) return ensureTable(id);
1442
+ for (const root of tables.keys()) if (id.startsWith(root + ".")) return ensureTable(root);
1360
1443
  return undefined;
1361
1444
  }
1362
1445
  function beginStream(frameId) {
1363
- tables.set(frameId, createJSONDataTable());
1446
+ tables.set(frameId, undefined);
1364
1447
  }
1365
1448
  function getFrameHost() {
1366
1449
  if (!sharedHost) {
1367
1450
  sharedHost = createFrameHost({
1451
+ prepareData: loadCodec,
1368
1452
  applyData: c => tableFor(c.id)?.apply(c),
1369
- resolve: (ref, id) => tableFor(id)?.resolve(ref)
1453
+ resolve: (ref, id) => tableFor(id)?.resolve(ref),
1454
+ revive: reviveContainerTraces,
1455
+ isContainer: isMaterializedContainer
1370
1456
  });
1371
1457
  }
1372
1458
  return sharedHost;
@@ -1438,6 +1524,7 @@ function slotArgsProxy(args) {
1438
1524
  return new Proxy({}, {
1439
1525
  get: (_, key) => {
1440
1526
  const v = args()[key];
1527
+ if (isMaterializedContainer(v)) return v;
1441
1528
  if (!isAsyncValue(v)) return v;
1442
1529
  let read = asyncReads.get(key);
1443
1530
  if (!read) {
@@ -1519,7 +1606,7 @@ function slotsFor(props) {
1519
1606
  owner.dispose();
1520
1607
  });
1521
1608
  const end = ctx.range.end;
1522
- const bind = () => web$1.insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
1609
+ const bind = () => web.insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
1523
1610
  solidJs.runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
1524
1611
  return undefined;
1525
1612
  }
@@ -1529,7 +1616,7 @@ function slotsFor(props) {
1529
1616
  });
1530
1617
  }
1531
1618
  function revealSeam(owner) {
1532
- return seam => solidJs.runWithOwner(owner, () => web$1.insert(seam.before.parentNode, solidJs.createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
1619
+ return seam => solidJs.runWithOwner(owner, () => web.insert(seam.before.parentNode, solidJs.createLoadingBoundary(() => seam.content(), () => seam.fallback), seam.before));
1533
1620
  }
1534
1621
  let streamInvoke = false;
1535
1622
  function boundaryScope(owner) {
@@ -1589,6 +1676,24 @@ function boundaryComponent(host, fnId) {
1589
1676
  };
1590
1677
  }
1591
1678
  const claimedBoundaries = new Set();
1679
+ const liveOps = new Map();
1680
+ const liveAppliers = new Set();
1681
+ let livePumped = null;
1682
+ function pumpLiveChannel() {
1683
+ const stream = globalThis._$HY?.r?.["sc:live"];
1684
+ if (!stream || stream === livePumped || typeof stream.getReader !== "function") return;
1685
+ livePumped = stream;
1686
+ const reader = stream.getReader();
1687
+ const pump = () => reader.read().then(r => {
1688
+ if (r.done) return;
1689
+ const op = r.value;
1690
+ liveOps.set(`${op.type}:${op.fid || ""}:${op.key || ""}`, op);
1691
+ for (const apply of liveAppliers) apply(op);
1692
+ return pump();
1693
+ });
1694
+ pump().catch(() => {
1695
+ });
1696
+ }
1592
1697
  let boundaryIndex = null;
1593
1698
  const isBoundaryId = id => !id.includes(".");
1594
1699
  function indexBoundaries(root) {
@@ -1667,6 +1772,7 @@ function adoptBoundary(host, id, el, props, binding) {
1667
1772
  const drainRecords = () => {
1668
1773
  const hy = globalThis._$HY;
1669
1774
  if (!hy || !hy.r) return;
1775
+ pumpLiveChannel();
1670
1776
  const slotPrefix = `sc:slot:${id}:`;
1671
1777
  for (const key of Object.keys(hy.r)) {
1672
1778
  if (appliedRecords.has(key)) continue;
@@ -1701,11 +1807,22 @@ function adoptBoundary(host, id, el, props, binding) {
1701
1807
  if (fr.claim && parent && el.contains(parent)) claimRegionFragments(parent);
1702
1808
  drainRecords();
1703
1809
  }) : undefined;
1810
+ const applyLiveOp = op => {
1811
+ if (op.type === "slot" && op.fid !== id) return;
1812
+ host.apply({
1813
+ ...op,
1814
+ id: address,
1815
+ version: 0
1816
+ });
1817
+ };
1818
+ liveAppliers.add(applyLiveOp);
1704
1819
  solidJs.onCleanup(() => {
1820
+ liveAppliers.delete(applyLiveOp);
1705
1821
  unsubscribe && unsubscribe();
1706
1822
  if (fr && fr.release) for (const fragId of claimedFragments) fr.release(fragId);
1707
1823
  });
1708
1824
  drainRecords();
1825
+ for (const op of liveOps.values()) applyLiveOp(op);
1709
1826
  const owner = solidJs.getOwner();
1710
1827
  let release;
1711
1828
  let setGate;