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

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 (39) hide show
  1. package/dist/dev.cjs +3 -1
  2. package/dist/dev.js +3 -2
  3. package/dist/server.cjs +41 -78
  4. package/dist/server.js +42 -80
  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 +33 -45
  12. package/frames/dist/server.js +33 -45
  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 +15 -2
  19. package/server-functions/dist/client.js +13 -3
  20. package/server-functions/dist/server.cjs +161 -5
  21. package/server-functions/dist/server.js +155 -6
  22. package/types/client.d.ts +3 -3
  23. package/types/frames/serializer.d.ts +7 -1
  24. package/types/jsx.d.ts +1 -1
  25. package/types/response.d.ts +10 -0
  26. package/types/serializer.d.ts +7 -1
  27. package/types/server-functions/client.d.ts +3 -0
  28. package/types/server-functions/flash.d.ts +38 -0
  29. package/types/server-functions/server.d.ts +79 -4
  30. package/types/server-functions/shared.d.ts +35 -0
  31. package/types-cjs/client.d.cts +3 -3
  32. package/types-cjs/frames/serializer.d.cts +7 -1
  33. package/types-cjs/jsx.d.cts +1 -1
  34. package/types-cjs/response.d.cts +10 -0
  35. package/types-cjs/serializer.d.cts +7 -1
  36. package/types-cjs/server-functions/client.d.cts +3 -0
  37. package/types-cjs/server-functions/flash.d.cts +38 -0
  38. package/types-cjs/server-functions/server.d.cts +79 -4
  39. package/types-cjs/server-functions/shared.d.cts +35 -0
@@ -114,7 +114,7 @@ function createFrameHost(options = {}) {
114
114
  pending.delete(id);
115
115
  const records = {};
116
116
  let version;
117
- for (const chunk of buffered) {
117
+ for (const chunk of buffered.chunks) {
118
118
  if (chunk.type === "data") {
119
119
  options.applyData && options.applyData(chunk);
120
120
  continue;
@@ -146,12 +146,20 @@ function createFrameHost(options = {}) {
146
146
  for (const frame of set) deliver(frame, chunk);
147
147
  return;
148
148
  }
149
- const buffered = pending.get(chunk.id) ?? [];
150
- const maxVersion = buffered.reduce((m, c) => Math.max(m, c.version), chunk.version);
151
- if (chunk.version < maxVersion) return;
152
- const kept = buffered.filter(c => c.version >= chunk.version);
153
- kept.push(chunk);
154
- pending.set(chunk.id, kept);
149
+ const buffered = pending.get(chunk.id);
150
+ if (!buffered) {
151
+ pending.set(chunk.id, {
152
+ version: chunk.version,
153
+ chunks: [chunk]
154
+ });
155
+ return;
156
+ }
157
+ if (chunk.version < buffered.version) return;
158
+ if (chunk.version > buffered.version) {
159
+ buffered.version = chunk.version;
160
+ buffered.chunks.length = 0;
161
+ }
162
+ buffered.chunks.push(chunk);
155
163
  },
156
164
  get(id) {
157
165
  const set = frames.get(id);
@@ -210,7 +218,7 @@ class FrameImpl {
210
218
  if (options.host && options.id !== undefined) {
211
219
  options.host.register(options.id, this);
212
220
  }
213
- if (options.adopt) this.#syncSlots();
221
+ if (options.adopt && this.#version === undefined) this.#syncSlots();
214
222
  }
215
223
  #parent() {
216
224
  return this.#element ?? this.#start.parentNode;
@@ -354,7 +362,7 @@ class FrameImpl {
354
362
  if (nodes) this.#replaceRange(occurrence, start, nodes);
355
363
  this.#slotNodes.set(occurrence, nodes);
356
364
  this.#mountedSlots.add(occurrence);
357
- this.#discoverRegions(occurrence, start);
365
+ if (!this.#options.adopt || nodes) this.#discoverRegions(occurrence, start);
358
366
  this.#bindRegions(occurrence);
359
367
  } else if (record !== this.#slotArgs.get(occurrence)) {
360
368
  if (this.#refArgsUnchanged(occurrence, record)) {
@@ -1226,15 +1234,18 @@ function normalizeSlotContent(value) {
1226
1234
  if (value == null || typeof value === "boolean") return document.createTextNode("");
1227
1235
  return value instanceof Node ? value : document.createTextNode(String(value));
1228
1236
  }
1237
+ function gatherClaims(el, registry) {
1238
+ if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
1239
+ if (el.hasAttribute(FRAME_ID_ATTR)) return;
1240
+ for (let c = el.firstElementChild; c; c = c.nextElementSibling) gatherClaims(c, registry);
1241
+ }
1229
1242
  function claimRender(prefix, existing, render) {
1230
1243
  const sc = solidJs.sharedConfig;
1231
1244
  if (!sc.getNextContextId) return render();
1232
1245
  const registry = new Map();
1233
1246
  for (const n of existing) {
1234
- const el = n;
1235
- if (el.nodeType !== 1) continue;
1236
- if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
1237
- el.querySelectorAll("*[_hk]").forEach(child => registry.set(child.getAttribute("_hk"), child));
1247
+ if (n.nodeType !== 1) continue;
1248
+ gatherClaims(n, registry);
1238
1249
  }
1239
1250
  if (!registry.size) return render();
1240
1251
  const prevRegistry = sc.registry;
@@ -1298,21 +1309,57 @@ function boundaryComponent(host, id) {
1298
1309
  }
1299
1310
  const claimedBoundaries = new Set();
1300
1311
  let boundaryIndex = null;
1312
+ const isBoundaryId = id => !id.includes(".");
1313
+ function indexBoundaries(root) {
1314
+ root.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
1315
+ const key = el.getAttribute(FRAME_ID_ATTR);
1316
+ if (key && isBoundaryId(key) && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
1317
+ });
1318
+ }
1301
1319
  function findBoundaryElement(id) {
1302
1320
  if (!boundaryIndex) {
1303
1321
  boundaryIndex = new Map();
1304
- if (typeof document !== "undefined" && document.body) {
1305
- document.body.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
1306
- const key = el.getAttribute(FRAME_ID_ATTR);
1307
- if (key && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
1308
- });
1309
- }
1322
+ if (typeof document !== "undefined" && document.body) indexBoundaries(document.body);
1310
1323
  }
1311
1324
  return boundaryIndex.get(id);
1312
1325
  }
1326
+ const boundaryWaiters = new Map();
1327
+ function documentStreaming() {
1328
+ const hy = globalThis._$HY;
1329
+ return !!hy && !hy.done;
1330
+ }
1331
+ function installRevealHook() {
1332
+ const hy = globalThis._$HY;
1333
+ if (!hy || hy.$sc) return;
1334
+ hy.$sc = true;
1335
+ const prev = hy.fe;
1336
+ hy.fe = (fragmentId, parent) => {
1337
+ if (prev) prev(fragmentId, parent);
1338
+ if (!boundaryIndex) return;
1339
+ const root = parent || (typeof document !== "undefined" ? document.body : null);
1340
+ if (!root) return;
1341
+ indexBoundaries(root);
1342
+ for (const [id, notify] of boundaryWaiters) {
1343
+ const el = boundaryIndex.get(id);
1344
+ if (!el) continue;
1345
+ boundaryWaiters.delete(id);
1346
+ notify(el);
1347
+ }
1348
+ };
1349
+ }
1313
1350
  function documentBoundary(host, id, props) {
1314
- const el = !claimedBoundaries.has(id) ? findBoundaryElement(id) : undefined;
1315
- if (!el) return boundaryComponent(host, id)(props);
1351
+ const claimed = claimedBoundaries.has(id);
1352
+ const el = !claimed ? findBoundaryElement(id) : undefined;
1353
+ if (el) return adoptBoundary(host, id, el, props);
1354
+ if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
1355
+ const owner = solidJs.getOwner();
1356
+ const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
1357
+ solidJs.onCleanup(() => boundaryWaiters.delete(id));
1358
+ return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
1359
+ }
1360
+ return boundaryComponent(host, id)(props);
1361
+ }
1362
+ function adoptBoundary(host, id, el, props) {
1316
1363
  claimedBoundaries.add(id);
1317
1364
  const hy = globalThis._$HY;
1318
1365
  if (hy && hy.r) {
@@ -1364,6 +1411,7 @@ function installServerComponents(host = getFrameHost()) {
1364
1411
  };
1365
1412
  }
1366
1413
  g._$SC.impl = (id, props) => documentBoundary(host, id, props);
1414
+ installRevealHook();
1367
1415
  client.configureServerFunctionsClient({
1368
1416
  responseHandler: createServerComponentHandler({
1369
1417
  host,
@@ -114,7 +114,7 @@ function createFrameHost(options = {}) {
114
114
  pending.delete(id);
115
115
  const records = {};
116
116
  let version;
117
- for (const chunk of buffered) {
117
+ for (const chunk of buffered.chunks) {
118
118
  if (chunk.type === "data") {
119
119
  options.applyData && options.applyData(chunk);
120
120
  continue;
@@ -146,12 +146,20 @@ function createFrameHost(options = {}) {
146
146
  for (const frame of set) deliver(frame, chunk);
147
147
  return;
148
148
  }
149
- const buffered = pending.get(chunk.id) ?? [];
150
- const maxVersion = buffered.reduce((m, c) => Math.max(m, c.version), chunk.version);
151
- if (chunk.version < maxVersion) return;
152
- const kept = buffered.filter(c => c.version >= chunk.version);
153
- kept.push(chunk);
154
- pending.set(chunk.id, kept);
149
+ const buffered = pending.get(chunk.id);
150
+ if (!buffered) {
151
+ pending.set(chunk.id, {
152
+ version: chunk.version,
153
+ chunks: [chunk]
154
+ });
155
+ return;
156
+ }
157
+ if (chunk.version < buffered.version) return;
158
+ if (chunk.version > buffered.version) {
159
+ buffered.version = chunk.version;
160
+ buffered.chunks.length = 0;
161
+ }
162
+ buffered.chunks.push(chunk);
155
163
  },
156
164
  get(id) {
157
165
  const set = frames.get(id);
@@ -210,7 +218,7 @@ class FrameImpl {
210
218
  if (options.host && options.id !== undefined) {
211
219
  options.host.register(options.id, this);
212
220
  }
213
- if (options.adopt) this.#syncSlots();
221
+ if (options.adopt && this.#version === undefined) this.#syncSlots();
214
222
  }
215
223
  #parent() {
216
224
  return this.#element ?? this.#start.parentNode;
@@ -354,7 +362,7 @@ class FrameImpl {
354
362
  if (nodes) this.#replaceRange(occurrence, start, nodes);
355
363
  this.#slotNodes.set(occurrence, nodes);
356
364
  this.#mountedSlots.add(occurrence);
357
- this.#discoverRegions(occurrence, start);
365
+ if (!this.#options.adopt || nodes) this.#discoverRegions(occurrence, start);
358
366
  this.#bindRegions(occurrence);
359
367
  } else if (record !== this.#slotArgs.get(occurrence)) {
360
368
  if (this.#refArgsUnchanged(occurrence, record)) {
@@ -1240,15 +1248,18 @@ function normalizeSlotContent(value) {
1240
1248
  if (value == null || typeof value === "boolean") return document.createTextNode("");
1241
1249
  return value instanceof Node ? value : document.createTextNode(String(value));
1242
1250
  }
1251
+ function gatherClaims(el, registry) {
1252
+ if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
1253
+ if (el.hasAttribute(FRAME_ID_ATTR)) return;
1254
+ for (let c = el.firstElementChild; c; c = c.nextElementSibling) gatherClaims(c, registry);
1255
+ }
1243
1256
  function claimRender(prefix, existing, render) {
1244
1257
  const sc = solidJs.sharedConfig;
1245
1258
  if (!sc.getNextContextId) return render();
1246
1259
  const registry = new Map();
1247
1260
  for (const n of existing) {
1248
- const el = n;
1249
- if (el.nodeType !== 1) continue;
1250
- if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
1251
- el.querySelectorAll("*[_hk]").forEach(child => registry.set(child.getAttribute("_hk"), child));
1261
+ if (n.nodeType !== 1) continue;
1262
+ gatherClaims(n, registry);
1252
1263
  }
1253
1264
  if (!registry.size) return render();
1254
1265
  const prevRegistry = sc.registry;
@@ -1312,21 +1323,57 @@ function boundaryComponent(host, id) {
1312
1323
  }
1313
1324
  const claimedBoundaries = new Set();
1314
1325
  let boundaryIndex = null;
1326
+ const isBoundaryId = id => !id.includes(".");
1327
+ function indexBoundaries(root) {
1328
+ root.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
1329
+ const key = el.getAttribute(FRAME_ID_ATTR);
1330
+ if (key && isBoundaryId(key) && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
1331
+ });
1332
+ }
1315
1333
  function findBoundaryElement(id) {
1316
1334
  if (!boundaryIndex) {
1317
1335
  boundaryIndex = new Map();
1318
- if (typeof document !== "undefined" && document.body) {
1319
- document.body.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
1320
- const key = el.getAttribute(FRAME_ID_ATTR);
1321
- if (key && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
1322
- });
1323
- }
1336
+ if (typeof document !== "undefined" && document.body) indexBoundaries(document.body);
1324
1337
  }
1325
1338
  return boundaryIndex.get(id);
1326
1339
  }
1340
+ const boundaryWaiters = new Map();
1341
+ function documentStreaming() {
1342
+ const hy = globalThis._$HY;
1343
+ return !!hy && !hy.done;
1344
+ }
1345
+ function installRevealHook() {
1346
+ const hy = globalThis._$HY;
1347
+ if (!hy || hy.$sc) return;
1348
+ hy.$sc = true;
1349
+ const prev = hy.fe;
1350
+ hy.fe = (fragmentId, parent) => {
1351
+ if (prev) prev(fragmentId, parent);
1352
+ if (!boundaryIndex) return;
1353
+ const root = parent || (typeof document !== "undefined" ? document.body : null);
1354
+ if (!root) return;
1355
+ indexBoundaries(root);
1356
+ for (const [id, notify] of boundaryWaiters) {
1357
+ const el = boundaryIndex.get(id);
1358
+ if (!el) continue;
1359
+ boundaryWaiters.delete(id);
1360
+ notify(el);
1361
+ }
1362
+ };
1363
+ }
1327
1364
  function documentBoundary(host, id, props) {
1328
- const el = !claimedBoundaries.has(id) ? findBoundaryElement(id) : undefined;
1329
- if (!el) return boundaryComponent(host, id)(props);
1365
+ const claimed = claimedBoundaries.has(id);
1366
+ const el = !claimed ? findBoundaryElement(id) : undefined;
1367
+ if (el) return adoptBoundary(host, id, el, props);
1368
+ if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
1369
+ const owner = solidJs.getOwner();
1370
+ const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
1371
+ solidJs.onCleanup(() => boundaryWaiters.delete(id));
1372
+ return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
1373
+ }
1374
+ return boundaryComponent(host, id)(props);
1375
+ }
1376
+ function adoptBoundary(host, id, el, props) {
1330
1377
  claimedBoundaries.add(id);
1331
1378
  const hy = globalThis._$HY;
1332
1379
  if (hy && hy.r) {
@@ -1378,6 +1425,7 @@ function installServerComponents(host = getFrameHost()) {
1378
1425
  };
1379
1426
  }
1380
1427
  g._$SC.impl = (id, props) => documentBoundary(host, id, props);
1428
+ installRevealHook();
1381
1429
  client.configureServerFunctionsClient({
1382
1430
  responseHandler: createServerComponentHandler({
1383
1431
  host,
@@ -1,4 +1,4 @@
1
- import { getOwner, runWithOwner, onCleanup, createLoadingBoundary, sharedConfig, createOwner } from 'solid-js';
1
+ import { getOwner, onCleanup, createMemo, runWithOwner, createLoadingBoundary, sharedConfig, createOwner } from 'solid-js';
2
2
  import { insert } from '@solidjs/web';
3
3
  import { configureServerFunctionsClient } from '@solidjs/web/server-functions/client';
4
4
  import { fromCrossJSON, Feature } from 'seroval';
@@ -112,7 +112,7 @@ function createFrameHost(options = {}) {
112
112
  pending.delete(id);
113
113
  const records = {};
114
114
  let version;
115
- for (const chunk of buffered) {
115
+ for (const chunk of buffered.chunks) {
116
116
  if (chunk.type === "data") {
117
117
  options.applyData && options.applyData(chunk);
118
118
  continue;
@@ -144,12 +144,20 @@ function createFrameHost(options = {}) {
144
144
  for (const frame of set) deliver(frame, chunk);
145
145
  return;
146
146
  }
147
- const buffered = pending.get(chunk.id) ?? [];
148
- const maxVersion = buffered.reduce((m, c) => Math.max(m, c.version), chunk.version);
149
- if (chunk.version < maxVersion) return;
150
- const kept = buffered.filter(c => c.version >= chunk.version);
151
- kept.push(chunk);
152
- pending.set(chunk.id, kept);
147
+ const buffered = pending.get(chunk.id);
148
+ if (!buffered) {
149
+ pending.set(chunk.id, {
150
+ version: chunk.version,
151
+ chunks: [chunk]
152
+ });
153
+ return;
154
+ }
155
+ if (chunk.version < buffered.version) return;
156
+ if (chunk.version > buffered.version) {
157
+ buffered.version = chunk.version;
158
+ buffered.chunks.length = 0;
159
+ }
160
+ buffered.chunks.push(chunk);
153
161
  },
154
162
  get(id) {
155
163
  const set = frames.get(id);
@@ -208,7 +216,7 @@ class FrameImpl {
208
216
  if (options.host && options.id !== undefined) {
209
217
  options.host.register(options.id, this);
210
218
  }
211
- if (options.adopt) this.#syncSlots();
219
+ if (options.adopt && this.#version === undefined) this.#syncSlots();
212
220
  }
213
221
  #parent() {
214
222
  return this.#element ?? this.#start.parentNode;
@@ -352,7 +360,7 @@ class FrameImpl {
352
360
  if (nodes) this.#replaceRange(occurrence, start, nodes);
353
361
  this.#slotNodes.set(occurrence, nodes);
354
362
  this.#mountedSlots.add(occurrence);
355
- this.#discoverRegions(occurrence, start);
363
+ if (!this.#options.adopt || nodes) this.#discoverRegions(occurrence, start);
356
364
  this.#bindRegions(occurrence);
357
365
  } else if (record !== this.#slotArgs.get(occurrence)) {
358
366
  if (this.#refArgsUnchanged(occurrence, record)) {
@@ -1238,15 +1246,18 @@ function normalizeSlotContent(value) {
1238
1246
  if (value == null || typeof value === "boolean") return document.createTextNode("");
1239
1247
  return value instanceof Node ? value : document.createTextNode(String(value));
1240
1248
  }
1249
+ function gatherClaims(el, registry) {
1250
+ if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
1251
+ if (el.hasAttribute(FRAME_ID_ATTR)) return;
1252
+ for (let c = el.firstElementChild; c; c = c.nextElementSibling) gatherClaims(c, registry);
1253
+ }
1241
1254
  function claimRender(prefix, existing, render) {
1242
1255
  const sc = sharedConfig;
1243
1256
  if (!sc.getNextContextId) return render();
1244
1257
  const registry = new Map();
1245
1258
  for (const n of existing) {
1246
- const el = n;
1247
- if (el.nodeType !== 1) continue;
1248
- if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
1249
- el.querySelectorAll("*[_hk]").forEach(child => registry.set(child.getAttribute("_hk"), child));
1259
+ if (n.nodeType !== 1) continue;
1260
+ gatherClaims(n, registry);
1250
1261
  }
1251
1262
  if (!registry.size) return render();
1252
1263
  const prevRegistry = sc.registry;
@@ -1310,21 +1321,57 @@ function boundaryComponent(host, id) {
1310
1321
  }
1311
1322
  const claimedBoundaries = new Set();
1312
1323
  let boundaryIndex = null;
1324
+ const isBoundaryId = id => !id.includes(".");
1325
+ function indexBoundaries(root) {
1326
+ root.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
1327
+ const key = el.getAttribute(FRAME_ID_ATTR);
1328
+ if (key && isBoundaryId(key) && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
1329
+ });
1330
+ }
1313
1331
  function findBoundaryElement(id) {
1314
1332
  if (!boundaryIndex) {
1315
1333
  boundaryIndex = new Map();
1316
- if (typeof document !== "undefined" && document.body) {
1317
- document.body.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
1318
- const key = el.getAttribute(FRAME_ID_ATTR);
1319
- if (key && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
1320
- });
1321
- }
1334
+ if (typeof document !== "undefined" && document.body) indexBoundaries(document.body);
1322
1335
  }
1323
1336
  return boundaryIndex.get(id);
1324
1337
  }
1338
+ const boundaryWaiters = new Map();
1339
+ function documentStreaming() {
1340
+ const hy = globalThis._$HY;
1341
+ return !!hy && !hy.done;
1342
+ }
1343
+ function installRevealHook() {
1344
+ const hy = globalThis._$HY;
1345
+ if (!hy || hy.$sc) return;
1346
+ hy.$sc = true;
1347
+ const prev = hy.fe;
1348
+ hy.fe = (fragmentId, parent) => {
1349
+ if (prev) prev(fragmentId, parent);
1350
+ if (!boundaryIndex) return;
1351
+ const root = parent || (typeof document !== "undefined" ? document.body : null);
1352
+ if (!root) return;
1353
+ indexBoundaries(root);
1354
+ for (const [id, notify] of boundaryWaiters) {
1355
+ const el = boundaryIndex.get(id);
1356
+ if (!el) continue;
1357
+ boundaryWaiters.delete(id);
1358
+ notify(el);
1359
+ }
1360
+ };
1361
+ }
1325
1362
  function documentBoundary(host, id, props) {
1326
- const el = !claimedBoundaries.has(id) ? findBoundaryElement(id) : undefined;
1327
- if (!el) return boundaryComponent(host, id)(props);
1363
+ const claimed = claimedBoundaries.has(id);
1364
+ const el = !claimed ? findBoundaryElement(id) : undefined;
1365
+ if (el) return adoptBoundary(host, id, el, props);
1366
+ if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
1367
+ const owner = getOwner();
1368
+ const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
1369
+ onCleanup(() => boundaryWaiters.delete(id));
1370
+ return createMemo(() => arrival.then(node => runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
1371
+ }
1372
+ return boundaryComponent(host, id)(props);
1373
+ }
1374
+ function adoptBoundary(host, id, el, props) {
1328
1375
  claimedBoundaries.add(id);
1329
1376
  const hy = globalThis._$HY;
1330
1377
  if (hy && hy.r) {
@@ -1376,6 +1423,7 @@ function installServerComponents(host = getFrameHost()) {
1376
1423
  };
1377
1424
  }
1378
1425
  g._$SC.impl = (id, props) => documentBoundary(host, id, props);
1426
+ installRevealHook();
1379
1427
  configureServerFunctionsClient({
1380
1428
  responseHandler: createServerComponentHandler({
1381
1429
  host,
@@ -1,4 +1,4 @@
1
- import { getOwner, runWithOwner, onCleanup, createLoadingBoundary, sharedConfig, createOwner } from 'solid-js';
1
+ import { getOwner, onCleanup, createMemo, runWithOwner, createLoadingBoundary, sharedConfig, createOwner } from 'solid-js';
2
2
  import { insert } from '@solidjs/web';
3
3
  import { configureServerFunctionsClient } from '@solidjs/web/server-functions/client';
4
4
  import { fromCrossJSON, Feature } from 'seroval';
@@ -112,7 +112,7 @@ function createFrameHost(options = {}) {
112
112
  pending.delete(id);
113
113
  const records = {};
114
114
  let version;
115
- for (const chunk of buffered) {
115
+ for (const chunk of buffered.chunks) {
116
116
  if (chunk.type === "data") {
117
117
  options.applyData && options.applyData(chunk);
118
118
  continue;
@@ -144,12 +144,20 @@ function createFrameHost(options = {}) {
144
144
  for (const frame of set) deliver(frame, chunk);
145
145
  return;
146
146
  }
147
- const buffered = pending.get(chunk.id) ?? [];
148
- const maxVersion = buffered.reduce((m, c) => Math.max(m, c.version), chunk.version);
149
- if (chunk.version < maxVersion) return;
150
- const kept = buffered.filter(c => c.version >= chunk.version);
151
- kept.push(chunk);
152
- pending.set(chunk.id, kept);
147
+ const buffered = pending.get(chunk.id);
148
+ if (!buffered) {
149
+ pending.set(chunk.id, {
150
+ version: chunk.version,
151
+ chunks: [chunk]
152
+ });
153
+ return;
154
+ }
155
+ if (chunk.version < buffered.version) return;
156
+ if (chunk.version > buffered.version) {
157
+ buffered.version = chunk.version;
158
+ buffered.chunks.length = 0;
159
+ }
160
+ buffered.chunks.push(chunk);
153
161
  },
154
162
  get(id) {
155
163
  const set = frames.get(id);
@@ -208,7 +216,7 @@ class FrameImpl {
208
216
  if (options.host && options.id !== undefined) {
209
217
  options.host.register(options.id, this);
210
218
  }
211
- if (options.adopt) this.#syncSlots();
219
+ if (options.adopt && this.#version === undefined) this.#syncSlots();
212
220
  }
213
221
  #parent() {
214
222
  return this.#element ?? this.#start.parentNode;
@@ -352,7 +360,7 @@ class FrameImpl {
352
360
  if (nodes) this.#replaceRange(occurrence, start, nodes);
353
361
  this.#slotNodes.set(occurrence, nodes);
354
362
  this.#mountedSlots.add(occurrence);
355
- this.#discoverRegions(occurrence, start);
363
+ if (!this.#options.adopt || nodes) this.#discoverRegions(occurrence, start);
356
364
  this.#bindRegions(occurrence);
357
365
  } else if (record !== this.#slotArgs.get(occurrence)) {
358
366
  if (this.#refArgsUnchanged(occurrence, record)) {
@@ -1224,15 +1232,18 @@ function normalizeSlotContent(value) {
1224
1232
  if (value == null || typeof value === "boolean") return document.createTextNode("");
1225
1233
  return value instanceof Node ? value : document.createTextNode(String(value));
1226
1234
  }
1235
+ function gatherClaims(el, registry) {
1236
+ if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
1237
+ if (el.hasAttribute(FRAME_ID_ATTR)) return;
1238
+ for (let c = el.firstElementChild; c; c = c.nextElementSibling) gatherClaims(c, registry);
1239
+ }
1227
1240
  function claimRender(prefix, existing, render) {
1228
1241
  const sc = sharedConfig;
1229
1242
  if (!sc.getNextContextId) return render();
1230
1243
  const registry = new Map();
1231
1244
  for (const n of existing) {
1232
- const el = n;
1233
- if (el.nodeType !== 1) continue;
1234
- if (el.hasAttribute("_hk")) registry.set(el.getAttribute("_hk"), el);
1235
- el.querySelectorAll("*[_hk]").forEach(child => registry.set(child.getAttribute("_hk"), child));
1245
+ if (n.nodeType !== 1) continue;
1246
+ gatherClaims(n, registry);
1236
1247
  }
1237
1248
  if (!registry.size) return render();
1238
1249
  const prevRegistry = sc.registry;
@@ -1296,21 +1307,57 @@ function boundaryComponent(host, id) {
1296
1307
  }
1297
1308
  const claimedBoundaries = new Set();
1298
1309
  let boundaryIndex = null;
1310
+ const isBoundaryId = id => !id.includes(".");
1311
+ function indexBoundaries(root) {
1312
+ root.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
1313
+ const key = el.getAttribute(FRAME_ID_ATTR);
1314
+ if (key && isBoundaryId(key) && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
1315
+ });
1316
+ }
1299
1317
  function findBoundaryElement(id) {
1300
1318
  if (!boundaryIndex) {
1301
1319
  boundaryIndex = new Map();
1302
- if (typeof document !== "undefined" && document.body) {
1303
- document.body.querySelectorAll(`[${FRAME_ID_ATTR}]`).forEach(el => {
1304
- const key = el.getAttribute(FRAME_ID_ATTR);
1305
- if (key && !boundaryIndex.has(key)) boundaryIndex.set(key, el);
1306
- });
1307
- }
1320
+ if (typeof document !== "undefined" && document.body) indexBoundaries(document.body);
1308
1321
  }
1309
1322
  return boundaryIndex.get(id);
1310
1323
  }
1324
+ const boundaryWaiters = new Map();
1325
+ function documentStreaming() {
1326
+ const hy = globalThis._$HY;
1327
+ return !!hy && !hy.done;
1328
+ }
1329
+ function installRevealHook() {
1330
+ const hy = globalThis._$HY;
1331
+ if (!hy || hy.$sc) return;
1332
+ hy.$sc = true;
1333
+ const prev = hy.fe;
1334
+ hy.fe = (fragmentId, parent) => {
1335
+ if (prev) prev(fragmentId, parent);
1336
+ if (!boundaryIndex) return;
1337
+ const root = parent || (typeof document !== "undefined" ? document.body : null);
1338
+ if (!root) return;
1339
+ indexBoundaries(root);
1340
+ for (const [id, notify] of boundaryWaiters) {
1341
+ const el = boundaryIndex.get(id);
1342
+ if (!el) continue;
1343
+ boundaryWaiters.delete(id);
1344
+ notify(el);
1345
+ }
1346
+ };
1347
+ }
1311
1348
  function documentBoundary(host, id, props) {
1312
- const el = !claimedBoundaries.has(id) ? findBoundaryElement(id) : undefined;
1313
- if (!el) return boundaryComponent(host, id)(props);
1349
+ const claimed = claimedBoundaries.has(id);
1350
+ const el = !claimed ? findBoundaryElement(id) : undefined;
1351
+ if (el) return adoptBoundary(host, id, el, props);
1352
+ if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
1353
+ const owner = getOwner();
1354
+ const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
1355
+ onCleanup(() => boundaryWaiters.delete(id));
1356
+ return createMemo(() => arrival.then(node => runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
1357
+ }
1358
+ return boundaryComponent(host, id)(props);
1359
+ }
1360
+ function adoptBoundary(host, id, el, props) {
1314
1361
  claimedBoundaries.add(id);
1315
1362
  const hy = globalThis._$HY;
1316
1363
  if (hy && hy.r) {
@@ -1362,6 +1409,7 @@ function installServerComponents(host = getFrameHost()) {
1362
1409
  };
1363
1410
  }
1364
1411
  g._$SC.impl = (id, props) => documentBoundary(host, id, props);
1412
+ installRevealHook();
1365
1413
  configureServerFunctionsClient({
1366
1414
  responseHandler: createServerComponentHandler({
1367
1415
  host,