octane 0.3.1 → 0.3.2
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.
- package/dist/cjs/constants.cjs +18 -25
- package/dist/cjs/css.cjs +6 -0
- package/dist/cjs/dom-binding-protocol.cjs +37 -14
- package/dist/cjs/hydration/control-capture.cjs +12 -4
- package/dist/cjs/hydration/event-capture.cjs +6 -7
- package/dist/cjs/hydration-markers.cjs +40 -2
- package/dist/cjs/runtime-tags.cjs +55 -0
- package/dist/cjs/runtime.cjs +136 -113
- package/dist/cjs/runtime.server.cjs +34 -41
- package/dist/cjs/server/streamed-signals.cjs +7 -4
- package/dist/cjs/signals/control-binding.cjs +2 -1
- package/dist/cjs/stream-protocol.cjs +9 -8
- package/dist/cjs/version.cjs +1 -1
- package/dist/compiler/compile.js +70 -17
- package/dist/compiler/dom-bindings.js +5 -0
- package/dist/constants.d.ts +7 -18
- package/dist/constants.js +11 -9
- package/dist/css.d.ts +7 -0
- package/dist/css.js +4 -0
- package/dist/dom-binding-program.js +12 -5
- package/dist/dom-binding-protocol.d.ts +14 -1
- package/dist/dom-binding-protocol.js +40 -14
- package/dist/hydration/control-capture.d.ts +2 -0
- package/dist/hydration/control-capture.js +18 -5
- package/dist/hydration/event-capture.js +1 -2
- package/dist/hydration/independent-island.js +5 -5
- package/dist/hydration-markers.d.ts +30 -0
- package/dist/hydration-markers.js +27 -1
- package/dist/react/index.js +1 -1
- package/dist/react/react-compat-shared.js +5 -3
- package/dist/react/shared.d.ts +1 -3
- package/dist/react/shared.js +1 -1
- package/dist/runtime-tags.d.ts +34 -0
- package/dist/runtime-tags.js +22 -0
- package/dist/runtime.d.ts +5 -14
- package/dist/runtime.js +116 -71
- package/dist/runtime.server.d.ts +2 -3
- package/dist/runtime.server.js +25 -17
- package/dist/server/streamed-signals.js +7 -4
- package/dist/signals/control-binding.js +4 -2
- package/dist/stream-protocol.js +20 -9
- package/dist/universal-core.js +8 -4
- package/dist/universal-native.js +1 -1
- package/dist/version.js +1 -1
- package/package.json +3 -3
|
@@ -5,7 +5,13 @@ import {
|
|
|
5
5
|
__releaseBinding,
|
|
6
6
|
__writeBinding
|
|
7
7
|
} from "./dom-bindings.js";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
bindingRootMarker,
|
|
10
|
+
BINDING_OPEN_PREFIX,
|
|
11
|
+
encodeBindingKey,
|
|
12
|
+
parseBindingMarker
|
|
13
|
+
} from "./dom-binding-protocol.js";
|
|
14
|
+
import { HYDRATION_FOR_PREFIX } from "./hydration-markers.js";
|
|
9
15
|
import { moveNativeNodeBefore } from "./dom-focused-move.js";
|
|
10
16
|
import { rendererRangeClose } from "./stream-protocol.js";
|
|
11
17
|
import {
|
|
@@ -527,7 +533,7 @@ function createFragment(definition, id, document, transaction) {
|
|
|
527
533
|
const template = document.createElement("template");
|
|
528
534
|
template.innerHTML = definition.ns === 1 ? `<svg>${definition.html}</svg>` : definition.html;
|
|
529
535
|
const content = document.createDocumentFragment();
|
|
530
|
-
const start = document.createComment(
|
|
536
|
+
const start = document.createComment(bindingRootMarker(id));
|
|
531
537
|
const end = document.createComment("]");
|
|
532
538
|
content.appendChild(start);
|
|
533
539
|
if (definition.ns === 1) {
|
|
@@ -875,7 +881,8 @@ function commitRegion(plan, id, transaction) {
|
|
|
875
881
|
transaction
|
|
876
882
|
);
|
|
877
883
|
}
|
|
878
|
-
if (definition.kind === "if")
|
|
884
|
+
if (definition.kind === "if")
|
|
885
|
+
region.range.start.data = `${BINDING_OPEN_PREFIX}${id};${region.site};${plan.arm}`;
|
|
879
886
|
}
|
|
880
887
|
function writeText(region, value) {
|
|
881
888
|
if (region.text === null) {
|
|
@@ -1469,13 +1476,13 @@ function commitList(plan, id, transaction) {
|
|
|
1469
1476
|
}
|
|
1470
1477
|
let anchor = region.range.end;
|
|
1471
1478
|
for (const [key, item] of [...plan.items].reverse()) {
|
|
1472
|
-
item.instance.range.start.data =
|
|
1479
|
+
item.instance.range.start.data = `${BINDING_OPEN_PREFIX}${id};${region.site};k;${key}`;
|
|
1473
1480
|
moveRange(item.instance.range, region.range.end.parentNode, anchor, transaction);
|
|
1474
1481
|
if (transaction.disposed) return;
|
|
1475
1482
|
anchor = item.instance.range.start;
|
|
1476
1483
|
}
|
|
1477
1484
|
}
|
|
1478
|
-
region.range.start.data =
|
|
1485
|
+
region.range.start.data = `${HYDRATION_FOR_PREFIX}${plan.arm};b;${id};${region.site}`;
|
|
1479
1486
|
return;
|
|
1480
1487
|
}
|
|
1481
1488
|
function claimProgramControl(instance, index, node, transaction) {
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
-
/** Compiler-owned DOM presentation markers. This leaf is shared by client and SSR. */
|
|
2
1
|
export type BindingKey = string | number;
|
|
2
|
+
/** Payload prefix opening a presentation-binding range. */
|
|
3
|
+
export declare const BINDING_OPEN_PREFIX: string;
|
|
4
|
+
/**
|
|
5
|
+
* Comment payload opening an authored presentation view's own component range.
|
|
6
|
+
* The client runtime and the SSR serializer both stamp this onto the view they
|
|
7
|
+
* bind, so the two must never spell it separately.
|
|
8
|
+
*/
|
|
9
|
+
export declare function bindingRootMarker(id: string): string;
|
|
3
10
|
export declare function encodeBindingKey(key: BindingKey): string;
|
|
4
11
|
export declare function decodeBindingKey(encoded: string): BindingKey;
|
|
5
12
|
export interface BindingMarker {
|
|
@@ -11,3 +18,9 @@ export interface BindingMarker {
|
|
|
11
18
|
}
|
|
12
19
|
export declare function parseBindingMarker(data: string): BindingMarker | null;
|
|
13
20
|
export declare function isBindingOpenComment(data: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* True when a binding-open payload carries an `@for` outer arm. The prefix test
|
|
23
|
+
* alone is not a decision: `isBindingOpenComment` still requires the full
|
|
24
|
+
* receipt, so this only spares callers from spelling the arm prefixes again.
|
|
25
|
+
*/
|
|
26
|
+
export declare function isForBindingOpenComment(data: string): boolean;
|
|
@@ -1,3 +1,21 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HYDRATION_FOR_ARM_INDEX,
|
|
3
|
+
HYDRATION_FOR_EMPTY,
|
|
4
|
+
HYDRATION_FOR_ITEMS,
|
|
5
|
+
HYDRATION_FOR_PREFIX,
|
|
6
|
+
HYDRATION_START
|
|
7
|
+
} from "./hydration-markers.js";
|
|
8
|
+
const BINDING_OPEN_PREFIX = HYDRATION_START + "b;";
|
|
9
|
+
const BINDING_RECEIPT = ";b;";
|
|
10
|
+
const BINDING_FOR_EMPTY_PREFIX = HYDRATION_FOR_EMPTY + BINDING_RECEIPT;
|
|
11
|
+
const BINDING_FOR_ITEMS_PREFIX = HYDRATION_FOR_ITEMS + BINDING_RECEIPT;
|
|
12
|
+
const BINDING_FOR_ID_START = BINDING_FOR_EMPTY_PREFIX.length;
|
|
13
|
+
const BINDING_ID_START = BINDING_OPEN_PREFIX.length;
|
|
14
|
+
const BINDING_ROOT_SITE = "root";
|
|
15
|
+
const BINDING_ROOT_SUFFIX = ";" + BINDING_ROOT_SITE;
|
|
16
|
+
function bindingRootMarker(id) {
|
|
17
|
+
return BINDING_OPEN_PREFIX + id + BINDING_ROOT_SUFFIX;
|
|
18
|
+
}
|
|
1
19
|
function encodeBindingKey(key) {
|
|
2
20
|
if (typeof key === "string")
|
|
3
21
|
return "s:" + JSON.stringify(key).replace(/-/g, "\\u002d").replace(/</g, "\\u003c");
|
|
@@ -17,21 +35,22 @@ function decodeBindingKey(encoded) {
|
|
|
17
35
|
throw new TypeError("A DOM presentation key has invalid serialized identity.");
|
|
18
36
|
}
|
|
19
37
|
function parseBindingMarker(data) {
|
|
20
|
-
if (data.startsWith(
|
|
21
|
-
const separator = data.indexOf(";",
|
|
22
|
-
if (separator <=
|
|
38
|
+
if (data.startsWith(BINDING_FOR_EMPTY_PREFIX) || data.startsWith(BINDING_FOR_ITEMS_PREFIX)) {
|
|
39
|
+
const separator = data.indexOf(";", BINDING_FOR_ID_START);
|
|
40
|
+
if (separator <= BINDING_FOR_ID_START || separator === data.length - 1) return null;
|
|
23
41
|
return {
|
|
24
|
-
id: data.slice(
|
|
42
|
+
id: data.slice(BINDING_FOR_ID_START, separator),
|
|
25
43
|
site: data.slice(separator + 1),
|
|
26
44
|
kind: "for",
|
|
27
|
-
arm: data.charCodeAt(
|
|
45
|
+
arm: data.charCodeAt(HYDRATION_FOR_ARM_INDEX) - 48
|
|
28
46
|
};
|
|
29
47
|
}
|
|
30
|
-
if (!data.startsWith(
|
|
31
|
-
const idEnd = data.indexOf(";",
|
|
32
|
-
if (idEnd <=
|
|
33
|
-
const id = data.slice(
|
|
34
|
-
if (data.slice(idEnd + 1) ===
|
|
48
|
+
if (!data.startsWith(BINDING_OPEN_PREFIX)) return null;
|
|
49
|
+
const idEnd = data.indexOf(";", BINDING_ID_START);
|
|
50
|
+
if (idEnd <= BINDING_ID_START || idEnd === data.length - 1) return null;
|
|
51
|
+
const id = data.slice(BINDING_ID_START, idEnd);
|
|
52
|
+
if (data.slice(idEnd + 1) === BINDING_ROOT_SITE)
|
|
53
|
+
return { id, site: BINDING_ROOT_SITE, kind: "root" };
|
|
35
54
|
const siteEnd = data.indexOf(";", idEnd + 1);
|
|
36
55
|
if (siteEnd <= idEnd + 1 || siteEnd === data.length - 1) return null;
|
|
37
56
|
const site = data.slice(idEnd + 1, siteEnd);
|
|
@@ -56,13 +75,14 @@ function parseBindingMarker(data) {
|
|
|
56
75
|
return null;
|
|
57
76
|
}
|
|
58
77
|
function isBindingOpenComment(data) {
|
|
59
|
-
const list = data.startsWith(
|
|
60
|
-
if (!list && !data.startsWith(
|
|
61
|
-
const idStart = list ?
|
|
78
|
+
const list = data.startsWith(BINDING_FOR_EMPTY_PREFIX) || data.startsWith(BINDING_FOR_ITEMS_PREFIX);
|
|
79
|
+
if (!list && !data.startsWith(BINDING_OPEN_PREFIX)) return false;
|
|
80
|
+
const idStart = list ? BINDING_FOR_ID_START : BINDING_ID_START;
|
|
62
81
|
const idEnd = data.indexOf(";", idStart);
|
|
63
82
|
if (idEnd <= idStart || idEnd === data.length - 1) return false;
|
|
64
83
|
if (list) return data.indexOf(";", idEnd + 1) === -1;
|
|
65
|
-
if (data.length - idEnd ===
|
|
84
|
+
if (data.length - idEnd === BINDING_ROOT_SUFFIX.length && data.endsWith(BINDING_ROOT_SUFFIX))
|
|
85
|
+
return true;
|
|
66
86
|
const siteEnd = data.indexOf(";", idEnd + 1);
|
|
67
87
|
if (siteEnd <= idEnd + 1 || siteEnd === data.length - 1) return false;
|
|
68
88
|
const tail = siteEnd + 1;
|
|
@@ -80,9 +100,15 @@ function isBindingOpenComment(data) {
|
|
|
80
100
|
}
|
|
81
101
|
return true;
|
|
82
102
|
}
|
|
103
|
+
function isForBindingOpenComment(data) {
|
|
104
|
+
return data.startsWith(HYDRATION_FOR_PREFIX) && isBindingOpenComment(data);
|
|
105
|
+
}
|
|
83
106
|
export {
|
|
107
|
+
BINDING_OPEN_PREFIX,
|
|
108
|
+
bindingRootMarker,
|
|
84
109
|
decodeBindingKey,
|
|
85
110
|
encodeBindingKey,
|
|
86
111
|
isBindingOpenComment,
|
|
112
|
+
isForBindingOpenComment,
|
|
87
113
|
parseBindingMarker
|
|
88
114
|
};
|
|
@@ -45,6 +45,8 @@ export interface HydrationControlCandidateValue {
|
|
|
45
45
|
* the state changed while ownership was being transferred.
|
|
46
46
|
*/
|
|
47
47
|
export declare function snapshotHydrationControl(control: Element): HydrationControlSnapshot | null;
|
|
48
|
+
/** @internal Only unchanged server state may yield to an eventless textarea restore. */
|
|
49
|
+
export declare function isRestoredHydrationTextarea(control: Element, value: unknown): boolean;
|
|
48
50
|
/**
|
|
49
51
|
* Capture the exact DOM/edit authority an async storage read is allowed to replace.
|
|
50
52
|
* A focus, selection, composition, input (including clear), node replacement, or
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
HYDRATE_ID_ATTR,
|
|
3
|
+
HYDRATE_INDEPENDENT_ATTR,
|
|
4
|
+
HYDRATE_INPUT_ATTR,
|
|
5
|
+
HYDRATE_MARKER_SELECTOR,
|
|
6
|
+
HYDRATE_WHEN_ATTR
|
|
7
|
+
} from "../hydration-markers.js";
|
|
2
8
|
import {
|
|
3
9
|
EARLY_HYDRATION_INTENTS_KEY,
|
|
4
10
|
HYDRATE_INTERACTION_EVENTS_ATTR
|
|
@@ -9,10 +15,9 @@ import {
|
|
|
9
15
|
publishHydrationControlSignalValues,
|
|
10
16
|
readEarlyHydrationControlRevision
|
|
11
17
|
} from "../signals/early-values.js";
|
|
12
|
-
const HYDRATE_MARKER_SELECTOR = "[data-octane-hydrate-id]";
|
|
13
18
|
const HYDRATE_CONTROL_DOCUMENTS = /* @__PURE__ */ new WeakSet();
|
|
14
19
|
function isEarlyHydrationIntentCurrent([event, target, boundary, id, when, events], ownerDocument) {
|
|
15
|
-
return event.target === target && target.isConnected && boundary.isConnected && target.ownerDocument === ownerDocument && boundary.ownerDocument === ownerDocument && target.closest(`[${HYDRATE_INDEPENDENT_ATTR}]`) === boundary && boundary.getAttribute(
|
|
20
|
+
return event.target === target && target.isConnected && boundary.isConnected && target.ownerDocument === ownerDocument && boundary.ownerDocument === ownerDocument && target.closest(`[${HYDRATE_INDEPENDENT_ATTR}]`) === boundary && boundary.getAttribute(HYDRATE_ID_ATTR) === id && boundary.getAttribute(HYDRATE_WHEN_ATTR) === when && boundary.getAttribute(HYDRATE_INTERACTION_EVENTS_ATTR) === events;
|
|
16
21
|
}
|
|
17
22
|
function isHydrationElement(target) {
|
|
18
23
|
return target !== null && target.nodeType === 1;
|
|
@@ -108,6 +113,13 @@ function snapshotHydrationControl(control) {
|
|
|
108
113
|
composing: record?.composing ?? false
|
|
109
114
|
};
|
|
110
115
|
}
|
|
116
|
+
function isRestoredHydrationTextarea(control, value) {
|
|
117
|
+
if (control.localName !== "textarea" || typeof value !== "string" || HYDRATE_CONTROL_RECORDS.get(control)?.composing === true)
|
|
118
|
+
return false;
|
|
119
|
+
const textarea = control;
|
|
120
|
+
const baseline = textarea.defaultValue.replace(/\r\n?/g, "\n");
|
|
121
|
+
return value.replace(/\r\n?/g, "\n") === baseline && textarea.value !== baseline;
|
|
122
|
+
}
|
|
111
123
|
function captureHydrationControlCandidate(control) {
|
|
112
124
|
const snapshot = snapshotHydrationControl(control);
|
|
113
125
|
if (snapshot === null) return null;
|
|
@@ -115,7 +127,7 @@ function captureHydrationControlCandidate(control) {
|
|
|
115
127
|
return {
|
|
116
128
|
control,
|
|
117
129
|
bindingId: control.getAttribute(HYDRATE_INPUT_ATTR),
|
|
118
|
-
boundaryId: control.closest(HYDRATE_MARKER_SELECTOR)?.getAttribute(
|
|
130
|
+
boundaryId: control.closest(HYDRATE_MARKER_SELECTOR)?.getAttribute(HYDRATE_ID_ATTR) ?? null,
|
|
119
131
|
snapshot
|
|
120
132
|
};
|
|
121
133
|
}
|
|
@@ -130,7 +142,7 @@ function sameHydrationControlValue(left, right) {
|
|
|
130
142
|
}
|
|
131
143
|
function applyHydrationControlCandidate(candidate, value) {
|
|
132
144
|
const control = candidate.control;
|
|
133
|
-
if (!control.isConnected || control.getAttribute(HYDRATE_INPUT_ATTR) !== candidate.bindingId || (control.closest(HYDRATE_MARKER_SELECTOR)?.getAttribute(
|
|
145
|
+
if (!control.isConnected || control.getAttribute(HYDRATE_INPUT_ATTR) !== candidate.bindingId || (control.closest(HYDRATE_MARKER_SELECTOR)?.getAttribute(HYDRATE_ID_ATTR) ?? null) !== candidate.boundaryId) {
|
|
134
146
|
return false;
|
|
135
147
|
}
|
|
136
148
|
const current = snapshotHydrationControl(control);
|
|
@@ -219,5 +231,6 @@ export {
|
|
|
219
231
|
consumeHydrationControl,
|
|
220
232
|
initializeHydrationControlCapture,
|
|
221
233
|
isEarlyHydrationIntentCurrent,
|
|
234
|
+
isRestoredHydrationTextarea,
|
|
222
235
|
snapshotHydrationControl
|
|
223
236
|
};
|
|
@@ -19,8 +19,7 @@ import {
|
|
|
19
19
|
snapshotHydrationControl
|
|
20
20
|
} from "./control-capture.js";
|
|
21
21
|
import { HYDRATE_STREAM_TOKEN_ATTR, isRendererStreamBoundaryTemplate } from "../stream-protocol.js";
|
|
22
|
-
|
|
23
|
-
const HYDRATE_WHEN_ATTR = "data-octane-hydrate-when";
|
|
22
|
+
import { HYDRATE_MARKER_SELECTOR, HYDRATE_WHEN_ATTR } from "../hydration-markers.js";
|
|
24
23
|
function isHydrationNode(target) {
|
|
25
24
|
return target !== null && typeof target.nodeType === "number";
|
|
26
25
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { decodeSignalValue } from "../data-encoding.js";
|
|
2
2
|
import {
|
|
3
|
+
HYDRATE_ID_ATTR,
|
|
4
|
+
HYDRATE_WHEN_ATTR,
|
|
3
5
|
HYDRATE_INDEPENDENT_ATTR,
|
|
4
6
|
INDEPENDENT_HYDRATE_MANIFEST_ATTR
|
|
5
7
|
} from "../hydration-markers.js";
|
|
@@ -19,7 +21,7 @@ function registerIndependentHydrationIsland(element, manifest, registration) {
|
|
|
19
21
|
if (!isIndependentHydrateManifest(manifest)) {
|
|
20
22
|
throw new TypeError("Invalid independent Hydrate manifest.");
|
|
21
23
|
}
|
|
22
|
-
if (element.getAttribute(
|
|
24
|
+
if (element.getAttribute(HYDRATE_ID_ATTR) !== manifest.boundaryId) {
|
|
23
25
|
throw new Error("Independent Hydrate boundary identity mismatch.");
|
|
24
26
|
}
|
|
25
27
|
element.setAttribute(HYDRATE_INDEPENDENT_ATTR, "");
|
|
@@ -85,8 +87,7 @@ function registerIndependentHydrationIsland(element, manifest, registration) {
|
|
|
85
87
|
return status;
|
|
86
88
|
};
|
|
87
89
|
registerHydrationIntentBoundary(element, boundary);
|
|
88
|
-
if (intents.length !== 0 || element.getAttribute(
|
|
89
|
-
activate();
|
|
90
|
+
if (intents.length !== 0 || element.getAttribute(HYDRATE_WHEN_ATTR) === "load") activate();
|
|
90
91
|
return Object.assign(
|
|
91
92
|
() => {
|
|
92
93
|
if (disposed) return;
|
|
@@ -107,8 +108,7 @@ function registerIndependentHydrationIsland(element, manifest, registration) {
|
|
|
107
108
|
resume() {
|
|
108
109
|
if (disposed || !paused) return;
|
|
109
110
|
paused = false;
|
|
110
|
-
if (intents.length || element.getAttribute(
|
|
111
|
-
activate();
|
|
111
|
+
if (intents.length || element.getAttribute(HYDRATE_WHEN_ATTR) === "load") activate();
|
|
112
112
|
}
|
|
113
113
|
}
|
|
114
114
|
);
|
|
@@ -5,3 +5,33 @@ export declare const HYDRATE_INDEPENDENT_ATTR = "data-octane-hydrate-independent
|
|
|
5
5
|
export declare const HYDRATE_INPUT_ATTR = "data-octane-input";
|
|
6
6
|
/** Server-only writable-signal identity joined to a compiler control site. */
|
|
7
7
|
export declare const SIGNAL_CONTROL_ATTR = "data-octane-signal-control";
|
|
8
|
+
/** Stable id of a server-rendered deferred hydration boundary. */
|
|
9
|
+
export declare const HYDRATE_ID_ATTR = "data-octane-hydrate-id";
|
|
10
|
+
/** Serialized strategy kind (`visible`, `idle`, `dynamic`, …). */
|
|
11
|
+
export declare const HYDRATE_WHEN_ATTR = "data-octane-hydrate-when";
|
|
12
|
+
/** Number of `useId()` slots consumed while rendering the deferred child. */
|
|
13
|
+
export declare const HYDRATE_ID_COUNT_ATTR = "data-octane-hydrate-id-count";
|
|
14
|
+
/** Direct-child JSON script carrying this boundary's `use()` seed slice. */
|
|
15
|
+
export declare const HYDRATE_SEED_ATTR = "data-octane-hydrate-seed";
|
|
16
|
+
/** Matches any server-rendered deferred hydration boundary wrapper. */
|
|
17
|
+
export declare const HYDRATE_MARKER_SELECTOR = "[data-octane-hydrate-id]";
|
|
18
|
+
/** Single-character payload of a block-open comment. */
|
|
19
|
+
export declare const HYDRATION_START = "[";
|
|
20
|
+
/** Single-character payload of a block-close comment. */
|
|
21
|
+
export declare const HYDRATION_END = "]";
|
|
22
|
+
/** Leading payload shared by both `@for` outer-open markers. */
|
|
23
|
+
export declare const HYDRATION_FOR_PREFIX = "[f";
|
|
24
|
+
/** @for outer-open payload: the server rendered its @empty arm. */
|
|
25
|
+
export declare const HYDRATION_FOR_EMPTY = "[f0";
|
|
26
|
+
/** @for outer-open payload: the server rendered one or more direct-host items. */
|
|
27
|
+
export declare const HYDRATION_FOR_ITEMS = "[f1";
|
|
28
|
+
/** Index of the arm digit ('0' or '1') inside either @for outer-open payload. */
|
|
29
|
+
export declare const HYDRATION_FOR_ARM_INDEX: number;
|
|
30
|
+
/**
|
|
31
|
+
* Serialize one `useId()` value. The client regenerates the id the server
|
|
32
|
+
* already wrote, so the namespace prefix, the `in-` infix, the base-36 ordinal,
|
|
33
|
+
* and both colons must be produced in exactly one place: a divergence here
|
|
34
|
+
* survives every test that only checks one side and then mismatches every
|
|
35
|
+
* `useId` consumer at hydration.
|
|
36
|
+
*/
|
|
37
|
+
export declare function formatUseId(prefix: string, ordinal: number): string;
|
|
@@ -2,9 +2,35 @@ const INDEPENDENT_HYDRATE_MANIFEST_ATTR = "data-octane-independent";
|
|
|
2
2
|
const HYDRATE_INDEPENDENT_ATTR = "data-octane-hydrate-independent";
|
|
3
3
|
const HYDRATE_INPUT_ATTR = "data-octane-input";
|
|
4
4
|
const SIGNAL_CONTROL_ATTR = "data-octane-signal-control";
|
|
5
|
+
const HYDRATE_ID_ATTR = "data-octane-hydrate-id";
|
|
6
|
+
const HYDRATE_WHEN_ATTR = "data-octane-hydrate-when";
|
|
7
|
+
const HYDRATE_ID_COUNT_ATTR = "data-octane-hydrate-id-count";
|
|
8
|
+
const HYDRATE_SEED_ATTR = "data-octane-hydrate-seed";
|
|
9
|
+
const HYDRATE_MARKER_SELECTOR = "[data-octane-hydrate-id]";
|
|
10
|
+
const HYDRATION_START = "[";
|
|
11
|
+
const HYDRATION_END = "]";
|
|
12
|
+
const HYDRATION_FOR_PREFIX = "[f";
|
|
13
|
+
const HYDRATION_FOR_EMPTY = "[f0";
|
|
14
|
+
const HYDRATION_FOR_ITEMS = "[f1";
|
|
15
|
+
const HYDRATION_FOR_ARM_INDEX = HYDRATION_FOR_PREFIX.length;
|
|
16
|
+
function formatUseId(prefix, ordinal) {
|
|
17
|
+
return ":" + prefix + "in-" + ordinal.toString(36) + ":";
|
|
18
|
+
}
|
|
5
19
|
export {
|
|
20
|
+
HYDRATE_ID_ATTR,
|
|
21
|
+
HYDRATE_ID_COUNT_ATTR,
|
|
6
22
|
HYDRATE_INDEPENDENT_ATTR,
|
|
7
23
|
HYDRATE_INPUT_ATTR,
|
|
24
|
+
HYDRATE_MARKER_SELECTOR,
|
|
25
|
+
HYDRATE_SEED_ATTR,
|
|
26
|
+
HYDRATE_WHEN_ATTR,
|
|
27
|
+
HYDRATION_END,
|
|
28
|
+
HYDRATION_FOR_ARM_INDEX,
|
|
29
|
+
HYDRATION_FOR_EMPTY,
|
|
30
|
+
HYDRATION_FOR_ITEMS,
|
|
31
|
+
HYDRATION_FOR_PREFIX,
|
|
32
|
+
HYDRATION_START,
|
|
8
33
|
INDEPENDENT_HYDRATE_MANIFEST_ATTR,
|
|
9
|
-
SIGNAL_CONTROL_ATTR
|
|
34
|
+
SIGNAL_CONTROL_ATTR,
|
|
35
|
+
formatUseId
|
|
10
36
|
};
|
package/dist/react/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
"use client";
|
|
2
|
+
import { RENDERER_REGION_OWNER_TAG as RENDERER_REGION_OWNER } from "../runtime-tags.js";
|
|
2
3
|
import { ReactCompat } from "./react-compat.js";
|
|
3
4
|
import { bridgeReactContext } from "./react-compat-shared.js";
|
|
4
5
|
import * as React from "react";
|
|
@@ -21,7 +22,6 @@ import {
|
|
|
21
22
|
import { drainPassiveEffects } from "../runtime.js";
|
|
22
23
|
import { readNearestProviderValue } from "./fiber-adapter.js";
|
|
23
24
|
import { __hostContextFiberWalks } from "./fiber-adapter.js";
|
|
24
|
-
const RENDERER_REGION_OWNER = /* @__PURE__ */ Symbol.for("octane.renderer-region.owner");
|
|
25
25
|
const EMPTY_SNAPSHOT = { entries: [], values: [] };
|
|
26
26
|
function hostedRootEnvelope(props) {
|
|
27
27
|
bindRendererRegionOwner(props);
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import {
|
|
3
|
+
CONTEXT_TAG as OCTANE_CONTEXT_TAG,
|
|
4
|
+
ELEMENT_TAG as OCTANE_ELEMENT_TAG,
|
|
5
|
+
REACT_CONTEXT_TAG
|
|
6
|
+
} from "../runtime-tags.js";
|
|
5
7
|
const REACT_MEMO_TAG = /* @__PURE__ */ Symbol.for("react.memo");
|
|
6
8
|
const REACT_LAZY_TAG = /* @__PURE__ */ Symbol.for("react.lazy");
|
|
7
9
|
const REACT_FORWARD_REF_TAG = /* @__PURE__ */ Symbol.for("react.forward_ref");
|
package/dist/react/shared.d.ts
CHANGED
|
@@ -64,8 +64,7 @@ export type OctaneRenderedNode = React.ReactElement & {
|
|
|
64
64
|
* `ComponentBody<P>` so one declaration can serve both hosts.
|
|
65
65
|
*/
|
|
66
66
|
export type OctaneReactComponent<P = Record<string, never>> = (props: P) => OctaneRenderedNode;
|
|
67
|
-
|
|
68
|
-
export declare const REACT_CONTEXT_TAG: unique symbol;
|
|
67
|
+
export { REACT_CONTEXT_TAG } from '../runtime-tags.js';
|
|
69
68
|
/** The client's stable opaque-host sentinel; the server writes real island HTML. */
|
|
70
69
|
export declare const OPAQUE_HOST_SENTINEL_COMMENT = "octane-compat-island";
|
|
71
70
|
export declare const OPAQUE_HOST_SENTINEL: Readonly<{
|
|
@@ -86,4 +85,3 @@ export declare function validateIslandChild(children: React.ReactNode): Transpor
|
|
|
86
85
|
* itself, which React resolves by remounting the wrapper.
|
|
87
86
|
*/
|
|
88
87
|
export declare function resolveHostedIsland(props: OctaneCompatProps | OctaneCompatComponentProps<unknown>): TransportedChild;
|
|
89
|
-
export {};
|
package/dist/react/shared.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
|
-
|
|
2
|
+
import { REACT_CONTEXT_TAG } from "../runtime-tags.js";
|
|
3
3
|
const OPAQUE_HOST_SENTINEL_COMMENT = "octane-compat-island";
|
|
4
4
|
const OPAQUE_HOST_SENTINEL = Object.freeze({
|
|
5
5
|
__html: `<!--${OPAQUE_HOST_SENTINEL_COMMENT}-->`
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-realm value-kind tags. Every one of these is a `Symbol.for` registry
|
|
3
|
+
* key, which makes the STRING the contract: the client runtime, the SSR
|
|
4
|
+
* serializer, the universal core, and the React compat layers all recognize a
|
|
5
|
+
* value by looking its tag up in the same global registry. A typo in any one of
|
|
6
|
+
* them mints a different symbol and silently fails every `$$kind` identity
|
|
7
|
+
* check that module performs, so each key is spelled exactly once, here.
|
|
8
|
+
*
|
|
9
|
+
* This leaf has no imports on purpose: a consumer that needs one tag must not
|
|
10
|
+
* pull in the DOM tables or the renderer graph to get it.
|
|
11
|
+
*/
|
|
12
|
+
/** `createElement` descriptor marker. */
|
|
13
|
+
export declare const ELEMENT_TAG: unique symbol;
|
|
14
|
+
/** `createPortal` descriptor marker. */
|
|
15
|
+
export declare const PORTAL_TAG: unique symbol;
|
|
16
|
+
/** React-compatible Fragment sentinel. */
|
|
17
|
+
export declare const FRAGMENT_TAG: unique symbol;
|
|
18
|
+
/** React-19 `<Activity>` sentinel. */
|
|
19
|
+
export declare const ACTIVITY_TAG: unique symbol;
|
|
20
|
+
/** Native Octane context object marker. */
|
|
21
|
+
export declare const CONTEXT_TAG: unique symbol;
|
|
22
|
+
/** `lazy()` wrapper marker. */
|
|
23
|
+
export declare const LAZY_COMPONENT_TAG: unique symbol;
|
|
24
|
+
/** Suspense boundary component type. */
|
|
25
|
+
export declare const SUSPENSE_TAG: unique symbol;
|
|
26
|
+
/** Lexical children body marker. */
|
|
27
|
+
export declare const CHILDREN_BLOCK_TAG: unique symbol;
|
|
28
|
+
/** Owner stamp for a renderer region's host boundary. */
|
|
29
|
+
export declare const RENDERER_REGION_OWNER_TAG: unique symbol;
|
|
30
|
+
/**
|
|
31
|
+
* React 19 context objects carry this `$$typeof`. Octane only ever READS it to
|
|
32
|
+
* recognize a foreign React context, but it is the same registry contract.
|
|
33
|
+
*/
|
|
34
|
+
export declare const REACT_CONTEXT_TAG: unique symbol;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const ELEMENT_TAG = /* @__PURE__ */ Symbol.for("octane.element");
|
|
2
|
+
const PORTAL_TAG = /* @__PURE__ */ Symbol.for("octane.portal");
|
|
3
|
+
const FRAGMENT_TAG = /* @__PURE__ */ Symbol.for("octane.Fragment");
|
|
4
|
+
const ACTIVITY_TAG = /* @__PURE__ */ Symbol.for("octane.Activity");
|
|
5
|
+
const CONTEXT_TAG = /* @__PURE__ */ Symbol.for("octane.context");
|
|
6
|
+
const LAZY_COMPONENT_TAG = /* @__PURE__ */ Symbol.for("octane.lazy");
|
|
7
|
+
const SUSPENSE_TAG = /* @__PURE__ */ Symbol.for("octane.suspense");
|
|
8
|
+
const CHILDREN_BLOCK_TAG = /* @__PURE__ */ Symbol.for("octane.childrenBlock");
|
|
9
|
+
const RENDERER_REGION_OWNER_TAG = /* @__PURE__ */ Symbol.for("octane.renderer-region.owner");
|
|
10
|
+
const REACT_CONTEXT_TAG = /* @__PURE__ */ Symbol.for("react.context");
|
|
11
|
+
export {
|
|
12
|
+
ACTIVITY_TAG,
|
|
13
|
+
CHILDREN_BLOCK_TAG,
|
|
14
|
+
CONTEXT_TAG,
|
|
15
|
+
ELEMENT_TAG,
|
|
16
|
+
FRAGMENT_TAG,
|
|
17
|
+
LAZY_COMPONENT_TAG,
|
|
18
|
+
PORTAL_TAG,
|
|
19
|
+
REACT_CONTEXT_TAG,
|
|
20
|
+
RENDERER_REGION_OWNER_TAG,
|
|
21
|
+
SUSPENSE_TAG
|
|
22
|
+
};
|
package/dist/runtime.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ import { EXTERNAL_HYDRATION_PROMISE, HYDRATION_RANGE_BOUNDARY } from './constant
|
|
|
19
19
|
import type { HydrateProps } from './hydration/types.js';
|
|
20
20
|
import type { IndependentHydrateActivator } from './hydration/independent-island.js';
|
|
21
21
|
import { snapshotHydrationControl } from './hydration/event-capture.js';
|
|
22
|
+
import { CONTEXT_TAG, ELEMENT_TAG, PORTAL_TAG } from './runtime-tags.js';
|
|
22
23
|
import { validateNativeReadWitness, type NativeReadWitness } from './signals/native-read-collector.js';
|
|
23
24
|
import { type NativeReadRetry } from './signals/native-read-retry.js';
|
|
24
25
|
import type { SignalActionFrame } from './signals/transition-action.js';
|
|
@@ -935,7 +936,6 @@ export declare function useSyncExternalStore<T>(subscribe: (onStoreChange: () =>
|
|
|
935
936
|
* suspended or failed render from leaking an uncommitted closure.
|
|
936
937
|
*/
|
|
937
938
|
export declare function useEffectEvent<F extends (...args: any[]) => any>(fn: F, slot?: symbol): F;
|
|
938
|
-
declare const CONTEXT_TAG: unique symbol;
|
|
939
939
|
export interface Context<T> {
|
|
940
940
|
(props: {
|
|
941
941
|
value: T;
|
|
@@ -1477,6 +1477,8 @@ export declare function child<T extends Node>(node: T): Node | null;
|
|
|
1477
1477
|
export declare function sibling(node: Node, n?: number): Node | null;
|
|
1478
1478
|
export declare function setText(node: Text, value: any): void;
|
|
1479
1479
|
declare const DIRECT_SIGNAL_BINDING: unique symbol;
|
|
1480
|
+
/** @internal Invalidate scalar-view caches when hydration retained a claimed publication. */
|
|
1481
|
+
export declare function hydrateClaimedBindingCaches(scope: Scope, fields: readonly (string | number)[]): void;
|
|
1480
1482
|
type DirectSignalBindingKind = 'text' | 'textOnlyChild' | 'attribute' | 'value' | 'checked';
|
|
1481
1483
|
type DirectSignalAttributeKind = 'attr' | 'class' | 'booleanAttr' | 'ariaAttr' | 'stringData';
|
|
1482
1484
|
interface DirectSignalBindingPolicy {
|
|
@@ -1783,7 +1785,7 @@ type HostPropSource = readonly [
|
|
|
1783
1785
|
value?: unknown,
|
|
1784
1786
|
merge?: boolean
|
|
1785
1787
|
];
|
|
1786
|
-
export declare function setHostPropSources(el: Element, sources: readonly HostPropSource[], prev: Record<string, unknown> | undefined, scope: Scope, hasNestedChildren?: boolean, readStyle?: (value: unknown) => unknown, deferControl?: boolean
|
|
1788
|
+
export declare function setHostPropSources(el: Element, sources: readonly HostPropSource[], prev: Record<string, unknown> | undefined, scope: Scope, hasNestedChildren?: boolean, readStyle?: (value: unknown) => unknown, deferControl?: boolean): Record<string, unknown>;
|
|
1787
1789
|
/** @internal Compiler target for spread-bearing hosts containing direct signals. */
|
|
1788
1790
|
export declare function bindSignalHostPropSources(scope: Scope, previous: unknown, element: Element, sources: readonly HostPropSource[], site: string, hasNestedChildren?: boolean, readStyle?: (value: unknown) => unknown): unknown;
|
|
1789
1791
|
export declare function setSpread(el: Element, value: any, prev: any, mountScope?: Scope, skipDangerouslySetInnerHTML?: boolean, skipFormControls?: boolean): void;
|
|
@@ -1884,7 +1886,7 @@ export declare function markNativeChangeDiagnosticStatic(el: Element): void;
|
|
|
1884
1886
|
* attribute write never clobbers what the user typed, and it keeps SSR
|
|
1885
1887
|
* output, form.reset() baselines, and differential byte-compares aligned.
|
|
1886
1888
|
*/
|
|
1887
|
-
export declare function setValue(el: Element, value: unknown
|
|
1889
|
+
export declare function setValue(el: Element, value: unknown): void;
|
|
1888
1890
|
export declare function setChecked(el: Element, value: unknown): void;
|
|
1889
1891
|
/**
|
|
1890
1892
|
* Compiler-only checked binding for a statically-known checkbox/radio whose
|
|
@@ -1939,16 +1941,6 @@ interface PortalSlot {
|
|
|
1939
1941
|
* down and removes its DOM from `target`.
|
|
1940
1942
|
*/
|
|
1941
1943
|
export declare function portal(parentScope: Scope, slotKey: number, target: Element | DocumentFragment, body: ComponentBody, props: any, host?: Node, env?: any[], fragmentOwners?: FragmentInstance | readonly FragmentInstance[], fragmentAnchor?: Node): void;
|
|
1942
|
-
/**
|
|
1943
|
-
* `createPortal(children, target, keyOrProps?)`. A string/number third argument
|
|
1944
|
-
* is a reconciliation key. An object remains Octane's optional props for a
|
|
1945
|
-
* function portal body. The
|
|
1946
|
-
* compiler recognises `{createPortal(...)}` at JSX child position and lowers it to a
|
|
1947
|
-
* direct `portal(...)` runtime call — no descriptor allocation on the hot path. This
|
|
1948
|
-
* function exists so non-JSX call sites (storing in a variable, passing through props,
|
|
1949
|
-
* etc.) still produce something the runtime can dispatch on.
|
|
1950
|
-
*/
|
|
1951
|
-
declare const PORTAL_TAG: unique symbol;
|
|
1952
1944
|
export interface PortalDescriptor {
|
|
1953
1945
|
$$kind: typeof PORTAL_TAG;
|
|
1954
1946
|
key: string | null;
|
|
@@ -1957,7 +1949,6 @@ export interface PortalDescriptor {
|
|
|
1957
1949
|
props: any;
|
|
1958
1950
|
}
|
|
1959
1951
|
export declare function createPortal(body: ComponentBody | ElementDescriptor | unknown, target: Element | DocumentFragment, props?: any): PortalDescriptor;
|
|
1960
|
-
declare const ELEMENT_TAG: unique symbol;
|
|
1961
1952
|
export interface ElementDescriptor<P = any> {
|
|
1962
1953
|
$$kind: typeof ELEMENT_TAG;
|
|
1963
1954
|
type: ComponentBody<P> | string | typeof Fragment;
|