@tanstack/redact 0.0.14 → 0.0.16

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 (90) hide show
  1. package/dist/core/internal.d.ts +23 -39
  2. package/dist/core/internal.js +7 -23
  3. package/dist/core/internal.js.map +3 -3
  4. package/dist/dom/dispatcher.d.ts +3 -1
  5. package/dist/dom/dispatcher.js +104 -97
  6. package/dist/dom/dispatcher.js.map +2 -2
  7. package/dist/dom/dom.js +1 -1
  8. package/dist/dom/dom.js.map +2 -2
  9. package/dist/dom/event-replay.js +7 -29
  10. package/dist/dom/event-replay.js.map +2 -2
  11. package/dist/dom/features/class/full.js +16 -16
  12. package/dist/dom/features/class/full.js.map +2 -2
  13. package/dist/dom/features/class/stub.js +7 -7
  14. package/dist/dom/features/class/stub.js.map +2 -2
  15. package/dist/dom/features/context/full.js +7 -7
  16. package/dist/dom/features/context/full.js.map +2 -2
  17. package/dist/dom/features/context/stub.js +3 -3
  18. package/dist/dom/features/context/stub.js.map +2 -2
  19. package/dist/dom/features/forward-ref/full.js +11 -11
  20. package/dist/dom/features/forward-ref/full.js.map +2 -2
  21. package/dist/dom/features/hydration/full.d.ts +26 -14
  22. package/dist/dom/features/hydration/full.js +417 -92
  23. package/dist/dom/features/hydration/full.js.map +2 -2
  24. package/dist/dom/features/hydration/stub.d.ts +13 -12
  25. package/dist/dom/features/hydration/stub.js +23 -8
  26. package/dist/dom/features/hydration/stub.js.map +2 -2
  27. package/dist/dom/features/lazy/full.js +3 -43
  28. package/dist/dom/features/lazy/full.js.map +2 -2
  29. package/dist/dom/features/lazy/stub.js +1 -1
  30. package/dist/dom/features/lazy/stub.js.map +2 -2
  31. package/dist/dom/features/memo/full.js +3 -3
  32. package/dist/dom/features/memo/full.js.map +2 -2
  33. package/dist/dom/features/memo/stub.js +1 -1
  34. package/dist/dom/features/memo/stub.js.map +2 -2
  35. package/dist/dom/features/portal/full.js +2 -2
  36. package/dist/dom/features/portal/full.js.map +2 -2
  37. package/dist/dom/features/suspense/full.js +151 -111
  38. package/dist/dom/features/suspense/full.js.map +2 -2
  39. package/dist/dom/reconcile.d.ts +3 -1
  40. package/dist/dom/reconcile.js +141 -129
  41. package/dist/dom/reconcile.js.map +2 -2
  42. package/dist/dom/root-internal.d.ts +9 -0
  43. package/dist/dom/root-internal.js +31 -0
  44. package/dist/dom/root-internal.js.map +7 -0
  45. package/dist/dom/root.d.ts +1 -1
  46. package/dist/dom/root.js +4 -136
  47. package/dist/dom/root.js.map +2 -2
  48. package/dist/dom/test-utils.js +1 -1
  49. package/dist/dom/test-utils.js.map +2 -2
  50. package/dist/react/children.js +4 -1
  51. package/dist/react/children.js.map +2 -2
  52. package/dist/react/class.js +8 -2
  53. package/dist/react/class.js.map +2 -2
  54. package/dist/react/context.js +4 -1
  55. package/dist/react/context.js.map +2 -2
  56. package/dist/react/index.js +1 -1
  57. package/dist/react/index.js.map +2 -2
  58. package/dist/react/shared-internals.d.ts +4 -7
  59. package/dist/react/shared-internals.js +4 -7
  60. package/dist/react/shared-internals.js.map +2 -2
  61. package/dist/server/stream.d.ts +5 -1
  62. package/dist/server/stream.js.map +2 -2
  63. package/package.json +1 -1
  64. package/src/core/internal.ts +30 -50
  65. package/src/dom/dispatcher.ts +114 -105
  66. package/src/dom/dom.ts +1 -1
  67. package/src/dom/event-replay.ts +14 -30
  68. package/src/dom/features/class/full.ts +16 -16
  69. package/src/dom/features/class/stub.ts +7 -7
  70. package/src/dom/features/context/full.ts +7 -7
  71. package/src/dom/features/context/stub.ts +3 -3
  72. package/src/dom/features/forward-ref/full.ts +11 -11
  73. package/src/dom/features/hydration/full.ts +519 -104
  74. package/src/dom/features/hydration/stub.ts +28 -14
  75. package/src/dom/features/lazy/full.ts +3 -56
  76. package/src/dom/features/lazy/stub.ts +1 -1
  77. package/src/dom/features/memo/full.ts +3 -3
  78. package/src/dom/features/memo/stub.ts +1 -1
  79. package/src/dom/features/portal/full.ts +2 -2
  80. package/src/dom/features/suspense/full.ts +176 -131
  81. package/src/dom/reconcile.ts +164 -170
  82. package/src/dom/root-internal.ts +40 -0
  83. package/src/dom/root.ts +5 -165
  84. package/src/dom/test-utils.ts +1 -1
  85. package/src/react/children.ts +4 -1
  86. package/src/react/class.ts +8 -2
  87. package/src/react/context.ts +4 -1
  88. package/src/react/index.ts +1 -1
  89. package/src/react/shared-internals.ts +8 -14
  90. package/src/server/stream.ts +9 -4
@@ -1,78 +1,62 @@
1
1
  // packages/redact/src/dom/features/hydration/full.ts
2
- import { FiberTag } from "../../../core";
3
- import { setProp } from "../../dom";
4
- import { findRoot } from "../../reconcile";
2
+ import {
3
+ FiberTag,
4
+ REACT_ELEMENT_TYPE
5
+ } from "../../../core";
6
+ import { createHostNode, setProp } from "../../dom";
5
7
  import { drainReplayQueue } from "../../event-replay";
6
- var GUARD_WINDOW_MS = 3e3;
8
+ import { discardPendingWork, findRoot, flushSyncWork, renderRoot } from "../../reconcile";
9
+ import { attachRootFiber, createFiberRoot } from "../../root-internal";
7
10
  function installHydrationScrollGuard() {
8
11
  if (typeof window === "undefined") return;
9
12
  const w = window;
10
- if (w.__redactScrollGuardInstalled) return;
11
- w.__redactScrollGuardInstalled = true;
12
- const guardStartedAt = performance.now();
13
+ if (w._r) return;
14
+ const time = Date.now;
15
+ const guardStartedAt = w._r = time();
13
16
  let lastUserScrollAt = 0;
14
- let programmatic = 0;
15
- w.__redactScrollLog = [];
16
- window.addEventListener(
17
+ let programmatic = false;
18
+ w.addEventListener(
17
19
  "scroll",
18
20
  () => {
19
- if (programmatic === 0) {
20
- lastUserScrollAt = performance.now();
21
- w.__redactScrollLog.push({ t: Math.round(lastUserScrollAt), ev: "user-scroll", y: window.scrollY });
21
+ if (!programmatic) {
22
+ lastUserScrollAt = time();
22
23
  }
23
24
  },
24
25
  { capture: true, passive: true }
25
26
  );
26
- const origScrollTo = window.scrollTo.bind(window);
27
- window.scrollTo = function(...args) {
28
- const now = performance.now();
29
- const inGuardWindow = now - guardStartedAt < GUARD_WINDOW_MS;
30
- const userScrolledRecently = lastUserScrollAt > 0 && now - lastUserScrollAt < 1500;
31
- if (inGuardWindow && userScrolledRecently) {
32
- w.__redactScrollLog.push({
33
- t: Math.round(now),
34
- ev: "suppressed",
35
- args: JSON.stringify(args).slice(0, 80),
36
- tSinceHydrate: Math.round(now - guardStartedAt),
37
- tSinceUserScroll: Math.round(now - lastUserScrollAt)
38
- });
27
+ const origScrollTo = w.scrollTo;
28
+ w.scrollTo = function(...args) {
29
+ const now = time();
30
+ if (now - guardStartedAt < 3e3 && now - lastUserScrollAt < 1500) {
39
31
  return;
40
32
  }
41
- w.__redactScrollLog.push({
42
- t: Math.round(now),
43
- ev: "allowed",
44
- args: JSON.stringify(args).slice(0, 80),
45
- tSinceHydrate: Math.round(now - guardStartedAt),
46
- inGuard: inGuardWindow,
47
- userScrolled: userScrolledRecently
48
- });
49
- programmatic++;
33
+ programmatic = true;
50
34
  try {
51
- return origScrollTo.apply(this, args);
35
+ return origScrollTo.apply(w, args);
52
36
  } finally {
53
37
  queueMicrotask(() => {
54
- programmatic = Math.max(0, programmatic - 1);
38
+ programmatic = false;
55
39
  });
56
40
  }
57
41
  };
58
42
  }
59
43
  var HydrationCursor = class {
60
- next;
61
- parent;
62
- endBefore;
44
+ n;
45
+ p;
46
+ e;
63
47
  constructor(parent, start = null, endBefore = null) {
64
- this.parent = parent;
65
- this.next = start ?? parent.firstChild;
66
- this.endBefore = endBefore;
48
+ this.p = parent;
49
+ this.n = start ?? parent.firstChild;
50
+ this.e = endBefore;
67
51
  }
68
- takeHostNode() {
69
- while (this.next && this.next !== this.endBefore) {
70
- const n = this.next;
52
+ take() {
53
+ while (this.n && this.n !== this.e) {
54
+ const n = this.n;
71
55
  if (n.nodeType !== 1 && n.nodeType !== 3) {
72
- this.next = n.nextSibling;
56
+ this.n = n.nextSibling;
73
57
  continue;
74
58
  }
75
- this.next = n.nextSibling;
59
+ this.n = n.nextSibling;
76
60
  return n;
77
61
  }
78
62
  return null;
@@ -84,10 +68,10 @@ var HydrationCursor = class {
84
68
  * name/property for meta, src for script). Non-matching nodes stay in
85
69
  * place so the SSR'd stylesheet/script order is preserved.
86
70
  */
87
- takeMatchingHeadElement(tag, props) {
71
+ head(tag, props) {
88
72
  const target = tag.toLowerCase();
89
- const keyAttrs = HEAD_KEY_ATTRS[target] ?? [];
90
- let scan = this.parent.firstChild;
73
+ const keyAttrs = HEAD_KEY_ATTRS[target];
74
+ let scan = this.p.firstChild;
91
75
  while (scan) {
92
76
  if (scan.nodeType === 1 && scan.tagName.toLowerCase() === target && headAttrsMatch(scan, props, keyAttrs)) {
93
77
  CLAIMED.add(scan);
@@ -97,58 +81,130 @@ var HydrationCursor = class {
97
81
  }
98
82
  return null;
99
83
  }
100
- remaining() {
101
- const out = [];
102
- let n = this.next;
103
- while (n && n !== this.endBefore) {
104
- out.push(n);
84
+ has() {
85
+ let n = this.n;
86
+ while (n && n !== this.e) {
87
+ if (n.nodeType === 1 || n.nodeType === 3) return true;
105
88
  n = n.nextSibling;
106
89
  }
107
- return out;
90
+ return false;
108
91
  }
109
92
  };
110
93
  var hydrationCursors = /* @__PURE__ */ new WeakMap();
94
+ var PROD_HYDRATION_ERROR = "Hydration mismatch.";
95
+ function isHydrationBailout(error) {
96
+ return !!error && error.f !== void 0;
97
+ }
98
+ function abortHydration(cause, fiber = null) {
99
+ const error = cause instanceof Error ? cause : new Error(PROD_HYDRATION_ERROR);
100
+ error.f = fiber;
101
+ throw error;
102
+ }
103
+ function hydrateRootImpl(container, initialChildren, options) {
104
+ const target = container;
105
+ const isDocument = container.nodeType === 9;
106
+ const body = isDocument ? target.body : null;
107
+ const root = createFiberRoot(target, options);
108
+ installHydrationScrollGuard();
109
+ const normalizedInitialChildren = isDocument ? normalizeDocumentChildren(initialChildren) : initialChildren;
110
+ let documentBodyFallback = false;
111
+ let hydrationError = null;
112
+ beginHydration(root);
113
+ try {
114
+ flushSyncWork(() => {
115
+ renderRoot(root, normalizedInitialChildren);
116
+ });
117
+ } catch (e) {
118
+ hydrationError = e;
119
+ }
120
+ endHydration(root);
121
+ if (hydrationError) {
122
+ if (!isHydrationBailout(hydrationError)) {
123
+ throw hydrationError;
124
+ }
125
+ let recoveryContainer = target;
126
+ let recoveryChildren = normalizedInitialChildren;
127
+ const hostRecovery = getRecoverableHostChildren(hydrationError);
128
+ if (hostRecovery) {
129
+ recoveryContainer = hostRecovery[0];
130
+ recoveryChildren = hostRecovery[1];
131
+ } else if (body) {
132
+ const bodyChildren = getRecoverableDocumentBodyChildren(hydrationError);
133
+ if (bodyChildren != null) {
134
+ documentBodyFallback = true;
135
+ recoveryContainer = body;
136
+ recoveryChildren = bodyChildren;
137
+ }
138
+ }
139
+ resetAfterHydrationFailure(root, recoveryContainer);
140
+ try {
141
+ flushSyncWork(() => {
142
+ renderRoot(root, recoveryChildren);
143
+ });
144
+ } catch (clientError) {
145
+ resetAfterHydrationFailure(root, recoveryContainer);
146
+ throw clientError;
147
+ }
148
+ }
149
+ drainReplayQueue();
150
+ return {
151
+ render(children) {
152
+ flushSyncWork(() => {
153
+ const normalized = isDocument ? normalizeDocumentChildren(children) : children;
154
+ renderRoot(
155
+ root,
156
+ documentBodyFallback ? getStaticDocumentBodyChildren(normalized) ?? normalized : normalized
157
+ );
158
+ });
159
+ },
160
+ unmount() {
161
+ flushSyncWork(() => {
162
+ renderRoot(root, null);
163
+ });
164
+ }
165
+ };
166
+ }
111
167
  var HEAD_KEY_ATTRS = {
112
168
  link: ["rel", "href", "sizes", "type"],
113
169
  meta: ["name", "property", "charset", "http-equiv"],
114
- script: ["src", "type"],
115
- style: [],
116
- title: []
170
+ script: ["src", "type"]
117
171
  };
118
172
  var DOCUMENT_HEAD_TAGS = /* @__PURE__ */ new Set(["base", "link", "meta", "script", "style", "title"]);
119
173
  var CLAIMED = /* @__PURE__ */ new WeakSet();
120
174
  function headAttrsMatch(el, props, keys) {
121
175
  if (CLAIMED.has(el)) return false;
122
- if (keys.length === 0) return true;
176
+ if (!keys) return true;
177
+ let matched = false;
123
178
  for (const k of keys) {
124
179
  const propVal = props[k] ?? (k === "http-equiv" ? props.httpEquiv : void 0);
125
180
  const elVal = el.getAttribute(k);
126
181
  if (propVal == null && elVal == null) continue;
182
+ matched = true;
127
183
  if (propVal == null || elVal == null) continue;
128
184
  if (String(propVal) !== elVal) return false;
129
185
  }
130
- return keys.some((k) => props[k] != null || el.hasAttribute(k));
186
+ return matched;
131
187
  }
132
188
  function beginHydration(root) {
133
- root.hydrating = true;
134
- hydrationCursors.set(root.current, new HydrationCursor(root.container));
189
+ root.h = true;
190
+ hydrationCursors.set(root.r, new HydrationCursor(root.c));
135
191
  }
136
192
  function endHydration(root) {
137
- root.hydrating = false;
138
- hydrationCursors.delete(root.current);
193
+ root.h = false;
194
+ hydrationCursors.delete(root.r);
139
195
  }
140
196
  function tryConsumeBoundary(parent) {
141
197
  const cursor = hydrationCursors.get(findHostParent(parent));
142
198
  if (!cursor) return null;
143
- const peek = cursor.next;
199
+ const peek = cursor.n;
144
200
  if (!peek || peek.nodeType !== 8) return null;
145
201
  const data = peek.data;
146
202
  const m = /^(\$\??)(\d+)$/.exec(data);
147
203
  if (!m) return null;
148
- const kind = m[1] === "$?" ? "pending" : "resolved";
204
+ const kind = m[1] === "$?" ? 1 : 0;
149
205
  const id = Number(m[2]);
150
206
  const startMark = peek;
151
- cursor.next = startMark.nextSibling;
207
+ cursor.n = startMark.nextSibling;
152
208
  let endMark = null;
153
209
  let scan = startMark.nextSibling;
154
210
  while (scan) {
@@ -159,12 +215,12 @@ function tryConsumeBoundary(parent) {
159
215
  scan = scan.nextSibling;
160
216
  }
161
217
  if (!endMark) return null;
162
- return { kind, id, startMark, endMark };
218
+ return [kind, id, startMark, endMark];
163
219
  }
164
220
  function advanceCursorPast(parent, node) {
165
221
  const cursor = hydrationCursors.get(findHostParent(parent));
166
222
  if (!cursor) return;
167
- cursor.next = node.nextSibling;
223
+ cursor.n = node.nextSibling;
168
224
  }
169
225
  function getHydrationCursor(hostFiber) {
170
226
  return hydrationCursors.get(hostFiber);
@@ -180,20 +236,20 @@ function adoptHostDom(fiber, parent) {
180
236
  const cursor = hydrationCursors.get(hostParent);
181
237
  if (!cursor) return false;
182
238
  const tag = fiber.type.toLowerCase();
183
- const documentHeadParent = getDocumentHeadParent(cursor.parent, tag);
184
- const parentEl = cursor.parent;
239
+ const documentHeadParent = cursor.p.nodeType === 9 && DOCUMENT_HEAD_TAGS.has(tag) ? cursor.p.head : null;
240
+ const parentEl = cursor.p;
185
241
  const parentTag = parentEl.nodeType === 1 ? parentEl.tagName.toLowerCase() : "";
186
242
  const isHeadish = parentTag === "head" || parentTag === "html" || !!documentHeadParent;
187
243
  let candidate;
188
244
  if (documentHeadParent) {
189
- candidate = new HydrationCursor(documentHeadParent).takeMatchingHeadElement(
245
+ candidate = new HydrationCursor(documentHeadParent).head(
190
246
  tag,
191
- fiber.pendingProps ?? {}
247
+ fiber.pp ?? {}
192
248
  );
193
249
  } else if (isHeadish) {
194
- candidate = cursor.takeMatchingHeadElement(tag, fiber.pendingProps ?? {});
250
+ candidate = cursor.head(tag, fiber.pp ?? {});
195
251
  } else {
196
- candidate = cursor.takeHostNode();
252
+ candidate = cursor.take();
197
253
  }
198
254
  if (!candidate) {
199
255
  if (!isHeadish) onMismatch(fiber, null);
@@ -204,30 +260,32 @@ function adoptHostDom(fiber, parent) {
204
260
  return false;
205
261
  }
206
262
  fiber.dom = candidate;
207
- const props = fiber.pendingProps ?? {};
263
+ const props = fiber.pp ?? {};
208
264
  const isSvg = tag === "svg" || candidate.namespaceURI === "http://www.w3.org/2000/svg" && tag !== "foreignobject";
265
+ validateHydrationProps(fiber, candidate, props, tag, isSvg);
209
266
  for (const k in props) {
210
267
  if (k === "children") continue;
211
- if (k[0] === "o" && k[1] === "n" && typeof props[k] === "function") {
268
+ if (k[0] === "o" && k[1] === "n" && typeof props[k] == "function") {
212
269
  setProp(candidate, k, props[k], void 0, isSvg);
213
270
  }
214
271
  }
215
272
  hydrationCursors.set(fiber, new HydrationCursor(candidate));
216
273
  return true;
217
274
  }
218
- function getDocumentHeadParent(parent, tag) {
219
- if (parent.nodeType !== 9 || !DOCUMENT_HEAD_TAGS.has(tag)) return null;
220
- return parent.head;
221
- }
222
275
  function adoptTextDom(fiber, parent, text) {
223
276
  const cursor = hydrationCursors.get(findHostParent(parent));
224
277
  if (!cursor) return false;
225
- const candidate = cursor.takeHostNode();
226
- if (!candidate) return false;
278
+ const candidate = cursor.take();
279
+ if (!candidate) onMismatch(fiber, null);
227
280
  if (candidate.nodeType === 3) {
228
281
  if (candidate.data !== text) {
229
- ;
230
- candidate.data = text;
282
+ if (true) {
283
+ failHydration(
284
+ fiber,
285
+ new Error(`Hydration text mismatch: expected "${text}" but found "${candidate.data}".`)
286
+ );
287
+ }
288
+ failHydration(fiber);
231
289
  }
232
290
  fiber.dom = candidate;
233
291
  return true;
@@ -244,21 +302,286 @@ function findHostParent(fiber) {
244
302
  }
245
303
  f = f.parent;
246
304
  }
247
- throw new Error("No host parent found");
305
+ if (true) {
306
+ throw new Error("No host parent found");
307
+ }
308
+ throw new Error();
248
309
  }
249
310
  function onMismatch(fiber, actualNode) {
250
- const root = findRoot(fiber);
251
- if (root?.onRecoverableError) {
252
- root.onRecoverableError(
311
+ if (true) {
312
+ failHydration(
313
+ fiber,
253
314
  new Error(
254
315
  `Hydration mismatch: expected <${fiber.type ?? "text"}> but found ${actualNode ? actualNode.nodeType === 1 ? actualNode.tagName : "text" : "nothing"}.`
255
316
  )
256
317
  );
257
318
  }
258
- if (actualNode && actualNode.parentNode) actualNode.parentNode.removeChild(actualNode);
319
+ failHydration(fiber);
320
+ }
321
+ function failHydration(fiber, error = new Error(PROD_HYDRATION_ERROR)) {
322
+ const root = findRoot(fiber);
323
+ if (root?.re) {
324
+ root.re(error);
325
+ }
326
+ abortHydration(error, findHostRecoveryParent(fiber) ?? fiber);
327
+ }
328
+ function findHostRecoveryParent(fiber) {
329
+ if (fiber.tag === FiberTag.Text) {
330
+ let directHost = fiber.parent;
331
+ while (directHost && (directHost.tag !== FiberTag.Host || !directHost.dom)) {
332
+ directHost = directHost.parent;
333
+ }
334
+ if (!directHost) return null;
335
+ let hasEvent;
336
+ const props = directHost.pp ?? directHost.mp;
337
+ if (props) {
338
+ for (const k in props) {
339
+ if (k[0] === "o" && k[1] === "n" && typeof props[k] == "function") {
340
+ hasEvent = true;
341
+ }
342
+ }
343
+ }
344
+ return findNearestSafeHostAboveComposite(
345
+ hasEvent ? directHost.parent : directHost.parent?.tag === FiberTag.Host ? directHost.parent : directHost
346
+ );
347
+ }
348
+ return findNearestSafeHostAboveComposite(fiber.parent);
349
+ }
350
+ function findNearestSafeHostAboveComposite(fiber) {
351
+ let host = null;
352
+ let f = fiber;
353
+ while (f) {
354
+ if (f.tag === FiberTag.Host && f.dom) {
355
+ if (!isSafeHostRecoveryElement(f)) return null;
356
+ const parentTag = f.parent?.tag;
357
+ if (!host || parentTag > FiberTag.Text && parentTag < FiberTag.Suspense) {
358
+ host = f;
359
+ }
360
+ }
361
+ f = f.parent;
362
+ }
363
+ return host;
364
+ }
365
+ function isSafeHostRecoveryElement(fiber) {
366
+ const tag = fiber.type.toLowerCase();
367
+ return tag !== "html" && tag !== "head" && tag !== "body";
368
+ }
369
+ function resetAfterHydrationFailure(root, container) {
370
+ discardPendingWork(root);
371
+ clearHydrationContainer(container);
372
+ attachRootFiber(root, container);
373
+ root.h = false;
374
+ }
375
+ function clearHydrationContainer(container) {
376
+ if (container.nodeType === 9) {
377
+ let node = container.firstChild;
378
+ while (node) {
379
+ const next = node.nextSibling;
380
+ if (node.nodeType !== 10) {
381
+ container.removeChild(node);
382
+ }
383
+ node = next;
384
+ }
385
+ return;
386
+ }
387
+ ;
388
+ container.textContent = "";
389
+ }
390
+ function getRecoverableHostChildren(error) {
391
+ const host = error.f;
392
+ if (host?.tag !== FiberTag.Host || !host.dom || !findNearestSafeHostAboveComposite(host.parent)) {
393
+ return null;
394
+ }
395
+ return [host.dom, (host.pp ?? host.mp)?.children ?? null];
396
+ }
397
+ function getRecoverableDocumentBodyChildren(error) {
398
+ const bodyFiber = findBodyAncestor(error.f);
399
+ if (!bodyFiber) return null;
400
+ return (bodyFiber.pp ?? bodyFiber.mp)?.children ?? null;
401
+ }
402
+ function findBodyAncestor(fiber) {
403
+ let f = fiber;
404
+ while (f) {
405
+ if (f.tag === FiberTag.Host && f.type === "body") {
406
+ return f === fiber ? null : f;
407
+ }
408
+ f = f.parent;
409
+ }
410
+ return null;
411
+ }
412
+ function getStaticDocumentBodyChildren(children) {
413
+ const list = toChildArray(children);
414
+ const html = list.find((child) => isHostElement(child, "html"));
415
+ if (!html) return null;
416
+ const htmlChildren = toChildArray(html.props?.children);
417
+ const body = htmlChildren.find((child) => isHostElement(child, "body"));
418
+ return body ? body.props?.children ?? null : null;
419
+ }
420
+ function normalizeDocumentChildren(children) {
421
+ const list = toChildArray(children);
422
+ const htmlIndex = list.findIndex((child) => isHostElement(child, "html"));
423
+ if (htmlIndex === -1) return children;
424
+ const headNodes = list.filter(isHeadElement);
425
+ if (headNodes.length === 0) return children;
426
+ const htmlElement = list[htmlIndex];
427
+ const normalizedHtml = hoistIntoHtmlHead(htmlElement, headNodes);
428
+ return list.filter((child, index) => index === htmlIndex || !isHeadElement(child)).map((child) => child === htmlElement ? normalizedHtml : child);
429
+ }
430
+ function hoistIntoHtmlHead(htmlElement, headNodes) {
431
+ const htmlChildren = toChildArray(htmlElement.props?.children);
432
+ const headIndex = htmlChildren.findIndex((child) => isHostElement(child, "head"));
433
+ let nextChildren;
434
+ if (headIndex === -1) {
435
+ nextChildren = [
436
+ createHostElement("head", { children: headNodes }),
437
+ ...htmlChildren
438
+ ];
439
+ } else {
440
+ const headElement = htmlChildren[headIndex];
441
+ const existingHeadChildren = toChildArray(headElement.props?.children);
442
+ const nextHead = {
443
+ ...headElement,
444
+ props: {
445
+ ...headElement.props,
446
+ children: [...headNodes, ...existingHeadChildren]
447
+ }
448
+ };
449
+ nextChildren = htmlChildren.map((child, index) => index === headIndex ? nextHead : child);
450
+ }
451
+ return {
452
+ ...htmlElement,
453
+ props: {
454
+ ...htmlElement.props,
455
+ children: nextChildren
456
+ }
457
+ };
458
+ }
459
+ function toChildArray(children) {
460
+ if (children == null || typeof children === "boolean") return [];
461
+ if (Array.isArray(children)) return children;
462
+ if (isReactElement(children)) return [children];
463
+ if (typeof children !== "string" && isIterable(children)) return Array.from(children);
464
+ return [children];
465
+ }
466
+ function isHeadElement(value) {
467
+ return isReactElement(value) && typeof value.type === "string" && DOCUMENT_HEAD_TAGS.has(value.type);
468
+ }
469
+ function isHostElement(value, tag) {
470
+ return isReactElement(value) && value.type === tag;
471
+ }
472
+ function isReactElement(value) {
473
+ return !!value && typeof value === "object" && value.$$typeof === REACT_ELEMENT_TYPE;
474
+ }
475
+ function isIterable(value) {
476
+ return !!value && typeof value[Symbol.iterator] == "function";
477
+ }
478
+ function createHostElement(type, props) {
479
+ return {
480
+ $$typeof: REACT_ELEMENT_TYPE,
481
+ type,
482
+ key: null,
483
+ ref: null,
484
+ props
485
+ };
486
+ }
487
+ function validateHydrationProps(fiber, el, props, tag, isSvg) {
488
+ if (props.suppressHydrationWarning) return;
489
+ let expected;
490
+ for (const k in props) {
491
+ const value = props[k];
492
+ if (k === "children" || k === "key" || k === "ref" || k === "suppressHydrationWarning" || k === "suppressContentEditableWarning" || k[0] === "o" && k[1] === "n" && typeof value == "function") continue;
493
+ if (k === "dangerouslySetInnerHTML") {
494
+ const probe = document.createElement("div");
495
+ probe.innerHTML = value?.__html ?? "";
496
+ if (el.innerHTML !== probe.innerHTML) {
497
+ if (true) {
498
+ failHydration(
499
+ fiber,
500
+ new Error(`Hydration HTML mismatch inside <${tag}>.`)
501
+ );
502
+ }
503
+ failHydration(fiber);
504
+ }
505
+ continue;
506
+ }
507
+ if (k === "value" || k === "defaultValue") {
508
+ if (tag === "select") continue;
509
+ if (tag === "input" || tag === "textarea") {
510
+ if (k === "value" || props.value == null) {
511
+ if (value != null && el.value !== "" + value) {
512
+ if (true) {
513
+ failHydration(fiber, new Error(`Hydration ${tag} value mismatch on <${tag}>.`));
514
+ }
515
+ failHydration(fiber);
516
+ }
517
+ }
518
+ continue;
519
+ }
520
+ }
521
+ if (tag === "input" && (k === "checked" || k === "defaultChecked")) {
522
+ if (k === "checked" || props.checked == null) {
523
+ if (value != null && el.checked !== !!value) {
524
+ if (true) {
525
+ failHydration(fiber, new Error(`Hydration checked mismatch on <input>.`));
526
+ }
527
+ failHydration(fiber);
528
+ }
529
+ }
530
+ continue;
531
+ }
532
+ if (tag === "option" && k === "selected") {
533
+ if (value != null && el.selected !== !!value) {
534
+ if (true) {
535
+ failHydration(fiber, new Error(`Hydration selected mismatch on <option>.`));
536
+ }
537
+ failHydration(fiber);
538
+ }
539
+ continue;
540
+ }
541
+ if (k === "style") {
542
+ expected ??= createHostNode(tag, isSvg);
543
+ setProp(expected, k, value, void 0, isSvg);
544
+ if (el.style.cssText !== expected.style.cssText) {
545
+ if (true) {
546
+ failHydration(
547
+ fiber,
548
+ new Error(`Hydration style mismatch on <${tag}>.`)
549
+ );
550
+ }
551
+ failHydration(fiber);
552
+ }
553
+ continue;
554
+ }
555
+ const stringifiedBoolean = k.startsWith("aria-") || k.startsWith("data-");
556
+ const attr = k === "className" ? "class" : k === "htmlFor" ? "for" : stringifiedBoolean ? k : k.toLowerCase();
557
+ let expectedValue;
558
+ if (value == null || value === false && !stringifiedBoolean) {
559
+ expectedValue = null;
560
+ } else {
561
+ expected ??= createHostNode(tag, isSvg);
562
+ setProp(expected, k, value, void 0, isSvg);
563
+ expectedValue = expected.getAttribute(attr);
564
+ }
565
+ const actualValue = el.getAttribute(attr);
566
+ if (expectedValue !== actualValue) {
567
+ if (true) {
568
+ failHydration(
569
+ fiber,
570
+ new Error(
571
+ `Hydration attribute mismatch on <${tag}> for "${attr}": expected ${formatHydrationValue(expectedValue)} but found ${formatHydrationValue(actualValue)}.`
572
+ )
573
+ );
574
+ }
575
+ failHydration(fiber);
576
+ }
577
+ }
578
+ }
579
+ function formatHydrationValue(value) {
580
+ return value == null ? "nothing" : JSON.stringify(value);
259
581
  }
260
582
  export {
261
583
  HydrationCursor,
584
+ abortHydration,
262
585
  adoptHostDom,
263
586
  adoptTextDom,
264
587
  advanceCursorPast,
@@ -268,7 +591,9 @@ export {
268
591
  endHydration,
269
592
  findHostParent,
270
593
  getHydrationCursor,
594
+ hydrateRootImpl,
271
595
  installHydrationScrollGuard,
596
+ isHydrationBailout,
272
597
  setHydrationCursor,
273
598
  tryConsumeBoundary
274
599
  };