@solidjs/web 2.0.0-beta.3 → 2.0.0-beta.30

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/README.md +27 -4
  2. package/dist/dev.cjs +1211 -205
  3. package/dist/dev.js +1175 -199
  4. package/dist/server.cjs +1342 -234
  5. package/dist/server.js +1304 -231
  6. package/dist/web.cjs +1195 -196
  7. package/dist/web.js +1159 -190
  8. package/frames/dist/client.cjs +1746 -0
  9. package/frames/dist/client.dev.cjs +1759 -0
  10. package/frames/dist/client.dev.js +1747 -0
  11. package/frames/dist/client.js +1734 -0
  12. package/frames/dist/server.cjs +2426 -0
  13. package/frames/dist/server.js +2414 -0
  14. package/frames/package.json +30 -0
  15. package/package.json +287 -38
  16. package/serialization/dist/serialization.cjs +169 -0
  17. package/serialization/dist/serialization.js +159 -0
  18. package/serialization/package.json +20 -0
  19. package/serialization/types/index.d.ts +157 -0
  20. package/serialization/types-cjs/index.d.cts +157 -0
  21. package/serialization/types-cjs/package.json +3 -0
  22. package/server-functions/dist/client.cjs +613 -0
  23. package/server-functions/dist/client.js +585 -0
  24. package/server-functions/dist/server.cjs +904 -0
  25. package/server-functions/dist/server.js +875 -0
  26. package/server-functions/package.json +30 -0
  27. package/storage/package.json +8 -3
  28. package/storage/types/index.d.ts +26 -0
  29. package/storage/types-cjs/index.d.cts +28 -0
  30. package/storage/types-cjs/package.json +3 -0
  31. package/types/client.d.ts +125 -21
  32. package/types/core.d.ts +4 -3
  33. package/types/frames/client.d.ts +20 -0
  34. package/types/frames/frame-client.d.ts +270 -0
  35. package/types/frames/frame-sink.d.ts +168 -0
  36. package/types/frames/frame-transport.d.ts +196 -0
  37. package/types/frames/serializer.d.ts +157 -0
  38. package/types/frames/server.d.ts +30 -0
  39. package/types/index.d.ts +211 -26
  40. package/types/jsx-properties.d.ts +93 -0
  41. package/types/jsx.d.ts +4150 -1
  42. package/types/response.d.ts +129 -0
  43. package/types/serializer.d.ts +157 -0
  44. package/types/server-functions/client.d.ts +200 -0
  45. package/types/server-functions/flash.d.ts +38 -0
  46. package/types/server-functions/server.d.ts +490 -0
  47. package/types/server-functions/shared.d.ts +445 -0
  48. package/types/server-mock.d.ts +93 -0
  49. package/types/server.d.ts +221 -28
  50. package/types-cjs/client.d.cts +192 -0
  51. package/types-cjs/core.d.cts +4 -0
  52. package/types-cjs/frames/client.d.cts +20 -0
  53. package/types-cjs/frames/frame-client.d.cts +270 -0
  54. package/types-cjs/frames/frame-sink.d.cts +168 -0
  55. package/types-cjs/frames/frame-transport.d.cts +196 -0
  56. package/types-cjs/frames/serializer.d.cts +157 -0
  57. package/types-cjs/frames/server.d.cts +30 -0
  58. package/types-cjs/index.d.cts +231 -0
  59. package/types-cjs/jsx-properties.d.cts +93 -0
  60. package/types-cjs/jsx.d.cts +4150 -0
  61. package/types-cjs/package.json +3 -0
  62. package/types-cjs/response.d.cts +129 -0
  63. package/types-cjs/serializer.d.cts +157 -0
  64. package/types-cjs/server-functions/client.d.cts +200 -0
  65. package/types-cjs/server-functions/flash.d.cts +38 -0
  66. package/types-cjs/server-functions/server.d.cts +490 -0
  67. package/types-cjs/server-functions/shared.d.cts +445 -0
  68. package/types-cjs/server-mock.d.cts +165 -0
  69. package/types-cjs/server.d.cts +349 -0
  70. package/storage/types/src/client.d.ts +0 -1
  71. package/storage/types/src/index.d.ts +0 -46
  72. package/storage/types/src/server-mock.d.ts +0 -72
  73. package/storage/types/storage/src/index.d.ts +0 -2
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@solidjs/web/server-functions",
3
+ "main": "./dist/server.cjs",
4
+ "module": "./dist/server.js",
5
+ "types": "../types/server-functions/server.d.ts",
6
+ "type": "module",
7
+ "sideEffects": false,
8
+ "exports": {
9
+ ".": {
10
+ "browser": {
11
+ "import": {
12
+ "types": "../types/server-functions/client.d.ts",
13
+ "default": "./dist/client.js"
14
+ },
15
+ "require": {
16
+ "types": "../types-cjs/server-functions/client.d.cts",
17
+ "default": "./dist/client.cjs"
18
+ }
19
+ },
20
+ "import": {
21
+ "types": "../types/server-functions/server.d.ts",
22
+ "default": "./dist/server.js"
23
+ },
24
+ "require": {
25
+ "types": "../types-cjs/server-functions/server.d.cts",
26
+ "default": "./dist/server.cjs"
27
+ }
28
+ }
29
+ }
30
+ }
@@ -7,9 +7,14 @@
7
7
  "sideEffects": false,
8
8
  "exports": {
9
9
  ".": {
10
- "types": "./types/index.d.ts",
11
- "import": "./dist/storage.js",
12
- "require": "./dist/storage.cjs"
10
+ "import": {
11
+ "types": "./types/index.d.ts",
12
+ "default": "./dist/storage.js"
13
+ },
14
+ "require": {
15
+ "types": "./types-cjs/index.d.cts",
16
+ "default": "./dist/storage.cjs"
17
+ }
13
18
  }
14
19
  }
15
20
  }
@@ -1,2 +1,28 @@
1
1
  import type { RequestEvent } from "@solidjs/web";
2
+ /**
3
+ * Establishes the request-event scope for a server request: everything
4
+ * `cb` runs (across `await`s, via AsyncLocalStorage) sees `init` from
5
+ * `getRequestEvent()`. Call it at the top of the server's request handling,
6
+ * wrapping SSR and server-function dispatch; the server-functions runtime
7
+ * also picks the scope up automatically as its default event provider.
8
+ *
9
+ * Lives on its own subpath because it imports `node:async_hooks` — keep it
10
+ * out of environments without that module.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { provideRequestEvent } from "@solidjs/web/storage";
15
+ *
16
+ * async function handler(request: Request) {
17
+ * return provideRequestEvent({ request, locals: {} }, () =>
18
+ * renderToStringAsync(() => <App />)
19
+ * );
20
+ * }
21
+ * ```
22
+ *
23
+ * @param init the event for this request — frameworks pass their richer
24
+ * event shapes
25
+ * @param cb runs synchronously; its return value is passed through
26
+ * @throws on the client, where there is no request to scope
27
+ */
2
28
  export declare function provideRequestEvent<T extends RequestEvent, U>(init: T, cb: () => U): U;
@@ -0,0 +1,28 @@
1
+ import type { RequestEvent } from "@solidjs/web";
2
+ /**
3
+ * Establishes the request-event scope for a server request: everything
4
+ * `cb` runs (across `await`s, via AsyncLocalStorage) sees `init` from
5
+ * `getRequestEvent()`. Call it at the top of the server's request handling,
6
+ * wrapping SSR and server-function dispatch; the server-functions runtime
7
+ * also picks the scope up automatically as its default event provider.
8
+ *
9
+ * Lives on its own subpath because it imports `node:async_hooks` — keep it
10
+ * out of environments without that module.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * import { provideRequestEvent } from "@solidjs/web/storage";
15
+ *
16
+ * async function handler(request: Request) {
17
+ * return provideRequestEvent({ request, locals: {} }, () =>
18
+ * renderToStringAsync(() => <App />)
19
+ * );
20
+ * }
21
+ * ```
22
+ *
23
+ * @param init the event for this request — frameworks pass their richer
24
+ * event shapes
25
+ * @param cb runs synchronously; its return value is passed through
26
+ * @throws on the client, where there is no request to scope
27
+ */
28
+ export declare function provideRequestEvent<T extends RequestEvent, U>(init: T, cb: () => U): U;
@@ -0,0 +1,3 @@
1
+ {
2
+ "type": "commonjs"
3
+ }
package/types/client.d.ts CHANGED
@@ -1,10 +1,13 @@
1
1
  import { JSX } from "./jsx.js";
2
- export const Properties: Set<string>;
2
+ export const DOMWithState: Record<string, Record<string, 1 | 2>>;
3
3
  export const ChildProperties: Set<string>;
4
4
  export const DelegatedEvents: Set<string>;
5
5
  export const DOMElements: Set<string>;
6
6
  export const SVGElements: Set<string>;
7
- export const SVGNamespace: Record<string, string>;
7
+ export const MathMLElements: Set<string>;
8
+ export const VoidElements: Set<string>;
9
+ export const RawTextElements: Set<string>;
10
+ export const Namespaces: Record<string, string>;
8
11
 
9
12
  type MountableElement = Element | Document | ShadowRoot | DocumentFragment | Node;
10
13
  export function render(
@@ -13,42 +16,86 @@ export function render(
13
16
  init?: JSX.Element,
14
17
  options?: { owner?: unknown }
15
18
  ): () => void;
16
- export function template(html: string, isImportNode?: boolean, isSVG?: boolean, isMathML?: boolean): () => Element;
17
- export function effect<T>(fn: (prev?: T) => T, effect: (value: T, prev?: T) => void, init?: T): void;
19
+ /**
20
+ * @param flag
21
+ * - `undefined` — clone the template as-is (uses `cloneNode`).
22
+ * - `1` — use `document.importNode` instead of `cloneNode`.
23
+ * - `2` — the template html is wrapped; the outer tag is stripped at clone time.
24
+ */
25
+ export function template(html: string, flag?: 1 | 2): () => Element;
26
+ export function scope<T extends () => any>(fn: T): T;
27
+ export function effect<T>(fn: (prev?: T) => T, effect: (value: T, prev?: T) => void): void;
18
28
  export function memo<T>(fn: () => T, equal: boolean): () => T;
19
29
  export function untrack<T>(fn: () => T): T;
20
30
  export function insert<T>(
21
31
  parent: MountableElement,
22
32
  accessor: (() => T) | T,
23
33
  marker?: Node | null,
24
- init?: JSX.Element
34
+ init?: JSX.Element,
35
+ options?: {
36
+ /**
37
+ * Live accessor for the slot's logical host in the source tree (portals).
38
+ * Each top-level node the slot manages is tagged with a `_$host` getter
39
+ * backed by this accessor so delegated events retarget correctly.
40
+ */
41
+ host?: () => Node | null;
42
+ /** Defer the insert effect to the queue instead of running it inline. */
43
+ schedule?: boolean;
44
+ }
25
45
  ): JSX.Element;
26
46
  export function createComponent<T>(Comp: (props: T) => JSX.Element, props: T): JSX.Element;
27
- export function delegateEvents(eventNames: string[], d?: Document): void;
28
- export function clearDelegatedEvents(d?: Document): void;
29
- export function spread<T>(
30
- node: Element,
31
- accessor: T,
32
- isSVG?: Boolean,
33
- skipChildren?: Boolean
47
+ export function delegateEvents(eventNames: string[]): void;
48
+ export function registerDelegatedRoot(root: MountableElement): void;
49
+ export function unregisterDelegatedRoot(root: MountableElement): void;
50
+ export function registerDelegatedContainer(
51
+ container: MountableElement,
52
+ owner?: MountableElement
34
53
  ): void;
54
+ export function unregisterDelegatedContainer(
55
+ container: MountableElement,
56
+ owner?: MountableElement
57
+ ): void;
58
+ export function getDelegatedRoot(node: MountableElement): MountableElement | undefined;
59
+ export function spread<T>(node: Element, accessor: T, skipChildren?: Boolean): void;
35
60
  export function assign(
36
61
  node: Element,
37
62
  props: any,
38
- isSVG?: Boolean,
39
63
  skipChildren?: Boolean,
40
64
  prevProps?: any,
41
65
  skipRef?: Boolean
42
66
  ): void;
43
67
  export function setAttribute(node: Element, name: string, value: string): void;
44
68
  export function setAttributeNS(node: Element, namespace: string, name: string, value: string): void;
45
- type ClassList =
46
- | Record<string, boolean>
47
- | Array<string | number | boolean | null | undefined | Record<string, boolean>>;
48
- export function className(node: Element, value: string | ClassList, isSvg?: boolean, prev?: string | ClassList): void;
69
+ /**
70
+ * Register a consumer for compiler-emitted element claims. Compiled DOM
71
+ * output claims navigation-relevant elements (`a[href]`, `form[action]`) at
72
+ * creation, and compiler-owned writes to `href`/`action` re-invoke the same
73
+ * handlers — so handlers must be idempotent and must check the element's
74
+ * relevance themselves (rechecks can fire for any element whose
75
+ * `href`/`action` is written, e.g. `<link href>`). Handlers run under the
76
+ * reactive owner current at element creation; scope per-element state and
77
+ * cleanup through your own reactive system. Dormant until registered —
78
+ * without a handler the emitted claims are null checks. Returns an
79
+ * unregister function.
80
+ */
81
+ export function registerElementClaim(handler: (element: Element) => void): () => void;
82
+ /**
83
+ * Claim `node` for registered consumers (see `registerElementClaim`).
84
+ * Emitted by the compiler at element creation; idempotent by contract.
85
+ */
86
+ export function claimElement<T extends Element>(node: T): T;
87
+ /**
88
+ * Sweep-claim every navigation-relevant element (`a[href]`, `form[action]`)
89
+ * in `root` — the subtree equivalent of the per-element `claimElement`
90
+ * compiled output emits, for content that becomes live DOM without compiled
91
+ * creation code (frame streams, adopted SSR ranges). Dormant without a
92
+ * registered consumer.
93
+ */
94
+ export function claimElementTree<T extends Node>(root: T): T;
95
+ export function className(node: Element, value: JSX.ClassValue, prev?: JSX.ClassValue): void;
49
96
  export function setProperty(node: Element, name: string, value: any): void;
50
97
  export function setStyleProperty(node: Element, name: string, value: any): void;
51
- export function addEventListener(
98
+ export function addEvent(
52
99
  node: Element,
53
100
  name: string,
54
101
  handler: EventListener | EventListenerObject | (EventListenerObject & AddEventListenerOptions),
@@ -62,8 +109,14 @@ export function style(
62
109
  export function getOwner(): unknown;
63
110
  export function mergeProps(...sources: unknown[]): unknown;
64
111
  export function dynamicProperty(props: unknown, key: string): unknown;
65
- export function applyRef(r: ((element: Element) => void) | ((element: Element) => void)[], element: Element): void;
66
- export function ref(fn: () => ((element: Element) => void) | ((element: Element) => void)[], element: Element): void;
112
+ export function applyRef<T extends Element = Element>(
113
+ r: ((element: NoInfer<T>) => void) | ((element: NoInfer<T>) => void)[],
114
+ element: T
115
+ ): void;
116
+ export function ref(
117
+ fn: () => ((element: Element) => void) | ((element: Element) => void)[],
118
+ element: Element
119
+ ): void;
67
120
 
68
121
  export function hydrate(
69
122
  fn: () => JSX.Element,
@@ -74,11 +127,62 @@ export function getHydrationKey(): string | undefined;
74
127
  export function getNextElement(template?: () => Element): Element;
75
128
  export function getNextMatch(start: Node, elementName: string): Element;
76
129
  export function getNextMarker(start: Node): [Node, Array<Node>];
130
+ /** @deprecated Use `useHead` — removed before `0.50.0` stable. */
77
131
  export function useAssets(fn: () => JSX.Element): void;
132
+ /** @deprecated Use `useHead` — removed before `0.50.0` stable. */
78
133
  export function getAssets(): string;
134
+ /**
135
+ * A head tag descriptor. Props values may be getters (reactive on the
136
+ * client); `children` is the text body. `key` overrides the built-in dedupe
137
+ * identity (`title` is a hard singleton that `key` cannot fork).
138
+ */
139
+ export type HeadTag = {
140
+ tag: "title" | "meta" | "link" | "style" | "script" | "base";
141
+ props: Record<string, any>;
142
+ key?: string | (() => string);
143
+ };
144
+ /**
145
+ * Registers head tags with the ambient head registry under the current
146
+ * owner. An array is a group — one replacement set. Resolution is
147
+ * last-committed group per identity; disposal restores the previous winner.
148
+ * During hydration the server-flushed head state stays authoritative until
149
+ * hydration completes. See docs/head-management-rfc.md.
150
+ */
151
+ export function useHead(tag: HeadTag | HeadTag[]): void;
152
+ export type AssetDescriptor =
153
+ | { type: "style"; href: string; attrs?: Record<string, string> }
154
+ | { type: "inline-style"; id: string; content?: string; attrs?: Record<string, string> }
155
+ | { type: "module"; href: string }
156
+ | ExclusiveAssetDescriptor<any>;
157
+ export interface ExclusiveAssetDescriptor<T> {
158
+ policy: "exclusive";
159
+ key: string;
160
+ value: T;
161
+ get(): T;
162
+ set(value: T): void;
163
+ }
164
+ export function acquireAsset(descriptor: AssetDescriptor): () => void;
79
165
  export function HydrationScript(props?: { nonce?: string; eventNames?: string[] }): JSX.Element;
80
- export function generateHydrationScript(options?: { nonce?: string; eventNames?: string[] }): string;
166
+ export function generateHydrationScript(options?: {
167
+ nonce?: string;
168
+ eventNames?: string[];
169
+ }): string;
81
170
  export function Assets(props: { children?: JSX.Element }): JSX.Element;
171
+ /**
172
+ * See the server entry's `ResponseStub` — the shape of the mutable response
173
+ * head integrations expose as `event.response` via module augmentation.
174
+ */
175
+ export interface ResponseStub {
176
+ status?: number;
177
+ statusText?: string;
178
+ headers: Headers;
179
+ /**
180
+ * Set by the integration once the response head has been derived/sent
181
+ * from this stub (status/headers can no longer change); consumers must
182
+ * treat later writes and cleanup-time retractions as no-ops.
183
+ */
184
+ committed?: boolean;
185
+ }
82
186
  export interface RequestEvent {
83
187
  request: Request;
84
188
  locals: Record<string | number | symbol, any>;
package/types/core.d.ts CHANGED
@@ -1,3 +1,4 @@
1
- export { getOwner, runWithOwner, createComponent, createRoot as root, sharedConfig, untrack, merge as mergeProps, flatten, ssrHandleError, ssrRunInScope } from "solid-js";
2
- export declare const effect: (fn: any, effectFn: any, initial: any) => void;
3
- export declare const memo: (fn: any, transparent: any) => any;
1
+ export { getOwner, runWithOwner, createComponent, createRoot as root, sharedConfig, untrack, merge as mergeProps, flatten, ssrHandleError, ssrScope, NoHydration, Hydration, runInServerComponentScope } from "solid-js";
2
+ export declare const effect: (fn: any, effectFn: any, options: any) => void;
3
+ export declare const memo: (fn: any) => import("solid-js").SourceAccessor<any>;
4
+ export declare const runWithHydrationScope: (id: any, fn: any) => unknown;
@@ -0,0 +1,20 @@
1
+ export { createFrame, createFrameHost, createFrameElement, FRAME_APPLIED_EVENT } from "./frame-client.js";
2
+ export { FRAME_STREAM_HEADER, applyFrameResponse, isFrameStreamResponse, createServerComponentHandler } from "./frame-transport.js";
3
+ export { createJSONDataTable } from "./serializer.js";
4
+ export type { Slot } from "./server.js";
5
+ export declare function getFrameHost(): any;
6
+ /**
7
+ * Installs the server-component transport policy on the server-function
8
+ * client: boundary identity is the call's intrinsic (function, arguments)
9
+ * address — per-args, exactly like the query cache, so a cached component
10
+ * always mounts the boundary showing the call it was cached for. Repeat
11
+ * calls for the same args resolve the identical component (refetches morph
12
+ * in place, cache hits pass `dynamic`'s equals-gate); a source switching
13
+ * args swaps boundaries, re-materialized instantly from the host's
14
+ * retained state.
15
+ *
16
+ * Call once in the client entry (an explicit call — the package is
17
+ * `sideEffects: false`, so a bare import would be tree-shaken away);
18
+ * call again to rebind to a custom host.
19
+ */
20
+ export declare function installServerComponents(host?: any): void;
@@ -0,0 +1,270 @@
1
+ /**
2
+ * Client frame runtime — the consumer side of a frame stream. A frame
3
+ * renders server-owned content into a DOM boundary from a resident keyed
4
+ * record store: chunks are writes, not events, so application is
5
+ * prerequisite-driven and order-independent. Client-owned slot ranges
6
+ * inside the boundary are preserved across server updates — the
7
+ * version is a stale-guard only ("policy A"): newer content morphs in
8
+ * place, and teardown is `dispose()`, never a version bump.
9
+ */
10
+
11
+ /** One transport chunk of a frame stream, addressed by frame `id`. */
12
+ export type FrameChunk =
13
+ | { type: "start"; id: string; version: number }
14
+ | { type: "html"; id: string; version: number; html: string }
15
+ | { type: "fragment"; id: string; version: number; key: string; html: string }
16
+ | {
17
+ type: "reveal";
18
+ id: string;
19
+ version: number;
20
+ keys: string[];
21
+ waitForStyles?: boolean;
22
+ fallback?: boolean;
23
+ }
24
+ | {
25
+ type: "data";
26
+ id: string;
27
+ version: number;
28
+ key?: string;
29
+ node?: unknown;
30
+ initial?: boolean;
31
+ /** Eval-style hydration script — only when produced with the hydration serializer. */
32
+ payload?: string;
33
+ }
34
+ | {
35
+ type: "assets";
36
+ id: string;
37
+ version: number;
38
+ key: string;
39
+ modules?: string[];
40
+ styles?: string[];
41
+ inlineStyles?: { id: string; content?: string; attrs?: Record<string, string> }[];
42
+ }
43
+ | { type: "slot"; id: string; version: number; key: string; args: Record<string, unknown> }
44
+ | { type: "complete"; id: string; version: number }
45
+ | { type: "error"; id: string; version: number; key?: string; error: unknown };
46
+
47
+ /**
48
+ * Maps a wire chunk onto resident-store record writes. `data` chunks map to
49
+ * no records — they are response-scoped and the host applies them through
50
+ * its data hook.
51
+ */
52
+ export function chunkToRecords(chunk: FrameChunk): Record<string, unknown>;
53
+
54
+ /**
55
+ * One store write applied to a frame: `r` maps record keys to values
56
+ * (`chunkToRecords` produces these from wire chunks) and `version` is the
57
+ * stream stamp — an older version than the frame's current one is ignored.
58
+ */
59
+ export interface FrameWrite {
60
+ version: number;
61
+ r: Record<string, unknown>;
62
+ }
63
+
64
+ /** Context passed to a slot callback. */
65
+ export interface SlotContext {
66
+ /**
67
+ * True only for the hydration-attach invocation of an adopted
68
+ * document-SSR range — the one call a consumer may answer with a claim
69
+ * (`existing` IS the server-rendered output for these args). Unset on
70
+ * stream-driven re-calls: those must render for real, or content the
71
+ * re-call displaced (e.g. `{$frame}` region ranges) is dropped.
72
+ */
73
+ adopted?: boolean;
74
+ /**
75
+ * Whether this occurrence is a render-prop CALL (the producer placed it
76
+ * with arguments — possibly empty — via a slot record) as opposed to a
77
+ * direct-insert position. Consumers cannot tell from the resolved props
78
+ * alone: an argless render prop and a direct insert both arrive as `{}`,
79
+ * but one is a function to invoke and the other a value to place.
80
+ */
81
+ invoked?: boolean;
82
+ /**
83
+ * Register cleanup for when this occurrence's range is removed from the
84
+ * server content, or the owning frame is disposed.
85
+ */
86
+ onCleanup(fn: () => void): void;
87
+ /**
88
+ * Live-props opt-in: a binding that registers here receives the
89
+ * re-resolved props when a re-sent record's args CHANGE in value, instead
90
+ * of the occurrence being re-called — the invocation's instance (and its
91
+ * client state) survives the change. Register synchronously during the
92
+ * invocation; one updater per occurrence (last registration wins). A
93
+ * genuine re-call or unmount clears it before/with the binding it served.
94
+ */
95
+ onUpdate(fn: (props: Record<string, unknown>) => void): void;
96
+ /**
97
+ * The range's current interior — server-rendered client content on an
98
+ * adopted document-SSR boot, or the previous output on a re-call. A
99
+ * framework binding hydrates onto it and returns `undefined` to claim it
100
+ * in place (zero DOM mutation).
101
+ */
102
+ existing: ChildNode[];
103
+ /**
104
+ * The range's own marker comments, when the occurrence has a placed range.
105
+ * A framework binding whose slot content is reactive at the top level (a
106
+ * boundary accessor, changing route children) owns the interior instead of
107
+ * returning nodes: bind before `end` with the framework's insert primitive
108
+ * and return `undefined` — the frame leaves the range alone (server morphs
109
+ * already protect slot ranges).
110
+ */
111
+ range?: { start: Comment; end: Comment };
112
+ }
113
+
114
+ /**
115
+ * Client content for a server-declared slot. Direct-insert occurrences
116
+ * call it with empty props; render-prop occurrences pass the occurrence's
117
+ * resolved args (primitives literal, `{$ref}` data resolved through the
118
+ * host, `{$frame}` regions as marker-range fragments). Return nodes to fill
119
+ * the range, or `undefined` to claim `ctx.existing` untouched.
120
+ */
121
+ export type Slot = (props: Record<string, unknown>, ctx: SlotContext) => Node | Node[] | undefined;
122
+
123
+ export interface Frame {
124
+ /** Merge a write into the store and flush (morph/reveal/slot sync). */
125
+ apply(write: FrameWrite): void;
126
+ /** The active version, or undefined before the first apply. */
127
+ readonly version: number | undefined;
128
+ /** Read-only view of the resident record store. */
129
+ readonly store: Readonly<Record<string, unknown>>;
130
+ /** The stream's error record, if an `error` chunk arrived. */
131
+ readonly error: unknown;
132
+ /** Whether the named fragment has been revealed into the boundary. */
133
+ isRevealed(segment: string): boolean;
134
+ /**
135
+ * Re-key this live frame to a different boundary id (the mount-preserving
136
+ * half of a call-site handoff): nothing tears down — the element, store,
137
+ * and slot state stay — while leaving the old id stashes a retention
138
+ * snapshot under it and joining the new id seeds/drains its retained
139
+ * store and buffered chunks. Version affinity resets: histories are per
140
+ * boundary id.
141
+ */
142
+ rebind(id: string): void;
143
+ /**
144
+ * Forget the version baseline without touching content — the next write
145
+ * is accepted whatever its number. Called by the host after seeding a
146
+ * registration from a retained snapshot, whose numbering belongs to a
147
+ * different stream space.
148
+ */
149
+ rebase(): void;
150
+ /** Tear down: slot cleanups cascade, later chunks are ignored. Idempotent. */
151
+ dispose(): void;
152
+ }
153
+
154
+ /**
155
+ * Routes a flat stream of addressed chunks to frames by id, buffering chunks
156
+ * for frames that have not registered yet (only the newest version's chunks
157
+ * are kept). `data` chunks are response-scoped and go to `applyData`.
158
+ *
159
+ * An id may have several frames (the same server component mounted more
160
+ * than once): chunks fan out to all of them, and a frame registering after
161
+ * delivery is seeded from a sibling's store.
162
+ */
163
+ export interface FrameHost {
164
+ register(id: string, frame: Frame): void;
165
+ /** Remove one frame (or all frames of the id when `frame` is omitted). */
166
+ unregister(id: string, frame?: Frame): void;
167
+ apply(chunk: FrameChunk): void;
168
+ /** The first registered frame under the id, if any. */
169
+ get(id: string): Frame | undefined;
170
+ serialize(value: unknown): { $ref: string };
171
+ /** `frameId` is the resolving frame's id — route to its stream's table. */
172
+ resolve(ref: { $ref: string }, frameId?: string): unknown;
173
+ }
174
+
175
+ /**
176
+ * The bubbling DOM event (`"frame:applied"`) a frame dispatches from its
177
+ * parent element whenever server content lands in the document — root
178
+ * materialize/morph, segment reveal, fallback materialization — with
179
+ * `detail: { id, version, reason }`. One document-level listener sees every
180
+ * boundary (nested region frames dispatch too); use it to re-apply
181
+ * client-owned decorations on server-owned markup (router affordance
182
+ * reflection, e.g. `aria-current`) without a MutationObserver.
183
+ */
184
+ export const FRAME_APPLIED_EVENT: "frame:applied";
185
+
186
+ /** Options for `createFrameHost`. */
187
+ export interface FrameHostOptions {
188
+ /**
189
+ * Backs `{$ref}` slot args (typically a codec data table's `resolve`).
190
+ * `frameId` identifies the resolving frame — data tables are
191
+ * response-scoped, so multi-stream hosts route by it (nested region ids
192
+ * prefix-match their root).
193
+ */
194
+ resolve?(ref: { $ref: string }, frameId?: string): unknown;
195
+ /** Test/host-side counterpart of `resolve`. */
196
+ serialize?(value: unknown): { $ref: string };
197
+ /**
198
+ * Receives each `data` chunk whole. Wire a codec table:
199
+ * `applyData: c => table.apply(c)` (see `createJSONDataTable`).
200
+ */
201
+ applyData?(chunk: Extract<FrameChunk, { type: "data" }>): void;
202
+ }
203
+
204
+ export function createFrameHost(options?: FrameHostOptions): FrameHost;
205
+
206
+ /** Options for `createFrame` / `createFrameElement`. */
207
+ export interface FrameOptions {
208
+ /** Register with this host under `id`, receiving routed/buffered chunks. */
209
+ host?: FrameHost;
210
+ id?: string;
211
+ /** Client content keyed by prop name (occurrences resolve by prop). */
212
+ slots?: Record<string, Slot>;
213
+ /**
214
+ * Adopt existing server-rendered DOM: the first apply morphs against it,
215
+ * and slots sync immediately (hydration attach) — a document-SSR boot
216
+ * needs no chunk.
217
+ */
218
+ adopt?: boolean;
219
+ /** Called after each apply flush (tests/telemetry). */
220
+ onApply?(info: { version: number; reason: "materialize" | "morph" | "reveal" }): void;
221
+ /**
222
+ * Wraps element-claim sweeps (`a[href]`/`form[action]` in materialized
223
+ * server content — and only those) so claim consumers register their
224
+ * per-element cleanup against the boundary's reactive owner, e.g.
225
+ * `fn => runWithOwner(owner, fn)`. Nested region frames inherit it.
226
+ * Without it, sweeps run under whatever owner is current (none, for
227
+ * streamed chunks).
228
+ */
229
+ ownerScope?<T>(fn: () => T): T;
230
+ /**
231
+ * Boundary-driven segment reveal. When present, `#revealSegment` hands the
232
+ * placeholder seam to this hook instead of swapping imperatively: the binding
233
+ * reconstructs a client `<Loading>` there — `fallback` is the placeholder's
234
+ * own template content (shown while holding), `content()` materializes the
235
+ * segment and renders its client fills INSIDE the boundary so their readiness
236
+ * gates the reveal — and inserts it before `before`. An unboundaried async
237
+ * fill suspends up to that boundary and is covered instead of orphaned; one
238
+ * boundary per revealed segment, i.e. per author-placed `<Loading>`. Omit it
239
+ * for the framework-agnostic imperative swap (no reactive reveal).
240
+ */
241
+ reveal?(seam: { before: Node; fallback: Node[]; content: () => Node | DocumentFragment }): void;
242
+ }
243
+
244
+ /**
245
+ * A frame rendering into an EXISTING element boundary. Pass `adopt: true` for
246
+ * the document-SSR path: the element already holds server-rendered content,
247
+ * so the first apply morphs against it and slots sync immediately (hydration
248
+ * attach), claiming their server-rendered DOM — a document boot needs no
249
+ * chunk.
250
+ */
251
+ export function createFrame(boundary: Element, options?: FrameOptions): Frame;
252
+
253
+ /** The default boundary/region element tag and its id attribute — the DOM
254
+ * contract the producer emits at t=0 and the consumer creates/adopts. */
255
+ export const FRAME_TAG: "dx-frame";
256
+ export const FRAME_ID_ATTR: "data-fid";
257
+
258
+ /**
259
+ * Create a boundary/region ELEMENT and bind a host-registered frame to it.
260
+ * The frame mounts INTO the element (server content is its children, morphed
261
+ * in place). Because the boundary is a real node, `insert` places the
262
+ * returned `element` in any position — single, array, or fragment — with no
263
+ * special-casing. One frame per element; lifecycle belongs to the creator via
264
+ * `dispose()` (register it with your owner's cleanup).
265
+ */
266
+ export function createFrameElement(options: FrameOptions): {
267
+ readonly element: Element;
268
+ readonly frame: Frame;
269
+ dispose(): void;
270
+ };