Sign In

@solidjs/web

Package Overview
Dependencies
Maintainers
2
Versions
53
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@solidjs/web - npm Package Compare versions

Comparing version
2.0.0-beta.30
to
2.0.0-beta.31
+53
-40
dist/dev.js

@@ -1,2 +0,2 @@

import { createRenderEffect, createMemo, sharedConfig, untrack, runWithOwner, flatten, createRoot, merge, createComponent, omit, createOwner, createSignal, onSettled, $DEVCOMP, enableHydration, enforceLoadingBoundary, flush, getOwner, createEffect } from 'solid-js';
import { createRenderEffect, createMemo, sharedConfig, untrack, runWithOwner, flatten, createRoot, merge, createComponent, omit, createOwner, createSignal, $DEVCOMP, onCleanup, enableHydration, enforceLoadingBoundary, flush, getOwner, createEffect } from 'solid-js';
export { Errored, For, Hydration, Loading, Match, NoHydration, Repeat, Reveal, Show, Switch, createComponent, getOwner, untrack } from 'solid-js';

@@ -174,3 +174,3 @@

const HEAD_ATTR_NAME = /^[a-zA-Z_][a-zA-Z0-9_:.-]*$/;
const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "icon", "stylesheet"]);
const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "stylesheet"]);
const RESOURCE_QUALIFIERS = ["as", "crossorigin", "type", "media", "imagesrcset", "imagesizes"];

@@ -218,8 +218,10 @@ function evalHeadValue(v) {

if (tag === "meta") {
if (props.name != null) return "meta:name:" + props.name;
if (props.property != null) return "meta:property:" + props.property;
if (props["http-equiv"] != null) return "meta:http-equiv:" + props["http-equiv"];
for (const ns of ["name", "property", "http-equiv"]) if (props[ns] != null) return "meta:" + ns + ":" + props[ns] + (props.media != null ? ":media=" + props.media : "");
return unique;
}
if (tag === "link") return "link:" + (props.rel || "") + ":" + (props.href || "");
if (tag === "link") {
const rel = props.rel || "";
if (rel === "icon" || rel === "apple-touch-icon") return "link:" + rel + (props.sizes != null ? ":sizes=" + props.sizes : "") + (props.type != null ? ":type=" + props.type : "");
return "link:" + rel + ":" + (props.href || "");
}
return unique;

@@ -842,8 +844,5 @@ }

}
function renderHeadElement(t, identity, existing) {
for (let i = 0; i < existing.length; i++) {
if (headElementMatches(existing[i], t)) return existing.splice(i, 1)[0];
}
const el = document.createElement(t.tag);
for (const name in t.props) {
function createHeadElement(tag, props) {
const el = document.createElement(tag);
for (const name in props) {
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;

@@ -854,7 +853,14 @@ if (!HEAD_ATTR_NAME.test(name)) {

}
const v = t.props[name];
const v = props[name];
if (v == null || v === false) continue;
el.setAttribute(name, v === true ? "" : String(v));
}
if (t.props.children != null) el.textContent = String(t.props.children);
if (props.children != null) el.textContent = String(props.children);
return el;
}
function renderHeadElement(t, identity, existing) {
for (let i = 0; i < existing.length; i++) {
if (headElementMatches(existing[i], t)) return existing.splice(i, 1)[0];
}
const el = createHeadElement(t.tag, t.props);
el.setAttribute("data-dh", identity);

@@ -902,14 +908,3 @@ document.head.appendChild(el);

}
if (!el) {
el = document.createElement(tag);
for (const name in props) {
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
if (!HEAD_ATTR_NAME.test(name)) continue;
const v = props[name];
if (v == null || v === false) continue;
el.setAttribute(name, v === true ? "" : String(v));
}
if (props.children != null) el.textContent = String(props.children);
document.head.appendChild(el);
}
if (!el) document.head.appendChild(createHeadElement(tag, props));
return noopFn;

@@ -919,3 +914,2 @@ }

function useHead(tags) {
const list = Array.isArray(tags) ? tags : [tags];
initHeadRegistry();

@@ -928,2 +922,4 @@ const reg = {

effect(() => {
let list = typeof tags === "function" ? tags() : tags;
if (!Array.isArray(list)) list = [list];
const replaceable = [];

@@ -1631,15 +1627,25 @@ const resources = [];

}
const COMPONENT_HANDOFF = Symbol.for("dom-expressions.component-handoff");
function resolveHandoff(next, prev) {
const handoff = typeof next === "function" && next !== null && next[COMPONENT_HANDOFF];
return handoff && handoff.take(prev) ? prev : next;
const COMPONENT_BINDING = Symbol.for("dom-expressions.component-binding");
function bindingOf(value) {
return value !== null && (typeof value === "function" || typeof value === "object") && value[COMPONENT_BINDING] || undefined;
}
function dynamic(source) {
let latest = 0;
const sites = new Set();
const resolveBinding = (next, prev) => {
const binding = bindingOf(next);
if (!binding) return next;
const prevBinding = bindingOf(prev);
if (prevBinding && prevBinding.component === binding.component) {
for (const deliver of sites) deliver(binding.address);
return prev;
}
return next;
};
const cached = createMemo(prev => {
const next = source();
if (!next || typeof next.then !== "function") return resolveHandoff(next, prev);
if (!next || typeof next.then !== "function") return resolveBinding(next, prev);
const token = ++latest;
return {
then: (onFulfilled, onRejected) => next.then(resolved => onFulfilled(token === latest ? resolveHandoff(resolved, prev) : resolved), onRejected)
then: (onFulfilled, onRejected) => next.then(resolved => onFulfilled(token === latest ? resolveBinding(resolved, prev) : resolved), onRejected)
};

@@ -1654,6 +1660,15 @@ }, {

case "function":
Object.assign(component, {
[$DEVCOMP]: true
});
return untrack(() => component(props));
{
Object.assign(component, {
[$DEVCOMP]: true
});
const binding = bindingOf(component);
if (binding) {
const [address, setAddress] = createSignal(binding.address);
sites.add(setAddress);
onCleanup(() => sites.delete(setAddress));
return untrack(() => binding.component(props, address));
}
return untrack(() => component(props));
}
case "string":

@@ -1695,5 +1710,3 @@ const el = sharedConfig.hydrating ? getNextElement() : createElement(component, untrack(() => props.is));

const gate = createMemo(() => (Comp = comp(), m = mounted(), untrack(() => Comp && m ? Comp(rest) : props.fallback)));
onSettled(() => {
setMounted(true);
});
sharedConfig.onHydrationEnd(() => setMounted(true));
return gate;

@@ -1700,0 +1713,0 @@ };

@@ -175,3 +175,3 @@ 'use strict';

const HEAD_ATTR_NAME = /^[a-zA-Z_][a-zA-Z0-9_:.-]*$/;
const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "icon", "stylesheet"]);
const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "stylesheet"]);
const RESOURCE_QUALIFIERS = ["as", "crossorigin", "type", "media", "imagesrcset", "imagesizes"];

@@ -219,8 +219,10 @@ function evalHeadValue(v) {

if (tag === "meta") {
if (props.name != null) return "meta:name:" + props.name;
if (props.property != null) return "meta:property:" + props.property;
if (props["http-equiv"] != null) return "meta:http-equiv:" + props["http-equiv"];
for (const ns of ["name", "property", "http-equiv"]) if (props[ns] != null) return "meta:" + ns + ":" + props[ns] + (props.media != null ? ":media=" + props.media : "");
return unique;
}
if (tag === "link") return "link:" + (props.rel || "") + ":" + (props.href || "");
if (tag === "link") {
const rel = props.rel || "";
if (rel === "icon" || rel === "apple-touch-icon") return "link:" + rel + (props.sizes != null ? ":sizes=" + props.sizes : "") + (props.type != null ? ":type=" + props.type : "");
return "link:" + rel + ":" + (props.href || "");
}
return unique;

@@ -836,8 +838,5 @@ }

}
function renderHeadElement(t, identity, existing) {
for (let i = 0; i < existing.length; i++) {
if (headElementMatches(existing[i], t)) return existing.splice(i, 1)[0];
}
const el = document.createElement(t.tag);
for (const name in t.props) {
function createHeadElement(tag, props) {
const el = document.createElement(tag);
for (const name in props) {
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;

@@ -847,7 +846,14 @@ if (!HEAD_ATTR_NAME.test(name)) {

}
const v = t.props[name];
const v = props[name];
if (v == null || v === false) continue;
el.setAttribute(name, v === true ? "" : String(v));
}
if (t.props.children != null) el.textContent = String(t.props.children);
if (props.children != null) el.textContent = String(props.children);
return el;
}
function renderHeadElement(t, identity, existing) {
for (let i = 0; i < existing.length; i++) {
if (headElementMatches(existing[i], t)) return existing.splice(i, 1)[0];
}
const el = createHeadElement(t.tag, t.props);
el.setAttribute("data-dh", identity);

@@ -895,14 +901,3 @@ document.head.appendChild(el);

}
if (!el) {
el = document.createElement(tag);
for (const name in props) {
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
if (!HEAD_ATTR_NAME.test(name)) continue;
const v = props[name];
if (v == null || v === false) continue;
el.setAttribute(name, v === true ? "" : String(v));
}
if (props.children != null) el.textContent = String(props.children);
document.head.appendChild(el);
}
if (!el) document.head.appendChild(createHeadElement(tag, props));
return noopFn;

@@ -912,3 +907,2 @@ }

function useHead(tags) {
const list = Array.isArray(tags) ? tags : [tags];
initHeadRegistry();

@@ -921,2 +915,4 @@ const reg = {

effect(() => {
let list = typeof tags === "function" ? tags() : tags;
if (!Array.isArray(list)) list = [list];
const replaceable = [];

@@ -1569,15 +1565,25 @@ const resources = [];

}
const COMPONENT_HANDOFF = Symbol.for("dom-expressions.component-handoff");
function resolveHandoff(next, prev) {
const handoff = typeof next === "function" && next !== null && next[COMPONENT_HANDOFF];
return handoff && handoff.take(prev) ? prev : next;
const COMPONENT_BINDING = Symbol.for("dom-expressions.component-binding");
function bindingOf(value) {
return value !== null && (typeof value === "function" || typeof value === "object") && value[COMPONENT_BINDING] || undefined;
}
function dynamic(source) {
let latest = 0;
const sites = new Set();
const resolveBinding = (next, prev) => {
const binding = bindingOf(next);
if (!binding) return next;
const prevBinding = bindingOf(prev);
if (prevBinding && prevBinding.component === binding.component) {
for (const deliver of sites) deliver(binding.address);
return prev;
}
return next;
};
const cached = solidJs.createMemo(prev => {
const next = source();
if (!next || typeof next.then !== "function") return resolveHandoff(next, prev);
if (!next || typeof next.then !== "function") return resolveBinding(next, prev);
const token = ++latest;
return {
then: (onFulfilled, onRejected) => next.then(resolved => onFulfilled(token === latest ? resolveHandoff(resolved, prev) : resolved), onRejected)
then: (onFulfilled, onRejected) => next.then(resolved => onFulfilled(token === latest ? resolveBinding(resolved, prev) : resolved), onRejected)
};

@@ -1592,3 +1598,12 @@ }, {

case "function":
return solidJs.untrack(() => component(props));
{
const binding = bindingOf(component);
if (binding) {
const [address, setAddress] = solidJs.createSignal(binding.address);
sites.add(setAddress);
solidJs.onCleanup(() => sites.delete(setAddress));
return solidJs.untrack(() => binding.component(props, address));
}
return solidJs.untrack(() => component(props));
}
case "string":

@@ -1630,5 +1645,3 @@ const el = solidJs.sharedConfig.hydrating ? getNextElement() : createElement(component, solidJs.untrack(() => props.is));

const gate = solidJs.createMemo(() => (Comp = comp(), m = mounted(), solidJs.untrack(() => Comp && m ? Comp(rest) : props.fallback)));
solidJs.onSettled(() => {
setMounted(true);
});
solidJs.sharedConfig.onHydrationEnd(() => setMounted(true));
return gate;

@@ -1635,0 +1648,0 @@ };

@@ -1,2 +0,2 @@

import { createRenderEffect, createMemo, sharedConfig, untrack, runWithOwner, flatten, createRoot, merge, createComponent, omit, createOwner, createSignal, onSettled, enableHydration, flush, getOwner, createEffect } from 'solid-js';
import { createRenderEffect, createMemo, sharedConfig, untrack, runWithOwner, flatten, createRoot, merge, createComponent, omit, createOwner, createSignal, onCleanup, enableHydration, flush, getOwner, createEffect } from 'solid-js';
export { Errored, For, Hydration, Loading, Match, NoHydration, Repeat, Reveal, Show, Switch, createComponent, getOwner, untrack } from 'solid-js';

@@ -174,3 +174,3 @@

const HEAD_ATTR_NAME = /^[a-zA-Z_][a-zA-Z0-9_:.-]*$/;
const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "icon", "stylesheet"]);
const RESOURCE_LINK_RELS = new Set(["preload", "modulepreload", "prefetch", "preconnect", "dns-prefetch", "stylesheet"]);
const RESOURCE_QUALIFIERS = ["as", "crossorigin", "type", "media", "imagesrcset", "imagesizes"];

@@ -218,8 +218,10 @@ function evalHeadValue(v) {

if (tag === "meta") {
if (props.name != null) return "meta:name:" + props.name;
if (props.property != null) return "meta:property:" + props.property;
if (props["http-equiv"] != null) return "meta:http-equiv:" + props["http-equiv"];
for (const ns of ["name", "property", "http-equiv"]) if (props[ns] != null) return "meta:" + ns + ":" + props[ns] + (props.media != null ? ":media=" + props.media : "");
return unique;
}
if (tag === "link") return "link:" + (props.rel || "") + ":" + (props.href || "");
if (tag === "link") {
const rel = props.rel || "";
if (rel === "icon" || rel === "apple-touch-icon") return "link:" + rel + (props.sizes != null ? ":sizes=" + props.sizes : "") + (props.type != null ? ":type=" + props.type : "");
return "link:" + rel + ":" + (props.href || "");
}
return unique;

@@ -835,8 +837,5 @@ }

}
function renderHeadElement(t, identity, existing) {
for (let i = 0; i < existing.length; i++) {
if (headElementMatches(existing[i], t)) return existing.splice(i, 1)[0];
}
const el = document.createElement(t.tag);
for (const name in t.props) {
function createHeadElement(tag, props) {
const el = document.createElement(tag);
for (const name in props) {
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;

@@ -846,7 +845,14 @@ if (!HEAD_ATTR_NAME.test(name)) {

}
const v = t.props[name];
const v = props[name];
if (v == null || v === false) continue;
el.setAttribute(name, v === true ? "" : String(v));
}
if (t.props.children != null) el.textContent = String(t.props.children);
if (props.children != null) el.textContent = String(props.children);
return el;
}
function renderHeadElement(t, identity, existing) {
for (let i = 0; i < existing.length; i++) {
if (headElementMatches(existing[i], t)) return existing.splice(i, 1)[0];
}
const el = createHeadElement(t.tag, t.props);
el.setAttribute("data-dh", identity);

@@ -894,14 +900,3 @@ document.head.appendChild(el);

}
if (!el) {
el = document.createElement(tag);
for (const name in props) {
if (name === "children" || name === "ref" || name.slice(0, 2) === "on") continue;
if (!HEAD_ATTR_NAME.test(name)) continue;
const v = props[name];
if (v == null || v === false) continue;
el.setAttribute(name, v === true ? "" : String(v));
}
if (props.children != null) el.textContent = String(props.children);
document.head.appendChild(el);
}
if (!el) document.head.appendChild(createHeadElement(tag, props));
return noopFn;

@@ -911,3 +906,2 @@ }

function useHead(tags) {
const list = Array.isArray(tags) ? tags : [tags];
initHeadRegistry();

@@ -920,2 +914,4 @@ const reg = {

effect(() => {
let list = typeof tags === "function" ? tags() : tags;
if (!Array.isArray(list)) list = [list];
const replaceable = [];

@@ -1568,15 +1564,25 @@ const resources = [];

}
const COMPONENT_HANDOFF = Symbol.for("dom-expressions.component-handoff");
function resolveHandoff(next, prev) {
const handoff = typeof next === "function" && next !== null && next[COMPONENT_HANDOFF];
return handoff && handoff.take(prev) ? prev : next;
const COMPONENT_BINDING = Symbol.for("dom-expressions.component-binding");
function bindingOf(value) {
return value !== null && (typeof value === "function" || typeof value === "object") && value[COMPONENT_BINDING] || undefined;
}
function dynamic(source) {
let latest = 0;
const sites = new Set();
const resolveBinding = (next, prev) => {
const binding = bindingOf(next);
if (!binding) return next;
const prevBinding = bindingOf(prev);
if (prevBinding && prevBinding.component === binding.component) {
for (const deliver of sites) deliver(binding.address);
return prev;
}
return next;
};
const cached = createMemo(prev => {
const next = source();
if (!next || typeof next.then !== "function") return resolveHandoff(next, prev);
if (!next || typeof next.then !== "function") return resolveBinding(next, prev);
const token = ++latest;
return {
then: (onFulfilled, onRejected) => next.then(resolved => onFulfilled(token === latest ? resolveHandoff(resolved, prev) : resolved), onRejected)
then: (onFulfilled, onRejected) => next.then(resolved => onFulfilled(token === latest ? resolveBinding(resolved, prev) : resolved), onRejected)
};

@@ -1591,3 +1597,12 @@ }, {

case "function":
return untrack(() => component(props));
{
const binding = bindingOf(component);
if (binding) {
const [address, setAddress] = createSignal(binding.address);
sites.add(setAddress);
onCleanup(() => sites.delete(setAddress));
return untrack(() => binding.component(props, address));
}
return untrack(() => component(props));
}
case "string":

@@ -1629,5 +1644,3 @@ const el = sharedConfig.hydrating ? getNextElement() : createElement(component, untrack(() => props.is));

const gate = createMemo(() => (Comp = comp(), m = mounted(), untrack(() => Comp && m ? Comp(rest) : props.fallback)));
onSettled(() => {
setMounted(true);
});
sharedConfig.onHydrationEnd(() => setMounted(true));
return gate;

@@ -1634,0 +1647,0 @@ };

@@ -86,14 +86,22 @@ 'use strict';

const frames = new Map();
const pending = new Map();
const retained = new Map();
const deliver = (frame, chunk) => {
if (chunk.type === "data") {
options.applyData && options.applyData(chunk);
return;
}
frame.apply({
version: chunk.version,
r: chunkToRecords(chunk)
const stores = new Map();
const storeFor = id => {
let store = stores.get(id);
if (!store) stores.set(id, store = {
version: undefined,
records: {}
});
return store;
};
const write = (store, version, records) => {
if (store.version !== undefined && version < store.version) return false;
if (store.version === undefined || version > store.version) {
store.version = version;
for (const key of Object.keys(store.records)) {
if (key.startsWith("seg:") || key === ":error") delete store.records[key];
}
}
Object.assign(store.records, records);
return true;
};
return {

@@ -103,39 +111,11 @@ register(id, frame) {

if (!set) frames.set(id, set = new Set());
const sibling = set.size ? set.values().next().value : undefined;
set.add(frame);
if (sibling) {
const store = stores.get(id);
if (store && store.version !== undefined) {
frame.apply({
version: sibling.version ?? 0,
r: sibling.store
version: store.version,
r: store.records
});
if (sibling.version === undefined) frame.rebase && frame.rebase();
return;
}
const kept = retained.get(id);
if (kept) {
retained.delete(id);
frame.apply({
version: kept.version,
r: kept.records
});
frame.rebase && frame.rebase();
}
const buffered = pending.get(id);
if (buffered) {
pending.delete(id);
const records = {};
let version;
for (const chunk of buffered.chunks) {
if (chunk.type === "data") {
options.applyData && options.applyData(chunk);
continue;
}
version = chunk.version;
Object.assign(records, chunkToRecords(chunk));
}
if (version !== undefined) frame.apply({
version,
r: records
});
}
},

@@ -146,11 +126,18 @@ unregister(id, frame) {

if (!set || !frame || !set.size) {
if (frame) {
const kept = frame.snapshot && frame.snapshot();
if (kept) retained.set(id, kept);
} else {
retained.delete(id);
frames.delete(id);
if (frame && frame.contentHTML) {
const store = storeFor(id);
if (!store.records[""]) {
const html = frame.contentHTML();
if (html != null) {
store.records[""] = {
kind: "html",
value: html
};
if (store.version === undefined) store.version = 0;
}
}
}
frames.delete(id);
pending.delete(id);
}
if (!frame) stores.delete(id);
},

@@ -162,21 +149,11 @@ apply(chunk) {

}
const records = chunkToRecords(chunk);
if (!write(storeFor(chunk.id), chunk.version, records)) return;
const set = frames.get(chunk.id);
if (set && set.size) {
for (const frame of set) deliver(frame, chunk);
return;
}
const buffered = pending.get(chunk.id);
if (!buffered) {
pending.set(chunk.id, {
if (set) {
for (const frame of set) frame.apply({
version: chunk.version,
chunks: [chunk]
r: records
});
return;
}
if (chunk.version < buffered.version) return;
if (chunk.version > buffered.version) {
buffered.version = chunk.version;
buffered.chunks.length = 0;
}
buffered.chunks.push(chunk);
},

@@ -217,2 +194,3 @@ get(id) {

#processedAssets = new Set();
#recordRefresh = null;
#disposed = false;

@@ -363,3 +341,5 @@ #styleFlush = () => {

const key = `slot:${occurrence}`;
if (key in this.#store) delete this.#store[key];else this.#options.removeSlotRecord?.(occurrence);
if (key in this.#store) {
if (!this.#mountedSlots.has(occurrence)) delete this.#store[key];
} else this.#options.removeSlotRecord?.(occurrence);
}

@@ -382,2 +362,11 @@ #syncSlots(root) {

if (!this.#mountedSlots.has(occurrence)) {
if (record === undefined && !root && this.#options.adopt && this.#options.recordsPending?.()) {
this.#recordRefresh ??= setTimeout(() => {
this.#recordRefresh = null;
if (this.#disposed) return;
this.#options.drainRecords?.();
this.#syncSlots();
});
continue;
}
if (this.#options.adopt) this.#discoverRegions(occurrence, start);

@@ -399,8 +388,2 @@ const nodes = this.#invokeSlot(occurrence, callback, record, start, this.#options.adopt);

const props = this.#resolveArgs(occurrence, record.args);
const regions = this.#slotRegions.get(occurrence);
if (regions) {
for (const [argKey, entry] of regions) {
if (!(argKey in props)) props[argKey] = entry.element;
}
}
this.#slotArgs.set(occurrence, record);

@@ -451,8 +434,2 @@ update(props);

const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
const regions = this.#slotRegions.get(occurrence);
if (regions) {
for (const [argKey, entry] of regions) {
if (!(argKey in props)) props[argKey] = entry.element;
}
}
const scope = this.#options.ownerScope;

@@ -542,6 +519,5 @@ const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);

const endData = slotEnd(slotKey);
const prefix = `${this.#options.id}.`;
let n = start.nextSibling;
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
collectRegionElements(n, regions, prefix);
collectRegionElements(n, regions);
n = n.nextSibling;

@@ -558,12 +534,3 @@ }

const kb = Object.keys(b);
if (kb.length < ka.length) return false;
if (kb.length !== ka.length) {
const regions = this.#slotRegions.get(occurrence);
for (const key of kb) {
if (key in a) continue;
const vb = b[key];
if (!vb || typeof vb !== "object" || typeof vb.$frame !== "string") return false;
if (!regions || !regions.has(key)) return false;
}
}
if (kb.length !== ka.length) return false;
const cache = this.#slotResolvedRefs.get(occurrence);

@@ -625,18 +592,5 @@ for (const key of ka) {

}
snapshot() {
if (this.#disposed) return null;
const records = {
...this.#store
};
if (!records[""] && this.#element && this.#hasContent) {
records[""] = {
kind: "html",
value: this.#element.innerHTML
};
}
if (!records[""] && this.#version === undefined) return null;
return {
version: this.#version ?? 0,
records
};
contentHTML() {
if (this.#disposed || !this.#element || !this.#hasContent) return null;
return this.#element.innerHTML;
}

@@ -676,2 +630,6 @@ rebind(id) {

this.#disposed = true;
if (this.#recordRefresh) {
clearTimeout(this.#recordRefresh);
this.#recordRefresh = null;
}
for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);

@@ -699,4 +657,5 @@ for (const key of this.#mountedSlots) this.#removeSlotRecord(key);

this.#collectSlots(ranges);
reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges);
if (ranges.size) restoreDisplacedRanges(this.#firstContent(), this.#end, ranges);
const grafts = [];
reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges, grafts);
if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
}

@@ -920,7 +879,7 @@ }

}
function collectRegionElements(node, regions, prefix) {
function collectRegionElements(node, regions) {
if (node.nodeType !== ELEMENT_NODE) return;
if (isFrameElement(node)) {
const childId = node.getAttribute(FRAME_ID_ATTR);
if (childId && childId.startsWith(prefix)) {
if (childId && childId.includes(".")) {
const argKey = childId.slice(childId.lastIndexOf(".") + 1);

@@ -938,3 +897,3 @@ if (!regions.has(argKey)) {

}
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions, prefix);
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions);
}

@@ -1007,7 +966,7 @@ function renameRegion(entry, childId) {

}
function morphNode(oldNode, newNode, claim, ranges) {
function morphNode(oldNode, newNode, claim, ranges, grafts) {
if (oldNode.nodeType === ELEMENT_NODE) {
if (oldNode.hasAttribute("data-preserve")) return;
morphAttributes(oldNode, newNode, claim);
reconcileChildren(oldNode, newNode, null, null, claim, ranges);
reconcileChildren(oldNode, newNode, null, null, claim, ranges, grafts);
} else if (oldNode.data !== newNode.data) {

@@ -1046,2 +1005,9 @@ oldNode.data = newNode.data;

}
function placeRange(parent, range, id, ref) {
if (range.nodeType === 11 ) {
parent.insertBefore(range, ref);
} else {
moveRangeBefore(parent, range, id, ref);
}
}
function adoptRange(parent, start, id, ref, claim) {

@@ -1064,3 +1030,3 @@ const end = slotEnd(id);

}
function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null) {
function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null, grafts = null) {
let oldChild = boundStart ? boundStart.nextSibling : parent.firstChild;

@@ -1081,7 +1047,3 @@ let newChild = source.firstChild;

if (ranges) ranges.delete(pid);
if (existing.nodeType === 11 ) {
parent.insertBefore(existing, old ?? boundEnd);
} else {
moveRangeBefore(parent, existing, pid, old ?? boundEnd);
}
placeRange(parent, existing, pid, old ?? boundEnd);
newChild = afterRange(newChild, pid);

@@ -1097,2 +1059,3 @@ } else {

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1104,2 +1067,3 @@ continue;

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1109,3 +1073,3 @@ continue;

if (compatible(old, newChild)) {
morphNode(old, newChild, claim, ranges);
morphNode(old, newChild, claim, ranges, grafts);
oldChild = old.nextSibling;

@@ -1123,3 +1087,3 @@ newChild = nextNew;

parent.insertBefore(ahead, old);
morphNode(ahead, newChild, claim, ranges);
morphNode(ahead, newChild, claim, ranges, grafts);
newChild = nextNew;

@@ -1131,2 +1095,3 @@ continue;

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1148,16 +1113,20 @@ }

}
function restoreDisplacedRanges(first, end, ranges) {
const found = new Map();
collectSlots(first, end, found);
for (const [id, start] of found) {
const displaced = ranges.get(id);
if (!displaced || displaced === start) continue;
ranges.delete(id);
const parent = start.parentNode;
if (displaced.nodeType === 11 ) {
parent.insertBefore(displaced, start);
} else {
moveRangeBefore(parent, displaced, id, start);
function flushGrafts(node, ranges) {
if (node.nodeType !== ELEMENT_NODE || isFrameElement(node)) return;
let n = node.firstChild;
while (n) {
const id = slotStartId(n);
if (id !== null) {
const next = afterRange(n, id);
const displaced = ranges.get(id);
if (displaced) {
ranges.delete(id);
placeRange(node, displaced, id, n);
stashRange(document.createDocumentFragment(), n, id);
}
n = next;
continue;
}
stashRange(document.createDocumentFragment(), start, id);
flushGrafts(n, ranges);
n = n.nextSibling;
}

@@ -1194,3 +1163,3 @@ }

} else {
if (as !== undefined && chunk.id === rootId) chunk.id = as;else if (options.route) chunk.id = options.route(chunk.id);
if (as !== undefined && chunk.id === rootId) chunk.id = as;
if (perFrame) {

@@ -1209,3 +1178,3 @@ let v = perFrame.get(chunk.id);

const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
const COMPONENT_HANDOFF = /*#__PURE__*/Symbol.for("dom-expressions.component-handoff");
const COMPONENT_BINDING = /*#__PURE__*/Symbol.for("dom-expressions.component-binding");
let resolveServerComponent;

@@ -1234,3 +1203,4 @@ function parseServerComponent(value, ctx) {

serialize(node, ctx) {
return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
const registry = "self._$SC";
return registry + ".r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
},

@@ -1260,3 +1230,2 @@ deserialize(node, ctx) {

onStream,
documentComponent,
intercept,

@@ -1266,50 +1235,27 @@ consumer = client.getFlightDataConsumer,

}) {
const byAddress = new Map();
const forwards = new Map();
const brand = (comp, fnId, frameId) => {
const brandable = typeof comp === "function" || typeof comp === "object" && comp !== null;
if (brandable && !comp[COMPONENT_HANDOFF]) {
comp[COMPONENT_HANDOFF] = {
fnId,
frameId,
take(prev) {
const meta = prev !== null && (typeof prev === "function" || typeof prev === "object") && prev[COMPONENT_HANDOFF];
if (!meta || meta.fnId !== fnId) return false;
const root = meta.frameId;
let cur = forwards.get(root) ?? root;
if (cur !== root && !host.get(cur)) {
forwards.delete(root);
cur = root;
}
if (cur === frameId) return true;
let frame = host.get(cur);
if (!frame) return false;
while (frame) {
frame.rebind(frameId);
frame = host.get(cur);
}
if (frameId === root) forwards.delete(root);else forwards.set(root, frameId);
return true;
}
};
}
const byFn = new Map();
const componentFor = fnId => {
let comp = byFn.get(fnId);
if (comp === undefined) byFn.set(fnId, comp = component(fnId));
return comp;
};
const boundaryFor = (address, fnId) => {
let entry = byAddress.get(address);
if (!entry) {
entry = {
frameId: address,
component: brand(component(address), fnId, address)
const byAddress = new Map();
const bindingFor = (address, fnId) => {
let binding = byAddress.get(address);
if (!binding) {
const comp = componentFor(fnId);
binding = props => comp(props, () => address);
binding[COMPONENT_BINDING] = {
component: comp,
address
};
byAddress.set(address, entry);
byAddress.set(address, binding);
}
return entry;
return binding;
};
const resolveAddress = (id, address) => boundaryFor(address, id).component;
resolveServerComponent = resolveAddress;
resolveServerComponent = (id, address) => bindingFor(address, id);
const versions = new Map();
const bump = frameId => {
const version = (versions.get(frameId) || 0) + 1;
versions.set(frameId, version);
const bump = address => {
const version = (versions.get(address) || 0) + 1;
versions.set(address, version);
return version;

@@ -1320,10 +1266,4 @@ };

const hit = intercept(info);
if (hit !== undefined) {
const address = client.frameAddress(info.id, info.args);
byAddress.set(address, {
frameId: info.id,
component: brand(hit, info.id, info.id)
});
}
return hit;
if (hit === undefined) return undefined;
return bindingFor(client.frameAddress(info.id, info.args), info.id);
}),

@@ -1333,26 +1273,14 @@ handle(response, ctx) {

const address = client.frameAddress(ctx.id, ctx.args);
let entry = byAddress.get(address);
if (!entry) {
const adopted = documentComponent && documentComponent(ctx.id);
if (adopted) {
entry = {
frameId: ctx.id,
component: brand(adopted, ctx.id, ctx.id)
};
byAddress.set(address, entry);
} else {
entry = boundaryFor(address, ctx.id);
}
}
const binding = bindingFor(address, ctx.id);
if (response.headers.has(client.SINGLE_FLIGHT_HEADER)) {
return applyFlightResponse(response, entry);
return applyFlightResponse(response, address, binding);
}
const version = bump(entry.frameId);
if (onStream) onStream(entry.frameId, version, response);
const version = bump(address);
if (onStream) onStream(address, version, response);
applyFrameResponse(response, host, {
as: entry.frameId,
as: address,
version
}).catch(err => host.apply({
type: "error",
id: entry.frameId,
id: address,
version,

@@ -1363,17 +1291,18 @@ error: {

}));
return entry.component;
return binding;
},
showing(address, functionId, component) {
if (!byAddress.has(address)) {
byAddress.set(address, {
frameId: functionId,
component: brand(component, functionId, functionId),
showing(address, functionId) {
bindingFor(address, functionId);
const comp = componentFor(functionId);
if ((typeof comp === "function" || typeof comp === "object" && comp !== null) && !comp[COMPONENT_BINDING]) {
comp[COMPONENT_BINDING] = {
component: comp,
address
});
};
}
}
};
async function applyFlightResponse(response, entry) {
async function applyFlightResponse(response, address, binding) {
const rootId = response.headers.get(FRAME_STREAM_HEADER) ?? "";
const as = rootId ? entry.frameId : undefined;
const as = rootId ? address : undefined;
let feed;

@@ -1389,6 +1318,2 @@ const source = new ReadableStream({

as,
route: id => {
const local = byAddress.get(id);
return local ? local.frameId : id;
},
version: frameId => {

@@ -1414,3 +1339,3 @@ const version = bump(frameId);

}
return rootId ? entry.component : envelope.value;
return rootId ? binding : envelope.value;
}

@@ -1594,11 +1519,3 @@ }

if (ctx && ctx.range) {
let claim = adopted;
const source = value;
const accessor = () => {
if (claim) {
claim = false;
return claimRender(prefix, ctx.existing, () => typeof source === "function" ? source() : source);
}
return typeof source === "function" ? source() : source;
};
const owner = solidJs.createOwner();

@@ -1611,3 +1528,4 @@ bindings.set(key, owner);

const end = ctx.range.end;
solidJs.runWithOwner(owner, () => web$1.insert(end.parentNode, accessor, end, [...ctx.existing]));
const bind = () => web$1.insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
solidJs.runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
return undefined;

@@ -1626,11 +1544,15 @@ }

}
function boundaryComponent(host, id) {
return props => {
function followBinding(frame, binding) {
solidJs.createRenderEffect(binding, address => frame.rebind(address));
}
function boundaryComponent(host, fnId) {
return (props, binding) => {
const owner = solidJs.getOwner();
const {
element,
frame,
dispose
} = createFrameElement({
host,
id,
id: binding ? binding() : fnId,
slots: slotsFor(props),

@@ -1640,2 +1562,3 @@ ownerScope: boundaryScope(owner),

});
if (binding) followBinding(frame, binding);
solidJs.onCleanup(dispose);

@@ -1662,47 +1585,61 @@ return element;

const boundaryWaiters = new Map();
function documentStreaming() {
function boundaryMayArrive() {
const hy = globalThis._$HY;
return !!hy && !hy.done;
if (!hy) return false;
return !hy.done || !!(hy.fr && hy.fr.pending());
}
function installRevealHook() {
const hy = globalThis._$HY;
if (!hy || hy.$sc) return;
if (!hy || hy.$sc || !hy.fr) return;
hy.$sc = true;
const prev = hy.fe;
hy.fe = (fragmentId, parent) => {
if (prev) prev(fragmentId, parent);
hy.fr.subscribe((_id, parent) => {
if (!boundaryIndex) return;
const root = parent || (typeof document !== "undefined" ? document.body : null);
if (!root) return;
indexBoundaries(root);
if (root) indexBoundaries(root);
if (!boundaryWaiters.size) return;
const exhausted = hy.done && !hy.fr.pending();
for (const [id, notify] of boundaryWaiters) {
const el = boundaryIndex.get(id);
if (!el) continue;
const el = boundaryIndex && boundaryIndex.get(id);
if (!el && !exhausted) continue;
boundaryWaiters.delete(id);
notify(el);
}
};
});
}
function documentBoundary(host, id, props) {
function documentBoundary(host, id, props, binding) {
installRevealHook();
const claimed = claimedBoundaries.has(id);
const el = !claimed ? findBoundaryElement(id) : undefined;
if (el) return adoptBoundary(host, id, el, props);
if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
if (el) return adoptBoundary(host, id, el, props, binding);
if (!claimed && !boundaryWaiters.has(id) && boundaryMayArrive()) {
const owner = solidJs.getOwner();
const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
solidJs.onCleanup(() => boundaryWaiters.delete(id));
return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () =>
node ? adoptBoundary(host, id, node, props, binding) : boundaryComponent(host, id)(props, binding))));
}
return boundaryComponent(host, id)(props);
return boundaryComponent(host, id)(props, binding);
}
function adoptBoundary(host, id, el, props) {
function documentAddress(id) {
const records = globalThis._$SC?.a;
if (records) {
for (const address in records) if (records[address] === id) return address;
}
return id;
}
function adoptBoundary(host, id, el, props, binding) {
claimedBoundaries.add(id);
const hy = globalThis._$HY;
if (hy && hy.r) {
const address = binding ? binding() : documentAddress(id);
const appliedRecords = new Set();
const drainRecords = () => {
const hy = globalThis._$HY;
if (!hy || !hy.r) return;
const slotPrefix = `sc:slot:${id}:`;
for (const key of Object.keys(hy.r)) {
if (appliedRecords.has(key)) continue;
if (key.startsWith(slotPrefix)) {
appliedRecords.add(key);
host.apply({
type: "slot",
id,
id: address,
version: 0,

@@ -1715,2 +1652,3 @@ key: key.slice(slotPrefix.length),

if (childId.startsWith(id + ".")) {
appliedRecords.add(key);
const val = hy.r[key];

@@ -1727,3 +1665,4 @@ const apply = html => host.apply({

}
}
};
drainRecords();
const owner = solidJs.getOwner();

@@ -1733,7 +1672,17 @@ const frame = createFrame(el, {

host,
id,
id: address,
slots: slotsFor(props),
ownerScope: boundaryScope(owner),
reveal: revealSeam(owner)
reveal: revealSeam(owner),
...{
recordsPending: () => {
if (document.readyState === "loading") return true;
const hy = globalThis._$HY;
return !!(hy && hy.fr && hy.fr.pending());
},
drainRecords,
claimScope: id
}
});
if (binding) followBinding(frame, binding);
solidJs.onCleanup(() => frame.dispose());

@@ -1753,13 +1702,12 @@ return el;

}
return g._$SC.c[i] || (g._$SC.c[i] = p => g._$SC.impl(i, p));
return g._$SC.c[i] || (g._$SC.c[i] = (p, b) => g._$SC.impl(i, p, b));
}
};
}
g._$SC.impl = (id, props) => documentBoundary(host, id, props);
g._$SC.impl = (id, props, binding) => documentBoundary(host, id, props, binding);
installRevealHook();
const handler = createServerComponentHandler({
host,
component: frameId => boundaryComponent(host, frameId),
onStream: frameId => beginStream(frameId),
documentComponent: functionId => claimedBoundaries.has(functionId) ? undefined : g._$SC.c[functionId],
component: fnId => g._$SC.r(fnId),
onStream: address => beginStream(address),
intercept: ({

@@ -1772,3 +1720,3 @@ id

});
const showing = (address, id) => handler.showing(address, id, g._$SC.r(id));
const showing = (address, id) => handler.showing(address, id);
const records = g._$SC.a || (g._$SC.a = {});

@@ -1775,0 +1723,0 @@ for (const address in records) showing(address, records[address]);

@@ -86,14 +86,22 @@ 'use strict';

const frames = new Map();
const pending = new Map();
const retained = new Map();
const deliver = (frame, chunk) => {
if (chunk.type === "data") {
options.applyData && options.applyData(chunk);
return;
}
frame.apply({
version: chunk.version,
r: chunkToRecords(chunk)
const stores = new Map();
const storeFor = id => {
let store = stores.get(id);
if (!store) stores.set(id, store = {
version: undefined,
records: {}
});
return store;
};
const write = (store, version, records) => {
if (store.version !== undefined && version < store.version) return false;
if (store.version === undefined || version > store.version) {
store.version = version;
for (const key of Object.keys(store.records)) {
if (key.startsWith("seg:") || key === ":error") delete store.records[key];
}
}
Object.assign(store.records, records);
return true;
};
return {

@@ -103,39 +111,11 @@ register(id, frame) {

if (!set) frames.set(id, set = new Set());
const sibling = set.size ? set.values().next().value : undefined;
set.add(frame);
if (sibling) {
const store = stores.get(id);
if (store && store.version !== undefined) {
frame.apply({
version: sibling.version ?? 0,
r: sibling.store
version: store.version,
r: store.records
});
if (sibling.version === undefined) frame.rebase && frame.rebase();
return;
}
const kept = retained.get(id);
if (kept) {
retained.delete(id);
frame.apply({
version: kept.version,
r: kept.records
});
frame.rebase && frame.rebase();
}
const buffered = pending.get(id);
if (buffered) {
pending.delete(id);
const records = {};
let version;
for (const chunk of buffered.chunks) {
if (chunk.type === "data") {
options.applyData && options.applyData(chunk);
continue;
}
version = chunk.version;
Object.assign(records, chunkToRecords(chunk));
}
if (version !== undefined) frame.apply({
version,
r: records
});
}
},

@@ -146,11 +126,18 @@ unregister(id, frame) {

if (!set || !frame || !set.size) {
if (frame) {
const kept = frame.snapshot && frame.snapshot();
if (kept) retained.set(id, kept);
} else {
retained.delete(id);
frames.delete(id);
if (frame && frame.contentHTML) {
const store = storeFor(id);
if (!store.records[""]) {
const html = frame.contentHTML();
if (html != null) {
store.records[""] = {
kind: "html",
value: html
};
if (store.version === undefined) store.version = 0;
}
}
}
frames.delete(id);
pending.delete(id);
}
if (!frame) stores.delete(id);
},

@@ -162,21 +149,11 @@ apply(chunk) {

}
const records = chunkToRecords(chunk);
if (!write(storeFor(chunk.id), chunk.version, records)) return;
const set = frames.get(chunk.id);
if (set && set.size) {
for (const frame of set) deliver(frame, chunk);
return;
}
const buffered = pending.get(chunk.id);
if (!buffered) {
pending.set(chunk.id, {
if (set) {
for (const frame of set) frame.apply({
version: chunk.version,
chunks: [chunk]
r: records
});
return;
}
if (chunk.version < buffered.version) return;
if (chunk.version > buffered.version) {
buffered.version = chunk.version;
buffered.chunks.length = 0;
}
buffered.chunks.push(chunk);
},

@@ -217,2 +194,3 @@ get(id) {

#processedAssets = new Set();
#recordRefresh = null;
#disposed = false;

@@ -363,3 +341,5 @@ #styleFlush = () => {

const key = `slot:${occurrence}`;
if (key in this.#store) delete this.#store[key];else this.#options.removeSlotRecord?.(occurrence);
if (key in this.#store) {
if (!this.#mountedSlots.has(occurrence)) delete this.#store[key];
} else this.#options.removeSlotRecord?.(occurrence);
}

@@ -382,2 +362,11 @@ #syncSlots(root) {

if (!this.#mountedSlots.has(occurrence)) {
if (record === undefined && !root && this.#options.adopt && this.#options.recordsPending?.()) {
this.#recordRefresh ??= setTimeout(() => {
this.#recordRefresh = null;
if (this.#disposed) return;
this.#options.drainRecords?.();
this.#syncSlots();
});
continue;
}
if (this.#options.adopt) this.#discoverRegions(occurrence, start);

@@ -399,8 +388,2 @@ const nodes = this.#invokeSlot(occurrence, callback, record, start, this.#options.adopt);

const props = this.#resolveArgs(occurrence, record.args);
const regions = this.#slotRegions.get(occurrence);
if (regions) {
for (const [argKey, entry] of regions) {
if (!(argKey in props)) props[argKey] = entry.element;
}
}
this.#slotArgs.set(occurrence, record);

@@ -451,8 +434,2 @@ update(props);

const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
const regions = this.#slotRegions.get(occurrence);
if (regions) {
for (const [argKey, entry] of regions) {
if (!(argKey in props)) props[argKey] = entry.element;
}
}
const scope = this.#options.ownerScope;

@@ -542,6 +519,5 @@ const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);

const endData = slotEnd(slotKey);
const prefix = `${this.#options.id}.`;
let n = start.nextSibling;
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
collectRegionElements(n, regions, prefix);
collectRegionElements(n, regions);
n = n.nextSibling;

@@ -558,12 +534,3 @@ }

const kb = Object.keys(b);
if (kb.length < ka.length) return false;
if (kb.length !== ka.length) {
const regions = this.#slotRegions.get(occurrence);
for (const key of kb) {
if (key in a) continue;
const vb = b[key];
if (!vb || typeof vb !== "object" || typeof vb.$frame !== "string") return false;
if (!regions || !regions.has(key)) return false;
}
}
if (kb.length !== ka.length) return false;
const cache = this.#slotResolvedRefs.get(occurrence);

@@ -625,18 +592,5 @@ for (const key of ka) {

}
snapshot() {
if (this.#disposed) return null;
const records = {
...this.#store
};
if (!records[""] && this.#element && this.#hasContent) {
records[""] = {
kind: "html",
value: this.#element.innerHTML
};
}
if (!records[""] && this.#version === undefined) return null;
return {
version: this.#version ?? 0,
records
};
contentHTML() {
if (this.#disposed || !this.#element || !this.#hasContent) return null;
return this.#element.innerHTML;
}

@@ -676,2 +630,6 @@ rebind(id) {

this.#disposed = true;
if (this.#recordRefresh) {
clearTimeout(this.#recordRefresh);
this.#recordRefresh = null;
}
for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);

@@ -699,4 +657,5 @@ for (const key of this.#mountedSlots) this.#removeSlotRecord(key);

this.#collectSlots(ranges);
reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges);
if (ranges.size) restoreDisplacedRanges(this.#firstContent(), this.#end, ranges);
const grafts = [];
reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges, grafts);
if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
}

@@ -924,7 +883,7 @@ }

}
function collectRegionElements(node, regions, prefix) {
function collectRegionElements(node, regions) {
if (node.nodeType !== ELEMENT_NODE) return;
if (isFrameElement(node)) {
const childId = node.getAttribute(FRAME_ID_ATTR);
if (childId && childId.startsWith(prefix)) {
if (childId && childId.includes(".")) {
const argKey = childId.slice(childId.lastIndexOf(".") + 1);

@@ -942,3 +901,3 @@ if (!regions.has(argKey)) {

}
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions, prefix);
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions);
}

@@ -1011,7 +970,7 @@ function renameRegion(entry, childId) {

}
function morphNode(oldNode, newNode, claim, ranges) {
function morphNode(oldNode, newNode, claim, ranges, grafts) {
if (oldNode.nodeType === ELEMENT_NODE) {
if (oldNode.hasAttribute("data-preserve")) return;
morphAttributes(oldNode, newNode, claim);
reconcileChildren(oldNode, newNode, null, null, claim, ranges);
reconcileChildren(oldNode, newNode, null, null, claim, ranges, grafts);
} else if (oldNode.data !== newNode.data) {

@@ -1059,2 +1018,9 @@ oldNode.data = newNode.data;

}
function placeRange(parent, range, id, ref) {
if (range.nodeType === 11 ) {
parent.insertBefore(range, ref);
} else {
moveRangeBefore(parent, range, id, ref);
}
}
function adoptRange(parent, start, id, ref, claim) {

@@ -1077,3 +1043,3 @@ const end = slotEnd(id);

}
function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null) {
function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null, grafts = null) {
let oldChild = boundStart ? boundStart.nextSibling : parent.firstChild;

@@ -1094,7 +1060,3 @@ let newChild = source.firstChild;

if (ranges) ranges.delete(pid);
if (existing.nodeType === 11 ) {
parent.insertBefore(existing, old ?? boundEnd);
} else {
moveRangeBefore(parent, existing, pid, old ?? boundEnd);
}
placeRange(parent, existing, pid, old ?? boundEnd);
newChild = afterRange(newChild, pid);

@@ -1110,2 +1072,3 @@ } else {

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1117,2 +1080,3 @@ continue;

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1122,3 +1086,3 @@ continue;

if (compatible(old, newChild)) {
morphNode(old, newChild, claim, ranges);
morphNode(old, newChild, claim, ranges, grafts);
oldChild = old.nextSibling;

@@ -1136,3 +1100,3 @@ newChild = nextNew;

parent.insertBefore(ahead, old);
morphNode(ahead, newChild, claim, ranges);
morphNode(ahead, newChild, claim, ranges, grafts);
newChild = nextNew;

@@ -1144,2 +1108,3 @@ continue;

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1161,16 +1126,20 @@ }

}
function restoreDisplacedRanges(first, end, ranges) {
const found = new Map();
collectSlots(first, end, found);
for (const [id, start] of found) {
const displaced = ranges.get(id);
if (!displaced || displaced === start) continue;
ranges.delete(id);
const parent = start.parentNode;
if (displaced.nodeType === 11 ) {
parent.insertBefore(displaced, start);
} else {
moveRangeBefore(parent, displaced, id, start);
function flushGrafts(node, ranges) {
if (node.nodeType !== ELEMENT_NODE || isFrameElement(node)) return;
let n = node.firstChild;
while (n) {
const id = slotStartId(n);
if (id !== null) {
const next = afterRange(n, id);
const displaced = ranges.get(id);
if (displaced) {
ranges.delete(id);
placeRange(node, displaced, id, n);
stashRange(document.createDocumentFragment(), n, id);
}
n = next;
continue;
}
stashRange(document.createDocumentFragment(), start, id);
flushGrafts(n, ranges);
n = n.nextSibling;
}

@@ -1207,3 +1176,3 @@ }

} else {
if (as !== undefined && chunk.id === rootId) chunk.id = as;else if (options.route) chunk.id = options.route(chunk.id);
if (as !== undefined && chunk.id === rootId) chunk.id = as;
if (perFrame) {

@@ -1222,3 +1191,3 @@ let v = perFrame.get(chunk.id);

const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
const COMPONENT_HANDOFF = /*#__PURE__*/Symbol.for("dom-expressions.component-handoff");
const COMPONENT_BINDING = /*#__PURE__*/Symbol.for("dom-expressions.component-binding");
let resolveServerComponent;

@@ -1247,3 +1216,4 @@ function parseServerComponent(value, ctx) {

serialize(node, ctx) {
return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
const registry = "self._$SC";
return registry + ".r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
},

@@ -1273,3 +1243,2 @@ deserialize(node, ctx) {

onStream,
documentComponent,
intercept,

@@ -1279,50 +1248,27 @@ consumer = client.getFlightDataConsumer,

}) {
const byAddress = new Map();
const forwards = new Map();
const brand = (comp, fnId, frameId) => {
const brandable = typeof comp === "function" || typeof comp === "object" && comp !== null;
if (brandable && !comp[COMPONENT_HANDOFF]) {
comp[COMPONENT_HANDOFF] = {
fnId,
frameId,
take(prev) {
const meta = prev !== null && (typeof prev === "function" || typeof prev === "object") && prev[COMPONENT_HANDOFF];
if (!meta || meta.fnId !== fnId) return false;
const root = meta.frameId;
let cur = forwards.get(root) ?? root;
if (cur !== root && !host.get(cur)) {
forwards.delete(root);
cur = root;
}
if (cur === frameId) return true;
let frame = host.get(cur);
if (!frame) return false;
while (frame) {
frame.rebind(frameId);
frame = host.get(cur);
}
if (frameId === root) forwards.delete(root);else forwards.set(root, frameId);
return true;
}
};
}
const byFn = new Map();
const componentFor = fnId => {
let comp = byFn.get(fnId);
if (comp === undefined) byFn.set(fnId, comp = component(fnId));
return comp;
};
const boundaryFor = (address, fnId) => {
let entry = byAddress.get(address);
if (!entry) {
entry = {
frameId: address,
component: brand(component(address), fnId, address)
const byAddress = new Map();
const bindingFor = (address, fnId) => {
let binding = byAddress.get(address);
if (!binding) {
const comp = componentFor(fnId);
binding = props => comp(props, () => address);
binding[COMPONENT_BINDING] = {
component: comp,
address
};
byAddress.set(address, entry);
byAddress.set(address, binding);
}
return entry;
return binding;
};
const resolveAddress = (id, address) => boundaryFor(address, id).component;
resolveServerComponent = resolveAddress;
resolveServerComponent = (id, address) => bindingFor(address, id);
const versions = new Map();
const bump = frameId => {
const version = (versions.get(frameId) || 0) + 1;
versions.set(frameId, version);
const bump = address => {
const version = (versions.get(address) || 0) + 1;
versions.set(address, version);
return version;

@@ -1333,10 +1279,4 @@ };

const hit = intercept(info);
if (hit !== undefined) {
const address = client.frameAddress(info.id, info.args);
byAddress.set(address, {
frameId: info.id,
component: brand(hit, info.id, info.id)
});
}
return hit;
if (hit === undefined) return undefined;
return bindingFor(client.frameAddress(info.id, info.args), info.id);
}),

@@ -1346,26 +1286,14 @@ handle(response, ctx) {

const address = client.frameAddress(ctx.id, ctx.args);
let entry = byAddress.get(address);
if (!entry) {
const adopted = documentComponent && documentComponent(ctx.id);
if (adopted) {
entry = {
frameId: ctx.id,
component: brand(adopted, ctx.id, ctx.id)
};
byAddress.set(address, entry);
} else {
entry = boundaryFor(address, ctx.id);
}
}
const binding = bindingFor(address, ctx.id);
if (response.headers.has(client.SINGLE_FLIGHT_HEADER)) {
return applyFlightResponse(response, entry);
return applyFlightResponse(response, address, binding);
}
const version = bump(entry.frameId);
if (onStream) onStream(entry.frameId, version, response);
const version = bump(address);
if (onStream) onStream(address, version, response);
applyFrameResponse(response, host, {
as: entry.frameId,
as: address,
version
}).catch(err => host.apply({
type: "error",
id: entry.frameId,
id: address,
version,

@@ -1376,17 +1304,18 @@ error: {

}));
return entry.component;
return binding;
},
showing(address, functionId, component) {
if (!byAddress.has(address)) {
byAddress.set(address, {
frameId: functionId,
component: brand(component, functionId, functionId),
showing(address, functionId) {
bindingFor(address, functionId);
const comp = componentFor(functionId);
if ((typeof comp === "function" || typeof comp === "object" && comp !== null) && !comp[COMPONENT_BINDING]) {
comp[COMPONENT_BINDING] = {
component: comp,
address
});
};
}
}
};
async function applyFlightResponse(response, entry) {
async function applyFlightResponse(response, address, binding) {
const rootId = response.headers.get(FRAME_STREAM_HEADER) ?? "";
const as = rootId ? entry.frameId : undefined;
const as = rootId ? address : undefined;
let feed;

@@ -1402,6 +1331,2 @@ const source = new ReadableStream({

as,
route: id => {
const local = byAddress.get(id);
return local ? local.frameId : id;
},
version: frameId => {

@@ -1427,3 +1352,3 @@ const version = bump(frameId);

}
return rootId ? entry.component : envelope.value;
return rootId ? binding : envelope.value;
}

@@ -1607,11 +1532,3 @@ }

if (ctx && ctx.range) {
let claim = adopted;
const source = value;
const accessor = () => {
if (claim) {
claim = false;
return claimRender(prefix, ctx.existing, () => typeof source === "function" ? source() : source);
}
return typeof source === "function" ? source() : source;
};
const owner = solidJs.createOwner();

@@ -1624,3 +1541,4 @@ bindings.set(key, owner);

const end = ctx.range.end;
solidJs.runWithOwner(owner, () => web$1.insert(end.parentNode, accessor, end, [...ctx.existing]));
const bind = () => web$1.insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
solidJs.runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
return undefined;

@@ -1639,11 +1557,15 @@ }

}
function boundaryComponent(host, id) {
return props => {
function followBinding(frame, binding) {
solidJs.createRenderEffect(binding, address => frame.rebind(address));
}
function boundaryComponent(host, fnId) {
return (props, binding) => {
const owner = solidJs.getOwner();
const {
element,
frame,
dispose
} = createFrameElement({
host,
id,
id: binding ? binding() : fnId,
slots: slotsFor(props),

@@ -1653,2 +1575,3 @@ ownerScope: boundaryScope(owner),

});
if (binding) followBinding(frame, binding);
solidJs.onCleanup(dispose);

@@ -1675,47 +1598,61 @@ return element;

const boundaryWaiters = new Map();
function documentStreaming() {
function boundaryMayArrive() {
const hy = globalThis._$HY;
return !!hy && !hy.done;
if (!hy) return false;
return !hy.done || !!(hy.fr && hy.fr.pending());
}
function installRevealHook() {
const hy = globalThis._$HY;
if (!hy || hy.$sc) return;
if (!hy || hy.$sc || !hy.fr) return;
hy.$sc = true;
const prev = hy.fe;
hy.fe = (fragmentId, parent) => {
if (prev) prev(fragmentId, parent);
hy.fr.subscribe((_id, parent) => {
if (!boundaryIndex) return;
const root = parent || (typeof document !== "undefined" ? document.body : null);
if (!root) return;
indexBoundaries(root);
if (root) indexBoundaries(root);
if (!boundaryWaiters.size) return;
const exhausted = hy.done && !hy.fr.pending();
for (const [id, notify] of boundaryWaiters) {
const el = boundaryIndex.get(id);
if (!el) continue;
const el = boundaryIndex && boundaryIndex.get(id);
if (!el && !exhausted) continue;
boundaryWaiters.delete(id);
notify(el);
}
};
});
}
function documentBoundary(host, id, props) {
function documentBoundary(host, id, props, binding) {
installRevealHook();
const claimed = claimedBoundaries.has(id);
const el = !claimed ? findBoundaryElement(id) : undefined;
if (el) return adoptBoundary(host, id, el, props);
if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
if (el) return adoptBoundary(host, id, el, props, binding);
if (!claimed && !boundaryWaiters.has(id) && boundaryMayArrive()) {
const owner = solidJs.getOwner();
const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
solidJs.onCleanup(() => boundaryWaiters.delete(id));
return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
return solidJs.createMemo(() => arrival.then(node => solidJs.runWithOwner(owner, () =>
node ? adoptBoundary(host, id, node, props, binding) : boundaryComponent(host, id)(props, binding))));
}
return boundaryComponent(host, id)(props);
return boundaryComponent(host, id)(props, binding);
}
function adoptBoundary(host, id, el, props) {
function documentAddress(id) {
const records = globalThis._$SC?.a;
if (records) {
for (const address in records) if (records[address] === id) return address;
}
return id;
}
function adoptBoundary(host, id, el, props, binding) {
claimedBoundaries.add(id);
const hy = globalThis._$HY;
if (hy && hy.r) {
const address = binding ? binding() : documentAddress(id);
const appliedRecords = new Set();
const drainRecords = () => {
const hy = globalThis._$HY;
if (!hy || !hy.r) return;
const slotPrefix = `sc:slot:${id}:`;
for (const key of Object.keys(hy.r)) {
if (appliedRecords.has(key)) continue;
if (key.startsWith(slotPrefix)) {
appliedRecords.add(key);
host.apply({
type: "slot",
id,
id: address,
version: 0,

@@ -1728,2 +1665,3 @@ key: key.slice(slotPrefix.length),

if (childId.startsWith(id + ".")) {
appliedRecords.add(key);
const val = hy.r[key];

@@ -1740,3 +1678,4 @@ const apply = html => host.apply({

}
}
};
drainRecords();
const owner = solidJs.getOwner();

@@ -1746,7 +1685,17 @@ const frame = createFrame(el, {

host,
id,
id: address,
slots: slotsFor(props),
ownerScope: boundaryScope(owner),
reveal: revealSeam(owner)
reveal: revealSeam(owner),
...{
recordsPending: () => {
if (document.readyState === "loading") return true;
const hy = globalThis._$HY;
return !!(hy && hy.fr && hy.fr.pending());
},
drainRecords,
claimScope: id
}
});
if (binding) followBinding(frame, binding);
solidJs.onCleanup(() => frame.dispose());

@@ -1766,13 +1715,12 @@ return el;

}
return g._$SC.c[i] || (g._$SC.c[i] = p => g._$SC.impl(i, p));
return g._$SC.c[i] || (g._$SC.c[i] = (p, b) => g._$SC.impl(i, p, b));
}
};
}
g._$SC.impl = (id, props) => documentBoundary(host, id, props);
g._$SC.impl = (id, props, binding) => documentBoundary(host, id, props, binding);
installRevealHook();
const handler = createServerComponentHandler({
host,
component: frameId => boundaryComponent(host, frameId),
onStream: frameId => beginStream(frameId),
documentComponent: functionId => claimedBoundaries.has(functionId) ? undefined : g._$SC.c[functionId],
component: fnId => g._$SC.r(fnId),
onStream: address => beginStream(address),
intercept: ({

@@ -1785,3 +1733,3 @@ id

});
const showing = (address, id) => handler.showing(address, id, g._$SC.r(id));
const showing = (address, id) => handler.showing(address, id);
const records = g._$SC.a || (g._$SC.a = {});

@@ -1788,0 +1736,0 @@ for (const address in records) showing(address, records[address]);

@@ -1,2 +0,2 @@

import { getOwner, onCleanup, createMemo, runWithOwner, createLoadingBoundary, createOwner, sharedConfig, createSignal } from 'solid-js';
import { getOwner, onCleanup, createMemo, runWithOwner, createLoadingBoundary, createOwner, createRenderEffect, sharedConfig, createSignal } from 'solid-js';
import { insert } from '@solidjs/web';

@@ -84,14 +84,22 @@ import { createPlugin, fromCrossJSON, Feature } from 'seroval';

const frames = new Map();
const pending = new Map();
const retained = new Map();
const deliver = (frame, chunk) => {
if (chunk.type === "data") {
options.applyData && options.applyData(chunk);
return;
}
frame.apply({
version: chunk.version,
r: chunkToRecords(chunk)
const stores = new Map();
const storeFor = id => {
let store = stores.get(id);
if (!store) stores.set(id, store = {
version: undefined,
records: {}
});
return store;
};
const write = (store, version, records) => {
if (store.version !== undefined && version < store.version) return false;
if (store.version === undefined || version > store.version) {
store.version = version;
for (const key of Object.keys(store.records)) {
if (key.startsWith("seg:") || key === ":error") delete store.records[key];
}
}
Object.assign(store.records, records);
return true;
};
return {

@@ -101,39 +109,11 @@ register(id, frame) {

if (!set) frames.set(id, set = new Set());
const sibling = set.size ? set.values().next().value : undefined;
set.add(frame);
if (sibling) {
const store = stores.get(id);
if (store && store.version !== undefined) {
frame.apply({
version: sibling.version ?? 0,
r: sibling.store
version: store.version,
r: store.records
});
if (sibling.version === undefined) frame.rebase && frame.rebase();
return;
}
const kept = retained.get(id);
if (kept) {
retained.delete(id);
frame.apply({
version: kept.version,
r: kept.records
});
frame.rebase && frame.rebase();
}
const buffered = pending.get(id);
if (buffered) {
pending.delete(id);
const records = {};
let version;
for (const chunk of buffered.chunks) {
if (chunk.type === "data") {
options.applyData && options.applyData(chunk);
continue;
}
version = chunk.version;
Object.assign(records, chunkToRecords(chunk));
}
if (version !== undefined) frame.apply({
version,
r: records
});
}
},

@@ -144,11 +124,18 @@ unregister(id, frame) {

if (!set || !frame || !set.size) {
if (frame) {
const kept = frame.snapshot && frame.snapshot();
if (kept) retained.set(id, kept);
} else {
retained.delete(id);
frames.delete(id);
if (frame && frame.contentHTML) {
const store = storeFor(id);
if (!store.records[""]) {
const html = frame.contentHTML();
if (html != null) {
store.records[""] = {
kind: "html",
value: html
};
if (store.version === undefined) store.version = 0;
}
}
}
frames.delete(id);
pending.delete(id);
}
if (!frame) stores.delete(id);
},

@@ -160,21 +147,11 @@ apply(chunk) {

}
const records = chunkToRecords(chunk);
if (!write(storeFor(chunk.id), chunk.version, records)) return;
const set = frames.get(chunk.id);
if (set && set.size) {
for (const frame of set) deliver(frame, chunk);
return;
}
const buffered = pending.get(chunk.id);
if (!buffered) {
pending.set(chunk.id, {
if (set) {
for (const frame of set) frame.apply({
version: chunk.version,
chunks: [chunk]
r: records
});
return;
}
if (chunk.version < buffered.version) return;
if (chunk.version > buffered.version) {
buffered.version = chunk.version;
buffered.chunks.length = 0;
}
buffered.chunks.push(chunk);
},

@@ -215,2 +192,3 @@ get(id) {

#processedAssets = new Set();
#recordRefresh = null;
#disposed = false;

@@ -361,3 +339,5 @@ #styleFlush = () => {

const key = `slot:${occurrence}`;
if (key in this.#store) delete this.#store[key];else this.#options.removeSlotRecord?.(occurrence);
if (key in this.#store) {
if (!this.#mountedSlots.has(occurrence)) delete this.#store[key];
} else this.#options.removeSlotRecord?.(occurrence);
}

@@ -380,2 +360,11 @@ #syncSlots(root) {

if (!this.#mountedSlots.has(occurrence)) {
if (record === undefined && !root && this.#options.adopt && this.#options.recordsPending?.()) {
this.#recordRefresh ??= setTimeout(() => {
this.#recordRefresh = null;
if (this.#disposed) return;
this.#options.drainRecords?.();
this.#syncSlots();
});
continue;
}
if (this.#options.adopt) this.#discoverRegions(occurrence, start);

@@ -397,8 +386,2 @@ const nodes = this.#invokeSlot(occurrence, callback, record, start, this.#options.adopt);

const props = this.#resolveArgs(occurrence, record.args);
const regions = this.#slotRegions.get(occurrence);
if (regions) {
for (const [argKey, entry] of regions) {
if (!(argKey in props)) props[argKey] = entry.element;
}
}
this.#slotArgs.set(occurrence, record);

@@ -449,8 +432,2 @@ update(props);

const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
const regions = this.#slotRegions.get(occurrence);
if (regions) {
for (const [argKey, entry] of regions) {
if (!(argKey in props)) props[argKey] = entry.element;
}
}
const scope = this.#options.ownerScope;

@@ -540,6 +517,5 @@ const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);

const endData = slotEnd(slotKey);
const prefix = `${this.#options.id}.`;
let n = start.nextSibling;
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
collectRegionElements(n, regions, prefix);
collectRegionElements(n, regions);
n = n.nextSibling;

@@ -556,12 +532,3 @@ }

const kb = Object.keys(b);
if (kb.length < ka.length) return false;
if (kb.length !== ka.length) {
const regions = this.#slotRegions.get(occurrence);
for (const key of kb) {
if (key in a) continue;
const vb = b[key];
if (!vb || typeof vb !== "object" || typeof vb.$frame !== "string") return false;
if (!regions || !regions.has(key)) return false;
}
}
if (kb.length !== ka.length) return false;
const cache = this.#slotResolvedRefs.get(occurrence);

@@ -623,18 +590,5 @@ for (const key of ka) {

}
snapshot() {
if (this.#disposed) return null;
const records = {
...this.#store
};
if (!records[""] && this.#element && this.#hasContent) {
records[""] = {
kind: "html",
value: this.#element.innerHTML
};
}
if (!records[""] && this.#version === undefined) return null;
return {
version: this.#version ?? 0,
records
};
contentHTML() {
if (this.#disposed || !this.#element || !this.#hasContent) return null;
return this.#element.innerHTML;
}

@@ -674,2 +628,6 @@ rebind(id) {

this.#disposed = true;
if (this.#recordRefresh) {
clearTimeout(this.#recordRefresh);
this.#recordRefresh = null;
}
for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);

@@ -697,4 +655,5 @@ for (const key of this.#mountedSlots) this.#removeSlotRecord(key);

this.#collectSlots(ranges);
reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges);
if (ranges.size) restoreDisplacedRanges(this.#firstContent(), this.#end, ranges);
const grafts = [];
reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges, grafts);
if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
}

@@ -922,7 +881,7 @@ }

}
function collectRegionElements(node, regions, prefix) {
function collectRegionElements(node, regions) {
if (node.nodeType !== ELEMENT_NODE) return;
if (isFrameElement(node)) {
const childId = node.getAttribute(FRAME_ID_ATTR);
if (childId && childId.startsWith(prefix)) {
if (childId && childId.includes(".")) {
const argKey = childId.slice(childId.lastIndexOf(".") + 1);

@@ -940,3 +899,3 @@ if (!regions.has(argKey)) {

}
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions, prefix);
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions);
}

@@ -1009,7 +968,7 @@ function renameRegion(entry, childId) {

}
function morphNode(oldNode, newNode, claim, ranges) {
function morphNode(oldNode, newNode, claim, ranges, grafts) {
if (oldNode.nodeType === ELEMENT_NODE) {
if (oldNode.hasAttribute("data-preserve")) return;
morphAttributes(oldNode, newNode, claim);
reconcileChildren(oldNode, newNode, null, null, claim, ranges);
reconcileChildren(oldNode, newNode, null, null, claim, ranges, grafts);
} else if (oldNode.data !== newNode.data) {

@@ -1057,2 +1016,9 @@ oldNode.data = newNode.data;

}
function placeRange(parent, range, id, ref) {
if (range.nodeType === 11 ) {
parent.insertBefore(range, ref);
} else {
moveRangeBefore(parent, range, id, ref);
}
}
function adoptRange(parent, start, id, ref, claim) {

@@ -1075,3 +1041,3 @@ const end = slotEnd(id);

}
function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null) {
function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null, grafts = null) {
let oldChild = boundStart ? boundStart.nextSibling : parent.firstChild;

@@ -1092,7 +1058,3 @@ let newChild = source.firstChild;

if (ranges) ranges.delete(pid);
if (existing.nodeType === 11 ) {
parent.insertBefore(existing, old ?? boundEnd);
} else {
moveRangeBefore(parent, existing, pid, old ?? boundEnd);
}
placeRange(parent, existing, pid, old ?? boundEnd);
newChild = afterRange(newChild, pid);

@@ -1108,2 +1070,3 @@ } else {

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1115,2 +1078,3 @@ continue;

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1120,3 +1084,3 @@ continue;

if (compatible(old, newChild)) {
morphNode(old, newChild, claim, ranges);
morphNode(old, newChild, claim, ranges, grafts);
oldChild = old.nextSibling;

@@ -1134,3 +1098,3 @@ newChild = nextNew;

parent.insertBefore(ahead, old);
morphNode(ahead, newChild, claim, ranges);
morphNode(ahead, newChild, claim, ranges, grafts);
newChild = nextNew;

@@ -1142,2 +1106,3 @@ continue;

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1159,16 +1124,20 @@ }

}
function restoreDisplacedRanges(first, end, ranges) {
const found = new Map();
collectSlots(first, end, found);
for (const [id, start] of found) {
const displaced = ranges.get(id);
if (!displaced || displaced === start) continue;
ranges.delete(id);
const parent = start.parentNode;
if (displaced.nodeType === 11 ) {
parent.insertBefore(displaced, start);
} else {
moveRangeBefore(parent, displaced, id, start);
function flushGrafts(node, ranges) {
if (node.nodeType !== ELEMENT_NODE || isFrameElement(node)) return;
let n = node.firstChild;
while (n) {
const id = slotStartId(n);
if (id !== null) {
const next = afterRange(n, id);
const displaced = ranges.get(id);
if (displaced) {
ranges.delete(id);
placeRange(node, displaced, id, n);
stashRange(document.createDocumentFragment(), n, id);
}
n = next;
continue;
}
stashRange(document.createDocumentFragment(), start, id);
flushGrafts(n, ranges);
n = n.nextSibling;
}

@@ -1205,3 +1174,3 @@ }

} else {
if (as !== undefined && chunk.id === rootId) chunk.id = as;else if (options.route) chunk.id = options.route(chunk.id);
if (as !== undefined && chunk.id === rootId) chunk.id = as;
if (perFrame) {

@@ -1220,3 +1189,3 @@ let v = perFrame.get(chunk.id);

const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
const COMPONENT_HANDOFF = /*#__PURE__*/Symbol.for("dom-expressions.component-handoff");
const COMPONENT_BINDING = /*#__PURE__*/Symbol.for("dom-expressions.component-binding");
let resolveServerComponent;

@@ -1245,3 +1214,4 @@ function parseServerComponent(value, ctx) {

serialize(node, ctx) {
return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
const registry = "self._$SC";
return registry + ".r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
},

@@ -1271,3 +1241,2 @@ deserialize(node, ctx) {

onStream,
documentComponent,
intercept,

@@ -1277,50 +1246,27 @@ consumer = getFlightDataConsumer,

}) {
const byAddress = new Map();
const forwards = new Map();
const brand = (comp, fnId, frameId) => {
const brandable = typeof comp === "function" || typeof comp === "object" && comp !== null;
if (brandable && !comp[COMPONENT_HANDOFF]) {
comp[COMPONENT_HANDOFF] = {
fnId,
frameId,
take(prev) {
const meta = prev !== null && (typeof prev === "function" || typeof prev === "object") && prev[COMPONENT_HANDOFF];
if (!meta || meta.fnId !== fnId) return false;
const root = meta.frameId;
let cur = forwards.get(root) ?? root;
if (cur !== root && !host.get(cur)) {
forwards.delete(root);
cur = root;
}
if (cur === frameId) return true;
let frame = host.get(cur);
if (!frame) return false;
while (frame) {
frame.rebind(frameId);
frame = host.get(cur);
}
if (frameId === root) forwards.delete(root);else forwards.set(root, frameId);
return true;
}
};
}
const byFn = new Map();
const componentFor = fnId => {
let comp = byFn.get(fnId);
if (comp === undefined) byFn.set(fnId, comp = component(fnId));
return comp;
};
const boundaryFor = (address, fnId) => {
let entry = byAddress.get(address);
if (!entry) {
entry = {
frameId: address,
component: brand(component(address), fnId, address)
const byAddress = new Map();
const bindingFor = (address, fnId) => {
let binding = byAddress.get(address);
if (!binding) {
const comp = componentFor(fnId);
binding = props => comp(props, () => address);
binding[COMPONENT_BINDING] = {
component: comp,
address
};
byAddress.set(address, entry);
byAddress.set(address, binding);
}
return entry;
return binding;
};
const resolveAddress = (id, address) => boundaryFor(address, id).component;
resolveServerComponent = resolveAddress;
resolveServerComponent = (id, address) => bindingFor(address, id);
const versions = new Map();
const bump = frameId => {
const version = (versions.get(frameId) || 0) + 1;
versions.set(frameId, version);
const bump = address => {
const version = (versions.get(address) || 0) + 1;
versions.set(address, version);
return version;

@@ -1331,10 +1277,4 @@ };

const hit = intercept(info);
if (hit !== undefined) {
const address = frameAddress(info.id, info.args);
byAddress.set(address, {
frameId: info.id,
component: brand(hit, info.id, info.id)
});
}
return hit;
if (hit === undefined) return undefined;
return bindingFor(frameAddress(info.id, info.args), info.id);
}),

@@ -1344,26 +1284,14 @@ handle(response, ctx) {

const address = frameAddress(ctx.id, ctx.args);
let entry = byAddress.get(address);
if (!entry) {
const adopted = documentComponent && documentComponent(ctx.id);
if (adopted) {
entry = {
frameId: ctx.id,
component: brand(adopted, ctx.id, ctx.id)
};
byAddress.set(address, entry);
} else {
entry = boundaryFor(address, ctx.id);
}
}
const binding = bindingFor(address, ctx.id);
if (response.headers.has(SINGLE_FLIGHT_HEADER)) {
return applyFlightResponse(response, entry);
return applyFlightResponse(response, address, binding);
}
const version = bump(entry.frameId);
if (onStream) onStream(entry.frameId, version, response);
const version = bump(address);
if (onStream) onStream(address, version, response);
applyFrameResponse(response, host, {
as: entry.frameId,
as: address,
version
}).catch(err => host.apply({
type: "error",
id: entry.frameId,
id: address,
version,

@@ -1374,17 +1302,18 @@ error: {

}));
return entry.component;
return binding;
},
showing(address, functionId, component) {
if (!byAddress.has(address)) {
byAddress.set(address, {
frameId: functionId,
component: brand(component, functionId, functionId),
showing(address, functionId) {
bindingFor(address, functionId);
const comp = componentFor(functionId);
if ((typeof comp === "function" || typeof comp === "object" && comp !== null) && !comp[COMPONENT_BINDING]) {
comp[COMPONENT_BINDING] = {
component: comp,
address
});
};
}
}
};
async function applyFlightResponse(response, entry) {
async function applyFlightResponse(response, address, binding) {
const rootId = response.headers.get(FRAME_STREAM_HEADER) ?? "";
const as = rootId ? entry.frameId : undefined;
const as = rootId ? address : undefined;
let feed;

@@ -1400,6 +1329,2 @@ const source = new ReadableStream({

as,
route: id => {
const local = byAddress.get(id);
return local ? local.frameId : id;
},
version: frameId => {

@@ -1425,3 +1350,3 @@ const version = bump(frameId);

}
return rootId ? entry.component : envelope.value;
return rootId ? binding : envelope.value;
}

@@ -1605,11 +1530,3 @@ }

if (ctx && ctx.range) {
let claim = adopted;
const source = value;
const accessor = () => {
if (claim) {
claim = false;
return claimRender(prefix, ctx.existing, () => typeof source === "function" ? source() : source);
}
return typeof source === "function" ? source() : source;
};
const owner = createOwner();

@@ -1622,3 +1539,4 @@ bindings.set(key, owner);

const end = ctx.range.end;
runWithOwner(owner, () => insert(end.parentNode, accessor, end, [...ctx.existing]));
const bind = () => insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
return undefined;

@@ -1637,11 +1555,15 @@ }

}
function boundaryComponent(host, id) {
return props => {
function followBinding(frame, binding) {
createRenderEffect(binding, address => frame.rebind(address));
}
function boundaryComponent(host, fnId) {
return (props, binding) => {
const owner = getOwner();
const {
element,
frame,
dispose
} = createFrameElement({
host,
id,
id: binding ? binding() : fnId,
slots: slotsFor(props),

@@ -1651,2 +1573,3 @@ ownerScope: boundaryScope(owner),

});
if (binding) followBinding(frame, binding);
onCleanup(dispose);

@@ -1673,47 +1596,61 @@ return element;

const boundaryWaiters = new Map();
function documentStreaming() {
function boundaryMayArrive() {
const hy = globalThis._$HY;
return !!hy && !hy.done;
if (!hy) return false;
return !hy.done || !!(hy.fr && hy.fr.pending());
}
function installRevealHook() {
const hy = globalThis._$HY;
if (!hy || hy.$sc) return;
if (!hy || hy.$sc || !hy.fr) return;
hy.$sc = true;
const prev = hy.fe;
hy.fe = (fragmentId, parent) => {
if (prev) prev(fragmentId, parent);
hy.fr.subscribe((_id, parent) => {
if (!boundaryIndex) return;
const root = parent || (typeof document !== "undefined" ? document.body : null);
if (!root) return;
indexBoundaries(root);
if (root) indexBoundaries(root);
if (!boundaryWaiters.size) return;
const exhausted = hy.done && !hy.fr.pending();
for (const [id, notify] of boundaryWaiters) {
const el = boundaryIndex.get(id);
if (!el) continue;
const el = boundaryIndex && boundaryIndex.get(id);
if (!el && !exhausted) continue;
boundaryWaiters.delete(id);
notify(el);
}
};
});
}
function documentBoundary(host, id, props) {
function documentBoundary(host, id, props, binding) {
installRevealHook();
const claimed = claimedBoundaries.has(id);
const el = !claimed ? findBoundaryElement(id) : undefined;
if (el) return adoptBoundary(host, id, el, props);
if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
if (el) return adoptBoundary(host, id, el, props, binding);
if (!claimed && !boundaryWaiters.has(id) && boundaryMayArrive()) {
const owner = getOwner();
const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
onCleanup(() => boundaryWaiters.delete(id));
return createMemo(() => arrival.then(node => runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
return createMemo(() => arrival.then(node => runWithOwner(owner, () =>
node ? adoptBoundary(host, id, node, props, binding) : boundaryComponent(host, id)(props, binding))));
}
return boundaryComponent(host, id)(props);
return boundaryComponent(host, id)(props, binding);
}
function adoptBoundary(host, id, el, props) {
function documentAddress(id) {
const records = globalThis._$SC?.a;
if (records) {
for (const address in records) if (records[address] === id) return address;
}
return id;
}
function adoptBoundary(host, id, el, props, binding) {
claimedBoundaries.add(id);
const hy = globalThis._$HY;
if (hy && hy.r) {
const address = binding ? binding() : documentAddress(id);
const appliedRecords = new Set();
const drainRecords = () => {
const hy = globalThis._$HY;
if (!hy || !hy.r) return;
const slotPrefix = `sc:slot:${id}:`;
for (const key of Object.keys(hy.r)) {
if (appliedRecords.has(key)) continue;
if (key.startsWith(slotPrefix)) {
appliedRecords.add(key);
host.apply({
type: "slot",
id,
id: address,
version: 0,

@@ -1726,2 +1663,3 @@ key: key.slice(slotPrefix.length),

if (childId.startsWith(id + ".")) {
appliedRecords.add(key);
const val = hy.r[key];

@@ -1738,3 +1676,4 @@ const apply = html => host.apply({

}
}
};
drainRecords();
const owner = getOwner();

@@ -1744,7 +1683,17 @@ const frame = createFrame(el, {

host,
id,
id: address,
slots: slotsFor(props),
ownerScope: boundaryScope(owner),
reveal: revealSeam(owner)
reveal: revealSeam(owner),
...{
recordsPending: () => {
if (document.readyState === "loading") return true;
const hy = globalThis._$HY;
return !!(hy && hy.fr && hy.fr.pending());
},
drainRecords,
claimScope: id
}
});
if (binding) followBinding(frame, binding);
onCleanup(() => frame.dispose());

@@ -1764,13 +1713,12 @@ return el;

}
return g._$SC.c[i] || (g._$SC.c[i] = p => g._$SC.impl(i, p));
return g._$SC.c[i] || (g._$SC.c[i] = (p, b) => g._$SC.impl(i, p, b));
}
};
}
g._$SC.impl = (id, props) => documentBoundary(host, id, props);
g._$SC.impl = (id, props, binding) => documentBoundary(host, id, props, binding);
installRevealHook();
const handler = createServerComponentHandler({
host,
component: frameId => boundaryComponent(host, frameId),
onStream: frameId => beginStream(frameId),
documentComponent: functionId => claimedBoundaries.has(functionId) ? undefined : g._$SC.c[functionId],
component: fnId => g._$SC.r(fnId),
onStream: address => beginStream(address),
intercept: ({

@@ -1783,3 +1731,3 @@ id

});
const showing = (address, id) => handler.showing(address, id, g._$SC.r(id));
const showing = (address, id) => handler.showing(address, id);
const records = g._$SC.a || (g._$SC.a = {});

@@ -1786,0 +1734,0 @@ for (const address in records) showing(address, records[address]);

@@ -1,2 +0,2 @@

import { getOwner, onCleanup, createMemo, runWithOwner, createLoadingBoundary, createOwner, sharedConfig, createSignal } from 'solid-js';
import { getOwner, onCleanup, createMemo, runWithOwner, createLoadingBoundary, createOwner, createRenderEffect, sharedConfig, createSignal } from 'solid-js';
import { insert } from '@solidjs/web';

@@ -84,14 +84,22 @@ import { createPlugin, fromCrossJSON, Feature } from 'seroval';

const frames = new Map();
const pending = new Map();
const retained = new Map();
const deliver = (frame, chunk) => {
if (chunk.type === "data") {
options.applyData && options.applyData(chunk);
return;
}
frame.apply({
version: chunk.version,
r: chunkToRecords(chunk)
const stores = new Map();
const storeFor = id => {
let store = stores.get(id);
if (!store) stores.set(id, store = {
version: undefined,
records: {}
});
return store;
};
const write = (store, version, records) => {
if (store.version !== undefined && version < store.version) return false;
if (store.version === undefined || version > store.version) {
store.version = version;
for (const key of Object.keys(store.records)) {
if (key.startsWith("seg:") || key === ":error") delete store.records[key];
}
}
Object.assign(store.records, records);
return true;
};
return {

@@ -101,39 +109,11 @@ register(id, frame) {

if (!set) frames.set(id, set = new Set());
const sibling = set.size ? set.values().next().value : undefined;
set.add(frame);
if (sibling) {
const store = stores.get(id);
if (store && store.version !== undefined) {
frame.apply({
version: sibling.version ?? 0,
r: sibling.store
version: store.version,
r: store.records
});
if (sibling.version === undefined) frame.rebase && frame.rebase();
return;
}
const kept = retained.get(id);
if (kept) {
retained.delete(id);
frame.apply({
version: kept.version,
r: kept.records
});
frame.rebase && frame.rebase();
}
const buffered = pending.get(id);
if (buffered) {
pending.delete(id);
const records = {};
let version;
for (const chunk of buffered.chunks) {
if (chunk.type === "data") {
options.applyData && options.applyData(chunk);
continue;
}
version = chunk.version;
Object.assign(records, chunkToRecords(chunk));
}
if (version !== undefined) frame.apply({
version,
r: records
});
}
},

@@ -144,11 +124,18 @@ unregister(id, frame) {

if (!set || !frame || !set.size) {
if (frame) {
const kept = frame.snapshot && frame.snapshot();
if (kept) retained.set(id, kept);
} else {
retained.delete(id);
frames.delete(id);
if (frame && frame.contentHTML) {
const store = storeFor(id);
if (!store.records[""]) {
const html = frame.contentHTML();
if (html != null) {
store.records[""] = {
kind: "html",
value: html
};
if (store.version === undefined) store.version = 0;
}
}
}
frames.delete(id);
pending.delete(id);
}
if (!frame) stores.delete(id);
},

@@ -160,21 +147,11 @@ apply(chunk) {

}
const records = chunkToRecords(chunk);
if (!write(storeFor(chunk.id), chunk.version, records)) return;
const set = frames.get(chunk.id);
if (set && set.size) {
for (const frame of set) deliver(frame, chunk);
return;
}
const buffered = pending.get(chunk.id);
if (!buffered) {
pending.set(chunk.id, {
if (set) {
for (const frame of set) frame.apply({
version: chunk.version,
chunks: [chunk]
r: records
});
return;
}
if (chunk.version < buffered.version) return;
if (chunk.version > buffered.version) {
buffered.version = chunk.version;
buffered.chunks.length = 0;
}
buffered.chunks.push(chunk);
},

@@ -215,2 +192,3 @@ get(id) {

#processedAssets = new Set();
#recordRefresh = null;
#disposed = false;

@@ -361,3 +339,5 @@ #styleFlush = () => {

const key = `slot:${occurrence}`;
if (key in this.#store) delete this.#store[key];else this.#options.removeSlotRecord?.(occurrence);
if (key in this.#store) {
if (!this.#mountedSlots.has(occurrence)) delete this.#store[key];
} else this.#options.removeSlotRecord?.(occurrence);
}

@@ -380,2 +360,11 @@ #syncSlots(root) {

if (!this.#mountedSlots.has(occurrence)) {
if (record === undefined && !root && this.#options.adopt && this.#options.recordsPending?.()) {
this.#recordRefresh ??= setTimeout(() => {
this.#recordRefresh = null;
if (this.#disposed) return;
this.#options.drainRecords?.();
this.#syncSlots();
});
continue;
}
if (this.#options.adopt) this.#discoverRegions(occurrence, start);

@@ -397,8 +386,2 @@ const nodes = this.#invokeSlot(occurrence, callback, record, start, this.#options.adopt);

const props = this.#resolveArgs(occurrence, record.args);
const regions = this.#slotRegions.get(occurrence);
if (regions) {
for (const [argKey, entry] of regions) {
if (!(argKey in props)) props[argKey] = entry.element;
}
}
this.#slotArgs.set(occurrence, record);

@@ -449,8 +432,2 @@ update(props);

const props = record && record.kind === "slot" ? this.#resolveArgs(occurrence, record.args) : {};
const regions = this.#slotRegions.get(occurrence);
if (regions) {
for (const [argKey, entry] of regions) {
if (!(argKey in props)) props[argKey] = entry.element;
}
}
const scope = this.#options.ownerScope;

@@ -540,6 +517,5 @@ const content = scope ? scope(() => callback(props, ctx)) : callback(props, ctx);

const endData = slotEnd(slotKey);
const prefix = `${this.#options.id}.`;
let n = start.nextSibling;
while (n && !(n.nodeType === COMMENT_NODE && n.data === endData)) {
collectRegionElements(n, regions, prefix);
collectRegionElements(n, regions);
n = n.nextSibling;

@@ -556,12 +532,3 @@ }

const kb = Object.keys(b);
if (kb.length < ka.length) return false;
if (kb.length !== ka.length) {
const regions = this.#slotRegions.get(occurrence);
for (const key of kb) {
if (key in a) continue;
const vb = b[key];
if (!vb || typeof vb !== "object" || typeof vb.$frame !== "string") return false;
if (!regions || !regions.has(key)) return false;
}
}
if (kb.length !== ka.length) return false;
const cache = this.#slotResolvedRefs.get(occurrence);

@@ -623,18 +590,5 @@ for (const key of ka) {

}
snapshot() {
if (this.#disposed) return null;
const records = {
...this.#store
};
if (!records[""] && this.#element && this.#hasContent) {
records[""] = {
kind: "html",
value: this.#element.innerHTML
};
}
if (!records[""] && this.#version === undefined) return null;
return {
version: this.#version ?? 0,
records
};
contentHTML() {
if (this.#disposed || !this.#element || !this.#hasContent) return null;
return this.#element.innerHTML;
}

@@ -674,2 +628,6 @@ rebind(id) {

this.#disposed = true;
if (this.#recordRefresh) {
clearTimeout(this.#recordRefresh);
this.#recordRefresh = null;
}
for (const key of [...this.#slotCleanups.keys()]) this.#runSlotCleanups(key);

@@ -697,4 +655,5 @@ for (const key of this.#mountedSlots) this.#removeSlotRecord(key);

this.#collectSlots(ranges);
reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges);
if (ranges.size) restoreDisplacedRanges(this.#firstContent(), this.#end, ranges);
const grafts = [];
reconcileChildren(parent, fragment, this.#start, this.#end, claim, ranges, grafts);
if (ranges.size) for (const root of grafts) flushGrafts(root, ranges);
}

@@ -918,7 +877,7 @@ }

}
function collectRegionElements(node, regions, prefix) {
function collectRegionElements(node, regions) {
if (node.nodeType !== ELEMENT_NODE) return;
if (isFrameElement(node)) {
const childId = node.getAttribute(FRAME_ID_ATTR);
if (childId && childId.startsWith(prefix)) {
if (childId && childId.includes(".")) {
const argKey = childId.slice(childId.lastIndexOf(".") + 1);

@@ -936,3 +895,3 @@ if (!regions.has(argKey)) {

}
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions, prefix);
for (let c = node.firstChild; c; c = c.nextSibling) collectRegionElements(c, regions);
}

@@ -1005,7 +964,7 @@ function renameRegion(entry, childId) {

}
function morphNode(oldNode, newNode, claim, ranges) {
function morphNode(oldNode, newNode, claim, ranges, grafts) {
if (oldNode.nodeType === ELEMENT_NODE) {
if (oldNode.hasAttribute("data-preserve")) return;
morphAttributes(oldNode, newNode, claim);
reconcileChildren(oldNode, newNode, null, null, claim, ranges);
reconcileChildren(oldNode, newNode, null, null, claim, ranges, grafts);
} else if (oldNode.data !== newNode.data) {

@@ -1044,2 +1003,9 @@ oldNode.data = newNode.data;

}
function placeRange(parent, range, id, ref) {
if (range.nodeType === 11 ) {
parent.insertBefore(range, ref);
} else {
moveRangeBefore(parent, range, id, ref);
}
}
function adoptRange(parent, start, id, ref, claim) {

@@ -1062,3 +1028,3 @@ const end = slotEnd(id);

}
function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null) {
function reconcileChildren(parent, source, boundStart = null, boundEnd = null, claim = null, ranges = null, grafts = null) {
let oldChild = boundStart ? boundStart.nextSibling : parent.firstChild;

@@ -1079,7 +1045,3 @@ let newChild = source.firstChild;

if (ranges) ranges.delete(pid);
if (existing.nodeType === 11 ) {
parent.insertBefore(existing, old ?? boundEnd);
} else {
moveRangeBefore(parent, existing, pid, old ?? boundEnd);
}
placeRange(parent, existing, pid, old ?? boundEnd);
newChild = afterRange(newChild, pid);

@@ -1095,2 +1057,3 @@ } else {

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1102,2 +1065,3 @@ continue;

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1107,3 +1071,3 @@ continue;

if (compatible(old, newChild)) {
morphNode(old, newChild, claim, ranges);
morphNode(old, newChild, claim, ranges, grafts);
oldChild = old.nextSibling;

@@ -1121,3 +1085,3 @@ newChild = nextNew;

parent.insertBefore(ahead, old);
morphNode(ahead, newChild, claim, ranges);
morphNode(ahead, newChild, claim, ranges, grafts);
newChild = nextNew;

@@ -1129,2 +1093,3 @@ continue;

if (claim) claim(newChild);
if (grafts) grafts.push(newChild);
newChild = nextNew;

@@ -1146,16 +1111,20 @@ }

}
function restoreDisplacedRanges(first, end, ranges) {
const found = new Map();
collectSlots(first, end, found);
for (const [id, start] of found) {
const displaced = ranges.get(id);
if (!displaced || displaced === start) continue;
ranges.delete(id);
const parent = start.parentNode;
if (displaced.nodeType === 11 ) {
parent.insertBefore(displaced, start);
} else {
moveRangeBefore(parent, displaced, id, start);
function flushGrafts(node, ranges) {
if (node.nodeType !== ELEMENT_NODE || isFrameElement(node)) return;
let n = node.firstChild;
while (n) {
const id = slotStartId(n);
if (id !== null) {
const next = afterRange(n, id);
const displaced = ranges.get(id);
if (displaced) {
ranges.delete(id);
placeRange(node, displaced, id, n);
stashRange(document.createDocumentFragment(), n, id);
}
n = next;
continue;
}
stashRange(document.createDocumentFragment(), start, id);
flushGrafts(n, ranges);
n = n.nextSibling;
}

@@ -1192,3 +1161,3 @@ }

} else {
if (as !== undefined && chunk.id === rootId) chunk.id = as;else if (options.route) chunk.id = options.route(chunk.id);
if (as !== undefined && chunk.id === rootId) chunk.id = as;
if (perFrame) {

@@ -1207,3 +1176,3 @@ let v = perFrame.get(chunk.id);

const SERVER_COMPONENT_ADDRESS = /*#__PURE__*/Symbol.for("dom-expressions.server-component-address");
const COMPONENT_HANDOFF = /*#__PURE__*/Symbol.for("dom-expressions.component-handoff");
const COMPONENT_BINDING = /*#__PURE__*/Symbol.for("dom-expressions.component-binding");
let resolveServerComponent;

@@ -1232,3 +1201,4 @@ function parseServerComponent(value, ctx) {

serialize(node, ctx) {
return "self._$SC.r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
const registry = "self._$SC";
return registry + ".r(" + ctx.serialize(node.id) + "," + ctx.serialize(node.address) + ")";
},

@@ -1258,3 +1228,2 @@ deserialize(node, ctx) {

onStream,
documentComponent,
intercept,

@@ -1264,50 +1233,27 @@ consumer = getFlightDataConsumer,

}) {
const byAddress = new Map();
const forwards = new Map();
const brand = (comp, fnId, frameId) => {
const brandable = typeof comp === "function" || typeof comp === "object" && comp !== null;
if (brandable && !comp[COMPONENT_HANDOFF]) {
comp[COMPONENT_HANDOFF] = {
fnId,
frameId,
take(prev) {
const meta = prev !== null && (typeof prev === "function" || typeof prev === "object") && prev[COMPONENT_HANDOFF];
if (!meta || meta.fnId !== fnId) return false;
const root = meta.frameId;
let cur = forwards.get(root) ?? root;
if (cur !== root && !host.get(cur)) {
forwards.delete(root);
cur = root;
}
if (cur === frameId) return true;
let frame = host.get(cur);
if (!frame) return false;
while (frame) {
frame.rebind(frameId);
frame = host.get(cur);
}
if (frameId === root) forwards.delete(root);else forwards.set(root, frameId);
return true;
}
};
}
const byFn = new Map();
const componentFor = fnId => {
let comp = byFn.get(fnId);
if (comp === undefined) byFn.set(fnId, comp = component(fnId));
return comp;
};
const boundaryFor = (address, fnId) => {
let entry = byAddress.get(address);
if (!entry) {
entry = {
frameId: address,
component: brand(component(address), fnId, address)
const byAddress = new Map();
const bindingFor = (address, fnId) => {
let binding = byAddress.get(address);
if (!binding) {
const comp = componentFor(fnId);
binding = props => comp(props, () => address);
binding[COMPONENT_BINDING] = {
component: comp,
address
};
byAddress.set(address, entry);
byAddress.set(address, binding);
}
return entry;
return binding;
};
const resolveAddress = (id, address) => boundaryFor(address, id).component;
resolveServerComponent = resolveAddress;
resolveServerComponent = (id, address) => bindingFor(address, id);
const versions = new Map();
const bump = frameId => {
const version = (versions.get(frameId) || 0) + 1;
versions.set(frameId, version);
const bump = address => {
const version = (versions.get(address) || 0) + 1;
versions.set(address, version);
return version;

@@ -1318,10 +1264,4 @@ };

const hit = intercept(info);
if (hit !== undefined) {
const address = frameAddress(info.id, info.args);
byAddress.set(address, {
frameId: info.id,
component: brand(hit, info.id, info.id)
});
}
return hit;
if (hit === undefined) return undefined;
return bindingFor(frameAddress(info.id, info.args), info.id);
}),

@@ -1331,26 +1271,14 @@ handle(response, ctx) {

const address = frameAddress(ctx.id, ctx.args);
let entry = byAddress.get(address);
if (!entry) {
const adopted = documentComponent && documentComponent(ctx.id);
if (adopted) {
entry = {
frameId: ctx.id,
component: brand(adopted, ctx.id, ctx.id)
};
byAddress.set(address, entry);
} else {
entry = boundaryFor(address, ctx.id);
}
}
const binding = bindingFor(address, ctx.id);
if (response.headers.has(SINGLE_FLIGHT_HEADER)) {
return applyFlightResponse(response, entry);
return applyFlightResponse(response, address, binding);
}
const version = bump(entry.frameId);
if (onStream) onStream(entry.frameId, version, response);
const version = bump(address);
if (onStream) onStream(address, version, response);
applyFrameResponse(response, host, {
as: entry.frameId,
as: address,
version
}).catch(err => host.apply({
type: "error",
id: entry.frameId,
id: address,
version,

@@ -1361,17 +1289,18 @@ error: {

}));
return entry.component;
return binding;
},
showing(address, functionId, component) {
if (!byAddress.has(address)) {
byAddress.set(address, {
frameId: functionId,
component: brand(component, functionId, functionId),
showing(address, functionId) {
bindingFor(address, functionId);
const comp = componentFor(functionId);
if ((typeof comp === "function" || typeof comp === "object" && comp !== null) && !comp[COMPONENT_BINDING]) {
comp[COMPONENT_BINDING] = {
component: comp,
address
});
};
}
}
};
async function applyFlightResponse(response, entry) {
async function applyFlightResponse(response, address, binding) {
const rootId = response.headers.get(FRAME_STREAM_HEADER) ?? "";
const as = rootId ? entry.frameId : undefined;
const as = rootId ? address : undefined;
let feed;

@@ -1387,6 +1316,2 @@ const source = new ReadableStream({

as,
route: id => {
const local = byAddress.get(id);
return local ? local.frameId : id;
},
version: frameId => {

@@ -1412,3 +1337,3 @@ const version = bump(frameId);

}
return rootId ? entry.component : envelope.value;
return rootId ? binding : envelope.value;
}

@@ -1592,11 +1517,3 @@ }

if (ctx && ctx.range) {
let claim = adopted;
const source = value;
const accessor = () => {
if (claim) {
claim = false;
return claimRender(prefix, ctx.existing, () => typeof source === "function" ? source() : source);
}
return typeof source === "function" ? source() : source;
};
const owner = createOwner();

@@ -1609,3 +1526,4 @@ bindings.set(key, owner);

const end = ctx.range.end;
runWithOwner(owner, () => insert(end.parentNode, accessor, end, [...ctx.existing]));
const bind = () => insert(end.parentNode, () => typeof source === "function" ? source() : source, end, [...ctx.existing]);
runWithOwner(owner, () => adopted ? claimRender(prefix, ctx.existing, bind) : bind());
return undefined;

@@ -1624,11 +1542,15 @@ }

}
function boundaryComponent(host, id) {
return props => {
function followBinding(frame, binding) {
createRenderEffect(binding, address => frame.rebind(address));
}
function boundaryComponent(host, fnId) {
return (props, binding) => {
const owner = getOwner();
const {
element,
frame,
dispose
} = createFrameElement({
host,
id,
id: binding ? binding() : fnId,
slots: slotsFor(props),

@@ -1638,2 +1560,3 @@ ownerScope: boundaryScope(owner),

});
if (binding) followBinding(frame, binding);
onCleanup(dispose);

@@ -1660,47 +1583,61 @@ return element;

const boundaryWaiters = new Map();
function documentStreaming() {
function boundaryMayArrive() {
const hy = globalThis._$HY;
return !!hy && !hy.done;
if (!hy) return false;
return !hy.done || !!(hy.fr && hy.fr.pending());
}
function installRevealHook() {
const hy = globalThis._$HY;
if (!hy || hy.$sc) return;
if (!hy || hy.$sc || !hy.fr) return;
hy.$sc = true;
const prev = hy.fe;
hy.fe = (fragmentId, parent) => {
if (prev) prev(fragmentId, parent);
hy.fr.subscribe((_id, parent) => {
if (!boundaryIndex) return;
const root = parent || (typeof document !== "undefined" ? document.body : null);
if (!root) return;
indexBoundaries(root);
if (root) indexBoundaries(root);
if (!boundaryWaiters.size) return;
const exhausted = hy.done && !hy.fr.pending();
for (const [id, notify] of boundaryWaiters) {
const el = boundaryIndex.get(id);
if (!el) continue;
const el = boundaryIndex && boundaryIndex.get(id);
if (!el && !exhausted) continue;
boundaryWaiters.delete(id);
notify(el);
}
};
});
}
function documentBoundary(host, id, props) {
function documentBoundary(host, id, props, binding) {
installRevealHook();
const claimed = claimedBoundaries.has(id);
const el = !claimed ? findBoundaryElement(id) : undefined;
if (el) return adoptBoundary(host, id, el, props);
if (!claimed && !boundaryWaiters.has(id) && documentStreaming()) {
if (el) return adoptBoundary(host, id, el, props, binding);
if (!claimed && !boundaryWaiters.has(id) && boundaryMayArrive()) {
const owner = getOwner();
const arrival = new Promise(resolve => boundaryWaiters.set(id, resolve));
onCleanup(() => boundaryWaiters.delete(id));
return createMemo(() => arrival.then(node => runWithOwner(owner, () => adoptBoundary(host, id, node, props))));
return createMemo(() => arrival.then(node => runWithOwner(owner, () =>
node ? adoptBoundary(host, id, node, props, binding) : boundaryComponent(host, id)(props, binding))));
}
return boundaryComponent(host, id)(props);
return boundaryComponent(host, id)(props, binding);
}
function adoptBoundary(host, id, el, props) {
function documentAddress(id) {
const records = globalThis._$SC?.a;
if (records) {
for (const address in records) if (records[address] === id) return address;
}
return id;
}
function adoptBoundary(host, id, el, props, binding) {
claimedBoundaries.add(id);
const hy = globalThis._$HY;
if (hy && hy.r) {
const address = binding ? binding() : documentAddress(id);
const appliedRecords = new Set();
const drainRecords = () => {
const hy = globalThis._$HY;
if (!hy || !hy.r) return;
const slotPrefix = `sc:slot:${id}:`;
for (const key of Object.keys(hy.r)) {
if (appliedRecords.has(key)) continue;
if (key.startsWith(slotPrefix)) {
appliedRecords.add(key);
host.apply({
type: "slot",
id,
id: address,
version: 0,

@@ -1713,2 +1650,3 @@ key: key.slice(slotPrefix.length),

if (childId.startsWith(id + ".")) {
appliedRecords.add(key);
const val = hy.r[key];

@@ -1725,3 +1663,4 @@ const apply = html => host.apply({

}
}
};
drainRecords();
const owner = getOwner();

@@ -1731,7 +1670,17 @@ const frame = createFrame(el, {

host,
id,
id: address,
slots: slotsFor(props),
ownerScope: boundaryScope(owner),
reveal: revealSeam(owner)
reveal: revealSeam(owner),
...{
recordsPending: () => {
if (document.readyState === "loading") return true;
const hy = globalThis._$HY;
return !!(hy && hy.fr && hy.fr.pending());
},
drainRecords,
claimScope: id
}
});
if (binding) followBinding(frame, binding);
onCleanup(() => frame.dispose());

@@ -1751,13 +1700,12 @@ return el;

}
return g._$SC.c[i] || (g._$SC.c[i] = p => g._$SC.impl(i, p));
return g._$SC.c[i] || (g._$SC.c[i] = (p, b) => g._$SC.impl(i, p, b));
}
};
}
g._$SC.impl = (id, props) => documentBoundary(host, id, props);
g._$SC.impl = (id, props, binding) => documentBoundary(host, id, props, binding);
installRevealHook();
const handler = createServerComponentHandler({
host,
component: frameId => boundaryComponent(host, frameId),
onStream: frameId => beginStream(frameId),
documentComponent: functionId => claimedBoundaries.has(functionId) ? undefined : g._$SC.c[functionId],
component: fnId => g._$SC.r(fnId),
onStream: address => beginStream(address),
intercept: ({

@@ -1770,3 +1718,3 @@ id

});
const showing = (address, id) => handler.showing(address, id, g._$SC.r(id));
const showing = (address, id) => handler.showing(address, id);
const records = g._$SC.a || (g._$SC.a = {});

@@ -1773,0 +1721,0 @@ for (const address in records) showing(address, records[address]);

{
"name": "@solidjs/web",
"description": "Solid's web runtime: client rendering, hydration, SSR, and DOM-specific control flow (Portal, Dynamic).",
"version": "2.0.0-beta.30",
"version": "2.0.0-beta.31",
"author": "Ryan Carniato",

@@ -319,6 +319,6 @@ "license": "MIT",

"peerDependencies": {
"solid-js": "^2.0.0-beta.30"
"solid-js": "^2.0.0-beta.31"
},
"devDependencies": {
"solid-js": "2.0.0-beta.30"
"solid-js": "2.0.0-beta.31"
},

@@ -346,5 +346,4 @@ "scripts": {

"bench:server": "vitest bench --run --config vite.config.server-bench.mjs",
"test-types": "npm-run-all -nl types test-types:tsc",
"test-types:tsc": "tsc --project tsconfig.test.json"
"test-types": "tsc --project tsconfig.test.json"
}
}

@@ -146,8 +146,10 @@ import { JSX } from "./jsx.cjs";

* Registers head tags with the ambient head registry under the current
* owner. An array is a group — one replacement set. Resolution is
* last-committed group per identity; disposal restores the previous winner.
* During hydration the server-flushed head state stays authoritative until
* hydration completes. See docs/head-management-rfc.md.
* owner. An array is a group — one replacement set; a function is a
* reactive group whose membership is tracked and re-read on change.
* Resolution is last-committed group per identity (reactive updates keep
* the registration's original commit position); disposal restores the
* previous winner. During hydration the server-flushed head state stays
* authoritative until hydration completes. See docs/head-management-rfc.md.
*/
export function useHead(tag: HeadTag | HeadTag[]): void;
export function useHead(tag: HeadTag | HeadTag[] | (() => HeadTag | HeadTag[])): void;
export type AssetDescriptor =

@@ -154,0 +156,0 @@ | { type: "style"; href: string; attrs?: Record<string, string> }

@@ -8,9 +8,11 @@ export { createFrame, createFrameHost, createFrameElement, FRAME_APPLIED_EVENT } from "./frame-client.cjs";

* Installs the server-component transport policy on the server-function
* client: boundary identity is the call's intrinsic (function, arguments)
* address — per-args, exactly like the query cache, so a cached component
* always mounts the boundary showing the call it was cached for. Repeat
* calls for the same args resolve the identical component (refetches morph
* in place, cache hits pass `dynamic`'s equals-gate); a source switching
* args swaps boundaries, re-materialized instantly from the host's
* retained state.
* client — the identity split (DR-1): CONTENT is keyed by the call's
* intrinsic (function, arguments) address — per-args, exactly like the
* query cache, so a cached resolution always names the content it was
* cached for — while the MOUNT belongs to the call site. Every call of a
* function resolves a binding wrapping the same per-function component
* (the document placeholder), so `dynamic` keeps its instance across both
* refetches AND argument changes; the instance follows delivered addresses
* by re-binding its frame's pull, and a preload for unshown args only ever
* warms that address's resident store.
*

@@ -17,0 +19,0 @@ * Call once in the client entry (an explicit call — the package is

@@ -242,2 +242,14 @@ /**

reveal?(seam: { before: Node; fallback: Node[]; content: () => Node | DocumentFragment }): void;
/**
* Document-face record-race guard (adopt path only — solidjs/solid#2968).
* Nothing on the wire formally orders an occurrence's args-record data
* script before the event that triggers adoption, so a recordless
* occurrence is ambiguous while this returns true: the frame defers its
* mount one macrotask (all currently parsed scripts run first), calls
* `drainRecords`, and classifies with whatever is then resolvable. Return
* false once the document can run no further data scripts.
*/
recordsPending?(): boolean;
/** Re-absorb the document's arrived-by-now records (idempotent per key). */
drainRecords?(): void;
}

@@ -244,0 +256,0 @@

@@ -164,6 +164,9 @@ import { FrameChunk } from "./frame-client.cjs";

/**
* Inline bootstrap for the document shell: installs the `self._$SC`
* placeholder registry the hydration references resolve through; the client
* upgrades it via `installServerComponents()`.
* Statement form of the `self._$SC` placeholder-registry bootstrap
* (idempotent — first definition wins). No longer required in the document
* shell: each hydration script's first serialized server-component reference
* self-bootstraps the registry. Kept for integrations still installing it
* document-wide; the client upgrades the registry via
* `installServerComponents()`.
*/
export const SERVER_COMPONENT_BOOTSTRAP: string;

@@ -40,8 +40,2 @@ import { FrameChunk, FrameHost } from "./frame-client.cjs";

/**
* Remap any frame id other than the response's own root onto a local one
* — how a consumer resolves the addresses a single-flight response uses
* for the regions it refreshed.
*/
route?(id: string): string;
/**
* Receives the payload text of each `outcome` chunk — the response-scoped

@@ -84,25 +78,18 @@ * single-flight envelope, the caller's result rather than anything the

/**
* The handoff contract on components the transport resolves: `{ fnId,
* frameId, take(prev) }`. A reader whose source resolved a NEW component
* while a previous one is mounted offers the old one — `take` rebinds the
* live mount when both are boundaries of the same function (the element and
* its slot state stay; the incoming stream morphs it), and the reader keeps
* its previous value instead of remounting. `Symbol.for`, so frameworks can
* honor it without importing this module.
* The binding brand on values the transport resolves: `{ component, address }`
* — the identity split (DR-1). `component` is the mount identity, one per
* server function; `address` names the call's content store. An equals-gated
* reader compares `component` across resolutions: same function means "same
* instance, new binding" — keep the mounted instance and deliver the new
* address into it; a different function swaps normally. `Symbol.for`, so
* frameworks can honor it without importing this module.
*/
export const COMPONENT_HANDOFF: unique symbol;
export const COMPONENT_BINDING: unique symbol;
/** The value under `COMPONENT_HANDOFF` on a transport-resolved component. */
export interface ComponentHandoff {
/** The server function id both peers derive the boundary's calls from. */
fnId: string;
/** The frame id this component's fresh mounts register under. */
frameId: string;
/**
* Offer `prev` (the reader's current value) to this component. Returns
* true when the reader should KEEP prev — the mounted frame was rebound
* to this component's id (or already showed it); false means swap
* normally (different function, unbranded prev, or nothing mounted).
*/
take(prev: unknown): boolean;
/** The value under `COMPONENT_BINDING` on a transport-resolved binding. */
export interface ComponentBinding<C = unknown> {
/** The per-function mount component (the equals-gate identity). */
component: C;
/** The call's intrinsic (function, arguments) address — its store's key. */
address: string;
}

@@ -120,2 +107,12 @@

/**
* Installs the hydration-serializer registry prefix: given the emitted
* script's serializer context, returns the expression the next serialized
* reference reads the `_$SC` registry through (the self-bootstrapping form
* on a script's first reference, a bare read after). Loaded document-SSR
* modules install this (see frame-sink); client bundles never carry the
* bootstrap text.
*/
export function setServerComponentBootstrap(resolve: (ctx: unknown) => string): void;
/**
* The codec options for a single-flight envelope: `codec` plus

@@ -131,21 +128,17 @@ * `ServerComponentPlugin` (deduped by tag). Injected by the protocol on both

/**
* Builds the framework's mountable component for a boundary. Invoked once
* per boundary and cached; every mount of the returned component is its
* own frame instance under the boundary id (multi-mount fans out).
* Builds the framework's mount component for a server FUNCTION. Invoked
* once per function and cached — this is the equals-gate identity every
* call of the function resolves through. The component is CALLED (by the
* binding wrapper or a gated reader), receiving its current address as a
* second argument (`() => string`); it should (re-)bind its frame's pull
* to that address's store. Multi-mount fans out per site.
*/
component(frameId: string): C;
component(fnId: string): C;
/**
* A new response is about to stream into a boundary: rotate
* A new response is about to stream into an address: rotate
* response-scoped state (codec data tables) here. `version` is the
* client-owned stream counter the chunks will be stamped with.
*/
onStream?(frameId: string, version: number, response: Response): void;
onStream?(address: string, version: number, response: Response): void;
/**
* Document-SSR adoption: given a boundary id the page already carries
* (server-rendered between `frame:<id>` markers), return the component
* that adopts that range — or `undefined` to stream normally. Consulted
* once per boundary, before any fetch.
*/
documentComponent?(frameId: string): C | undefined;
/**
* Answer a call SYNCHRONOUSLY before any request is made (t = 0 local

@@ -174,28 +167,29 @@ * answers — e.g. a boundary the document already carries). Returning a

* client's `responseHandler` seam: frame-stream responses resolve the call
* with a **stable component** instead of data, so an equals-gated consumer
* (Solid's `dynamic`) never remounts across refetches — the response streams
* into the boundary underneath as the only observable effect.
* with a **binding** — a callable wrapper branded `COMPONENT_BINDING` — so
* an equals-gated consumer (Solid's `dynamic`) never remounts across
* refetches or argument changes; the response streams into the address's
* resident store as the only observable effect.
*
* Boundary identity is derived, never declared: every call keys by its
* intrinsic (function, arguments) address — the query cache's per-args rule,
* so cached components and boundaries stay one-to-one. Same-args calls
* resolve the identical component and morph in place; an args switch swaps
* boundaries, re-materialized from the host's retained state.
* The identity split (DR-1): stores are keyed per-ADDRESS — the call's
* intrinsic (function, arguments) name, one-to-one with a query cache's
* per-args entries — while mounts are per-SITE, rendering the per-function
* component and following delivered addresses. An address nothing is bound
* to warms its store (preload isolation is the default, not a rule).
*/
export function createServerComponentHandler<C>(options: ServerComponentHandlerOptions<C>): {
intercept?(info: { id: string; meta: unknown; args: unknown[] }): C | undefined;
intercept?(info: { id: string; meta: unknown; args: unknown[] }): unknown;
handle(
response: Response,
ctx: { id: string; meta: unknown; args: unknown[]; context: unknown }
): C | undefined;
): unknown;
/**
* Declares that the document is showing a call: hydration-data references
* carry their call's address (`_$SC.r(id, address)`) but never travel
* through the transport, so the integration forwards those records here —
* they are how a post-load call for the same (function, arguments) finds
* its way back to the adopted boundary. `component` must be the exact
* reference the integration's cache holds for the call (the per-function
* placeholder), or readers' equals-gates fail into remounts.
* through the transport, so the integration forwards those records here.
* Mints the call's binding (a post-load refetch then resolves a value
* whose component matches what the document mounted) and brands the
* per-function component so cache-seeded readers deliver instead of
* remounting when their site later switches calls.
*/
showing(address: string, functionId: string, component: C): void;
showing(address: string, functionId: string): void;
};

@@ -179,9 +179,11 @@ import { JSX } from "./jsx.cjs";

* Registers head tags with the render's head registry. An array is a group —
* one replacement set; a single tag is a group of one. Replaceable tags
* (title/meta/canonical/…) resolve by last-committed group and stream as
* patches with their suspense boundary's reveal; resource tags (preload and
* friends, stylesheets, `script[src]`) emit eagerly and dedupe by identity.
* See docs/head-management-rfc.md.
* one replacement set; a single tag is a group of one; a function is a
* reactive group whose membership resolves at the owning flush boundary
* (resource tags inside it emit at that flush rather than eagerly).
* Replaceable tags (title/meta/canonical/…) resolve by last-committed group
* and stream as patches with their suspense boundary's reveal; resource tags
* (preload and friends, stylesheets, `script[src]`) emit eagerly and dedupe
* by identity. See docs/head-management-rfc.md.
*/
export function useHead(tag: HeadTag | HeadTag[]): void;
export function useHead(tag: HeadTag | HeadTag[] | (() => HeadTag | HeadTag[])): void;
export function getHydrationKey(): string | undefined;

@@ -188,0 +190,0 @@ export function effect<T>(fn: (prev?: T) => T, effect: (value: T, prev?: T) => void): void;

@@ -146,8 +146,10 @@ import { JSX } from "./jsx.js";

* Registers head tags with the ambient head registry under the current
* owner. An array is a group — one replacement set. Resolution is
* last-committed group per identity; disposal restores the previous winner.
* During hydration the server-flushed head state stays authoritative until
* hydration completes. See docs/head-management-rfc.md.
* owner. An array is a group — one replacement set; a function is a
* reactive group whose membership is tracked and re-read on change.
* Resolution is last-committed group per identity (reactive updates keep
* the registration's original commit position); disposal restores the
* previous winner. During hydration the server-flushed head state stays
* authoritative until hydration completes. See docs/head-management-rfc.md.
*/
export function useHead(tag: HeadTag | HeadTag[]): void;
export function useHead(tag: HeadTag | HeadTag[] | (() => HeadTag | HeadTag[])): void;
export type AssetDescriptor =

@@ -154,0 +156,0 @@ | { type: "style"; href: string; attrs?: Record<string, string> }

@@ -8,9 +8,11 @@ export { createFrame, createFrameHost, createFrameElement, FRAME_APPLIED_EVENT } from "./frame-client.js";

* Installs the server-component transport policy on the server-function
* client: boundary identity is the call's intrinsic (function, arguments)
* address — per-args, exactly like the query cache, so a cached component
* always mounts the boundary showing the call it was cached for. Repeat
* calls for the same args resolve the identical component (refetches morph
* in place, cache hits pass `dynamic`'s equals-gate); a source switching
* args swaps boundaries, re-materialized instantly from the host's
* retained state.
* client — the identity split (DR-1): CONTENT is keyed by the call's
* intrinsic (function, arguments) address — per-args, exactly like the
* query cache, so a cached resolution always names the content it was
* cached for — while the MOUNT belongs to the call site. Every call of a
* function resolves a binding wrapping the same per-function component
* (the document placeholder), so `dynamic` keeps its instance across both
* refetches AND argument changes; the instance follows delivered addresses
* by re-binding its frame's pull, and a preload for unshown args only ever
* warms that address's resident store.
*

@@ -17,0 +19,0 @@ * Call once in the client entry (an explicit call — the package is

@@ -242,2 +242,14 @@ /**

reveal?(seam: { before: Node; fallback: Node[]; content: () => Node | DocumentFragment }): void;
/**
* Document-face record-race guard (adopt path only — solidjs/solid#2968).
* Nothing on the wire formally orders an occurrence's args-record data
* script before the event that triggers adoption, so a recordless
* occurrence is ambiguous while this returns true: the frame defers its
* mount one macrotask (all currently parsed scripts run first), calls
* `drainRecords`, and classifies with whatever is then resolvable. Return
* false once the document can run no further data scripts.
*/
recordsPending?(): boolean;
/** Re-absorb the document's arrived-by-now records (idempotent per key). */
drainRecords?(): void;
}

@@ -244,0 +256,0 @@

@@ -164,6 +164,9 @@ import { FrameChunk } from "./frame-client.js";

/**
* Inline bootstrap for the document shell: installs the `self._$SC`
* placeholder registry the hydration references resolve through; the client
* upgrades it via `installServerComponents()`.
* Statement form of the `self._$SC` placeholder-registry bootstrap
* (idempotent — first definition wins). No longer required in the document
* shell: each hydration script's first serialized server-component reference
* self-bootstraps the registry. Kept for integrations still installing it
* document-wide; the client upgrades the registry via
* `installServerComponents()`.
*/
export const SERVER_COMPONENT_BOOTSTRAP: string;

@@ -40,8 +40,2 @@ import { FrameChunk, FrameHost } from "./frame-client.js";

/**
* Remap any frame id other than the response's own root onto a local one
* — how a consumer resolves the addresses a single-flight response uses
* for the regions it refreshed.
*/
route?(id: string): string;
/**
* Receives the payload text of each `outcome` chunk — the response-scoped

@@ -84,25 +78,18 @@ * single-flight envelope, the caller's result rather than anything the

/**
* The handoff contract on components the transport resolves: `{ fnId,
* frameId, take(prev) }`. A reader whose source resolved a NEW component
* while a previous one is mounted offers the old one — `take` rebinds the
* live mount when both are boundaries of the same function (the element and
* its slot state stay; the incoming stream morphs it), and the reader keeps
* its previous value instead of remounting. `Symbol.for`, so frameworks can
* honor it without importing this module.
* The binding brand on values the transport resolves: `{ component, address }`
* — the identity split (DR-1). `component` is the mount identity, one per
* server function; `address` names the call's content store. An equals-gated
* reader compares `component` across resolutions: same function means "same
* instance, new binding" — keep the mounted instance and deliver the new
* address into it; a different function swaps normally. `Symbol.for`, so
* frameworks can honor it without importing this module.
*/
export const COMPONENT_HANDOFF: unique symbol;
export const COMPONENT_BINDING: unique symbol;
/** The value under `COMPONENT_HANDOFF` on a transport-resolved component. */
export interface ComponentHandoff {
/** The server function id both peers derive the boundary's calls from. */
fnId: string;
/** The frame id this component's fresh mounts register under. */
frameId: string;
/**
* Offer `prev` (the reader's current value) to this component. Returns
* true when the reader should KEEP prev — the mounted frame was rebound
* to this component's id (or already showed it); false means swap
* normally (different function, unbranded prev, or nothing mounted).
*/
take(prev: unknown): boolean;
/** The value under `COMPONENT_BINDING` on a transport-resolved binding. */
export interface ComponentBinding<C = unknown> {
/** The per-function mount component (the equals-gate identity). */
component: C;
/** The call's intrinsic (function, arguments) address — its store's key. */
address: string;
}

@@ -120,2 +107,12 @@

/**
* Installs the hydration-serializer registry prefix: given the emitted
* script's serializer context, returns the expression the next serialized
* reference reads the `_$SC` registry through (the self-bootstrapping form
* on a script's first reference, a bare read after). Loaded document-SSR
* modules install this (see frame-sink); client bundles never carry the
* bootstrap text.
*/
export function setServerComponentBootstrap(resolve: (ctx: unknown) => string): void;
/**
* The codec options for a single-flight envelope: `codec` plus

@@ -131,21 +128,17 @@ * `ServerComponentPlugin` (deduped by tag). Injected by the protocol on both

/**
* Builds the framework's mountable component for a boundary. Invoked once
* per boundary and cached; every mount of the returned component is its
* own frame instance under the boundary id (multi-mount fans out).
* Builds the framework's mount component for a server FUNCTION. Invoked
* once per function and cached — this is the equals-gate identity every
* call of the function resolves through. The component is CALLED (by the
* binding wrapper or a gated reader), receiving its current address as a
* second argument (`() => string`); it should (re-)bind its frame's pull
* to that address's store. Multi-mount fans out per site.
*/
component(frameId: string): C;
component(fnId: string): C;
/**
* A new response is about to stream into a boundary: rotate
* A new response is about to stream into an address: rotate
* response-scoped state (codec data tables) here. `version` is the
* client-owned stream counter the chunks will be stamped with.
*/
onStream?(frameId: string, version: number, response: Response): void;
onStream?(address: string, version: number, response: Response): void;
/**
* Document-SSR adoption: given a boundary id the page already carries
* (server-rendered between `frame:<id>` markers), return the component
* that adopts that range — or `undefined` to stream normally. Consulted
* once per boundary, before any fetch.
*/
documentComponent?(frameId: string): C | undefined;
/**
* Answer a call SYNCHRONOUSLY before any request is made (t = 0 local

@@ -174,28 +167,29 @@ * answers — e.g. a boundary the document already carries). Returning a

* client's `responseHandler` seam: frame-stream responses resolve the call
* with a **stable component** instead of data, so an equals-gated consumer
* (Solid's `dynamic`) never remounts across refetches — the response streams
* into the boundary underneath as the only observable effect.
* with a **binding** — a callable wrapper branded `COMPONENT_BINDING` — so
* an equals-gated consumer (Solid's `dynamic`) never remounts across
* refetches or argument changes; the response streams into the address's
* resident store as the only observable effect.
*
* Boundary identity is derived, never declared: every call keys by its
* intrinsic (function, arguments) address — the query cache's per-args rule,
* so cached components and boundaries stay one-to-one. Same-args calls
* resolve the identical component and morph in place; an args switch swaps
* boundaries, re-materialized from the host's retained state.
* The identity split (DR-1): stores are keyed per-ADDRESS — the call's
* intrinsic (function, arguments) name, one-to-one with a query cache's
* per-args entries — while mounts are per-SITE, rendering the per-function
* component and following delivered addresses. An address nothing is bound
* to warms its store (preload isolation is the default, not a rule).
*/
export function createServerComponentHandler<C>(options: ServerComponentHandlerOptions<C>): {
intercept?(info: { id: string; meta: unknown; args: unknown[] }): C | undefined;
intercept?(info: { id: string; meta: unknown; args: unknown[] }): unknown;
handle(
response: Response,
ctx: { id: string; meta: unknown; args: unknown[]; context: unknown }
): C | undefined;
): unknown;
/**
* Declares that the document is showing a call: hydration-data references
* carry their call's address (`_$SC.r(id, address)`) but never travel
* through the transport, so the integration forwards those records here —
* they are how a post-load call for the same (function, arguments) finds
* its way back to the adopted boundary. `component` must be the exact
* reference the integration's cache holds for the call (the per-function
* placeholder), or readers' equals-gates fail into remounts.
* through the transport, so the integration forwards those records here.
* Mints the call's binding (a post-load refetch then resolves a value
* whose component matches what the document mounted) and brands the
* per-function component so cache-seeded readers deliver instead of
* remounting when their site later switches calls.
*/
showing(address: string, functionId: string, component: C): void;
showing(address: string, functionId: string): void;
};

@@ -179,9 +179,11 @@ import { JSX } from "./jsx.js";

* Registers head tags with the render's head registry. An array is a group —
* one replacement set; a single tag is a group of one. Replaceable tags
* (title/meta/canonical/…) resolve by last-committed group and stream as
* patches with their suspense boundary's reveal; resource tags (preload and
* friends, stylesheets, `script[src]`) emit eagerly and dedupe by identity.
* See docs/head-management-rfc.md.
* one replacement set; a single tag is a group of one; a function is a
* reactive group whose membership resolves at the owning flush boundary
* (resource tags inside it emit at that flush rather than eagerly).
* Replaceable tags (title/meta/canonical/…) resolve by last-committed group
* and stream as patches with their suspense boundary's reveal; resource tags
* (preload and friends, stylesheets, `script[src]`) emit eagerly and dedupe
* by identity. See docs/head-management-rfc.md.
*/
export function useHead(tag: HeadTag | HeadTag[]): void;
export function useHead(tag: HeadTag | HeadTag[] | (() => HeadTag | HeadTag[])): void;
export function getHydrationKey(): string | undefined;

@@ -188,0 +190,0 @@ export function effect<T>(fn: (prev?: T) => T, effect: (value: T, prev?: T) => void): void;

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display