octane 0.1.49 → 0.1.51

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 (37) hide show
  1. package/README.md +37 -0
  2. package/dist/cjs/runtime.cjs +180 -84
  3. package/dist/cjs/runtime.server.cjs +107 -28
  4. package/dist/cjs/signals/engine.cjs +9 -3
  5. package/dist/cjs/version.cjs +1 -1
  6. package/dist/compiler/bundler.js +76 -30
  7. package/dist/compiler/client-only-server.js +10 -6
  8. package/dist/compiler/compile-renderer-boundaries.js +2 -2
  9. package/dist/compiler/compile-universal.js +37 -16
  10. package/dist/compiler/compile.js +114 -46
  11. package/dist/compiler/css-module-imports.js +9 -5
  12. package/dist/compiler/hydrate-boundaries.js +105 -28
  13. package/dist/compiler/renderers.js +50 -18
  14. package/dist/compiler/runtime-requests.js +3 -1
  15. package/dist/compiler/slot-hooks.js +8 -4
  16. package/dist/compiler/vite.js +53 -9
  17. package/dist/jsx-runtime.d.ts +3 -0
  18. package/dist/react/index.d.ts +10 -9
  19. package/dist/react/index.js +5 -1
  20. package/dist/react/react-compat-envelope.d.ts +14 -0
  21. package/dist/react/react-compat-envelope.js +78 -0
  22. package/dist/react/react-compat-server.d.ts +7 -0
  23. package/dist/react/react-compat-server.js +128 -0
  24. package/dist/react/react-compat-shared.d.ts +59 -0
  25. package/dist/react/react-compat-shared.js +102 -0
  26. package/dist/react/react-compat.d.ts +8 -0
  27. package/dist/react/react-compat.js +222 -0
  28. package/dist/react/server.d.ts +3 -0
  29. package/dist/react/server.js +13 -4
  30. package/dist/runtime.d.ts +5 -1
  31. package/dist/runtime.js +178 -84
  32. package/dist/runtime.server.d.ts +34 -8
  33. package/dist/runtime.server.js +106 -28
  34. package/dist/signals/engine.js +9 -3
  35. package/dist/universal-core.js +115 -29
  36. package/dist/version.js +1 -1
  37. package/package.json +2 -1
package/README.md CHANGED
@@ -43,6 +43,43 @@ taking ownership of the existing markup. See the
43
43
  For the full story, see the
44
44
  [main README](https://github.com/octanejs/octane#readme).
45
45
 
46
+ ## React interoperability
47
+
48
+ `octane/react` exports both hosting directions: `ReactCompat` runs real React
49
+ components inside Octane, and `OctaneCompat` runs compiled Octane components
50
+ inside React 19. `ReactCompat` needs matching React and React DOM versions,
51
+ 19.2 or newer in the React 19 series.
52
+
53
+ ```tsrx
54
+ // App.tsrx — compiled by Octane.
55
+ import { ReactCompat } from 'octane/react';
56
+ import { Counter } from './Counter.react';
57
+
58
+ export function App() @{
59
+ <ReactCompat><Counter start={3} /></ReactCompat>
60
+ }
61
+ ```
62
+
63
+ `Counter.react.tsx` stays an ordinary React module, using hooks from `react` and
64
+ React's JSX transform with `/** @jsxImportSource react */`. Native `.tsrx`
65
+ components stay with Octane. In a mixed build, use `requireDirective: true` with
66
+ both compilers and mark Octane-owned `.tsx` and hook helper modules with
67
+ `/** @jsxImportSource octane */`. Do not alias React to Octane.
68
+
69
+ React retains its own state, events, refs, and component types, including class,
70
+ `memo`, `lazy`, and `forwardRef` components. Use
71
+ `bridgeReactContext(OctaneContext, ReactContext)` and `ReactCompat`'s `contexts`
72
+ prop to map native context into React. Within `OctaneCompat`, Octane's `use` or
73
+ `useContext` can read a real React context directly.
74
+
75
+ Both server implementations are exported from `octane/react/server`. Octane's
76
+ server compiler selects that entry automatically; React-owned server entries
77
+ that bypass it must select it explicitly. Each renderer commits its own work:
78
+ Octane transitions and `flushSync()` do not synchronously commit a
79
+ React root. The [React interoperability guide](https://octanejs.dev/docs/react-compat)
80
+ and [full ReactCompat reference](https://github.com/octanejs/octane/blob/main/docs/react-compat.md)
81
+ cover setup, pending updates, SSR buffering, hydration, and nesting limits.
82
+
46
83
  ## Browser compatibility
47
84
 
48
85
  See the [browser support guide](https://octanejs.dev/docs/browser-support) for
@@ -106,6 +106,7 @@ __export(runtime_exports, {
106
106
  finishNativeReadWitness: () => finishNativeReadWitness,
107
107
  flushSync: () => flushSync,
108
108
  forBlock: () => forBlock,
109
+ getRendererOwnerVisibility: () => getRendererOwnerVisibility,
109
110
  getRootRenderRetryKey: () => getRootRenderRetryKey,
110
111
  getTransitionFallbackTimeout: () => getTransitionFallbackTimeout,
111
112
  hasPendingWork: () => hasPendingWork,
@@ -186,6 +187,7 @@ __export(runtime_exports, {
186
187
  renderClientContextProvider: () => renderClientContextProvider,
187
188
  replaceRef: () => replaceRef,
188
189
  replayNativeReadWitness: () => replayNativeReadWitness,
190
+ reportRendererOwnerError: () => reportRendererOwnerError,
189
191
  requestFormReset: () => requestFormReset,
190
192
  resetFloatResourceState: () => resetFloatResourceState,
191
193
  scheduleRenderCleanup: () => scheduleRenderCleanup,
@@ -660,6 +662,7 @@ function runEffectCleanupCallback(callback) {
660
662
  }
661
663
  }
662
664
  const QUEUE = [];
665
+ let QUEUE_REINDEX_EPOCH = 0;
663
666
  let scheduled = false;
664
667
  let syncFlush = false;
665
668
  let inFlush = false;
@@ -2126,27 +2129,41 @@ function belongsToBlockTree(block, root) {
2126
2129
  }
2127
2130
  function drainHydrationRenderPhaseUpdates(root) {
2128
2131
  let renders = null;
2129
- for (; ; ) {
2130
- let index = -1;
2131
- for (let i = 0; i < QUEUE.length; i++) {
2132
- if (belongsToBlockTree(QUEUE[i], root)) {
2133
- index = i;
2134
- break;
2132
+ let read = 0;
2133
+ let write = 0;
2134
+ let reindexEpoch = QUEUE_REINDEX_EPOCH;
2135
+ try {
2136
+ while (read < QUEUE.length) {
2137
+ const block = QUEUE[read++];
2138
+ if (!belongsToBlockTree(block, root)) {
2139
+ QUEUE[write++] = block;
2140
+ continue;
2141
+ }
2142
+ if (!block.pending || block.disposed) continue;
2143
+ const seen = (renders ??= /* @__PURE__ */ new Map()).get(block) ?? 0;
2144
+ if (seen >= RENDER_PHASE_UPDATE_LIMIT) {
2145
+ throw new Error((0, import_error_codes_client_generated.formatClientError)(9));
2146
+ }
2147
+ renders.set(block, seen + 1);
2148
+ block.crossRenderUpdate = false;
2149
+ try {
2150
+ renderBlock(block);
2151
+ } catch (error) {
2152
+ handleRenderError(block, error);
2153
+ }
2154
+ if (reindexEpoch !== QUEUE_REINDEX_EPOCH) {
2155
+ reindexEpoch = QUEUE_REINDEX_EPOCH;
2156
+ read = 0;
2157
+ write = 0;
2135
2158
  }
2136
2159
  }
2137
- if (index === -1) return;
2138
- const block = QUEUE.splice(index, 1)[0];
2139
- if (!block.pending || block.disposed) continue;
2140
- const seen = (renders ??= /* @__PURE__ */ new Map()).get(block) ?? 0;
2141
- if (seen >= RENDER_PHASE_UPDATE_LIMIT) {
2142
- throw new Error((0, import_error_codes_client_generated.formatClientError)(9));
2143
- }
2144
- renders.set(block, seen + 1);
2145
- block.crossRenderUpdate = false;
2146
- try {
2147
- renderBlock(block);
2148
- } catch (error) {
2149
- handleRenderError(block, error);
2160
+ } finally {
2161
+ if (reindexEpoch === QUEUE_REINDEX_EPOCH) {
2162
+ while (read < QUEUE.length) {
2163
+ QUEUE[write++] = QUEUE[read++];
2164
+ }
2165
+ QUEUE.length = write;
2166
+ QUEUE_REINDEX_EPOCH++;
2150
2167
  }
2151
2168
  }
2152
2169
  }
@@ -2282,6 +2299,7 @@ function drainQueue() {
2282
2299
  }
2283
2300
  }
2284
2301
  QUEUE.length = 0;
2302
+ QUEUE_REINDEX_EPOCH++;
2285
2303
  if (activitiesToRehide !== null) {
2286
2304
  for (const activity of activitiesToRehide) SCHEDULED_VISIBILITY_DRIVER.rehide(activity);
2287
2305
  }
@@ -4220,29 +4238,53 @@ function __useStateWithGetter(initial, slot) {
4220
4238
  let HIDDEN_REVEAL_ACTIONS = null;
4221
4239
  function deferHiddenRevealAction(boundary, action) {
4222
4240
  const deferred = HIDDEN_REVEAL_ACTIONS ??= /* @__PURE__ */ new WeakMap();
4223
- const actions = deferred.get(boundary);
4224
- if (actions === void 0) deferred.set(boundary, [action]);
4225
- else actions.push(action);
4241
+ let queue = deferred.get(boundary);
4242
+ if (queue === void 0) {
4243
+ queue = { entries: [], live: 0 };
4244
+ deferred.set(boundary, queue);
4245
+ }
4246
+ const entry = { action, active: true, queue };
4247
+ queue.entries.push(entry);
4248
+ queue.live++;
4249
+ return entry;
4250
+ }
4251
+ function claimHiddenRevealAction(boundary, entry) {
4252
+ const queue = entry.queue;
4253
+ if (HIDDEN_REVEAL_ACTIONS?.get(boundary) !== queue) return null;
4254
+ if (!entry.active) return null;
4255
+ entry.active = false;
4256
+ if (--queue.live === 0) HIDDEN_REVEAL_ACTIONS.delete(boundary);
4257
+ return entry.action;
4258
+ }
4259
+ function cancelHiddenRevealAction(boundary, entry) {
4260
+ const queue = entry.queue;
4261
+ if (claimHiddenRevealAction(boundary, entry) === null || queue.live === 0) return;
4262
+ if (queue.entries.length > queue.live * 2) {
4263
+ queue.entries = queue.entries.filter((candidate) => candidate.active);
4264
+ }
4226
4265
  }
4227
4266
  function publishHiddenRevealActions(boundary) {
4228
- const actions = HIDDEN_REVEAL_ACTIONS?.get(boundary);
4229
- if (actions === void 0) return;
4267
+ const queue = HIDDEN_REVEAL_ACTIONS?.get(boundary);
4268
+ if (queue === void 0) return;
4269
+ const entries = queue.entries;
4230
4270
  if (boundary.__kind === "activityBlockSlot") {
4231
- for (let i = 0; i < actions.length; i++) {
4232
- const action = actions[i];
4271
+ const end = entries.length;
4272
+ for (let i = 0; i < end; i++) {
4273
+ const entry = entries[i];
4274
+ if (!entry.active) continue;
4233
4275
  enqueueEffectEventCommitAction(() => {
4234
- if (HIDDEN_REVEAL_ACTIONS?.get(boundary) !== actions) return;
4235
- const index = actions.indexOf(action);
4236
- if (index === -1) return;
4237
- actions.splice(index, 1);
4238
- if (actions.length === 0) HIDDEN_REVEAL_ACTIONS.delete(boundary);
4239
- return action();
4276
+ const claimed = claimHiddenRevealAction(boundary, entry);
4277
+ if (claimed === null) return;
4278
+ return claimed();
4240
4279
  });
4241
4280
  }
4242
4281
  return;
4243
4282
  }
4244
4283
  HIDDEN_REVEAL_ACTIONS.delete(boundary);
4245
- for (let i = 0; i < actions.length; i++) enqueueEffectEventCommitAction(actions[i]);
4284
+ for (let i = 0; i < entries.length; i++) {
4285
+ const entry = entries[i];
4286
+ if (entry.active) enqueueEffectEventCommitAction(entry.action);
4287
+ }
4246
4288
  }
4247
4289
  function useLinkedState(source, reconcile, options, slot) {
4248
4290
  if (typeof options === "symbol") {
@@ -5316,10 +5358,10 @@ function beginHydratePreload(state) {
5316
5358
  return promise;
5317
5359
  }
5318
5360
  function resolveHydrateWaiters(state, reason) {
5319
- if (state.hydrationWaiters.size === 0) return;
5320
- const waiters = [...state.hydrationWaiters];
5321
- state.hydrationWaiters.clear();
5322
- for (let i = 0; i < waiters.length; i++) waiters[i](reason);
5361
+ const waiters = state.hydrationWaiters;
5362
+ if (waiters === null) return;
5363
+ state.hydrationWaiters = null;
5364
+ for (const waiter of waiters) waiter(reason);
5323
5365
  }
5324
5366
  function waitForHydratePrefetchStrategy(state, strategy) {
5325
5367
  const controller = state.prefetchAbort;
@@ -5333,13 +5375,13 @@ function waitForHydratePrefetchStrategy(state, strategy) {
5333
5375
  if (settled) return;
5334
5376
  settled = true;
5335
5377
  cleanup?.();
5336
- state.hydrationWaiters.delete(onHydrate);
5378
+ state.hydrationWaiters?.delete(onHydrate);
5337
5379
  signal.removeEventListener("abort", onAbort);
5338
5380
  resolve(reason);
5339
5381
  };
5340
5382
  const onHydrate = () => finish("hydrate");
5341
5383
  const onAbort = () => finish("abort");
5342
- state.hydrationWaiters.add(onHydrate);
5384
+ (state.hydrationWaiters ??= /* @__PURE__ */ new Set()).add(onHydrate);
5343
5385
  signal.addEventListener("abort", onAbort, { once: true });
5344
5386
  cleanup = strategy._s?.({
5345
5387
  element: state.wrapper,
@@ -5739,7 +5781,7 @@ function createHydrateSlot(props, scope, boundaryId) {
5739
5781
  prefetchPromise: null,
5740
5782
  preloadPromise: null,
5741
5783
  loadedBody: null,
5742
- hydrationWaiters: /* @__PURE__ */ new Set(),
5784
+ hydrationWaiters: null,
5743
5785
  activationGeneration: 0,
5744
5786
  activationRequested: !serverPreserved,
5745
5787
  activationReady: !serverPreserved,
@@ -6314,6 +6356,21 @@ function readContextFromScope(scope, context) {
6314
6356
  recordContextDependency(scope.block, context);
6315
6357
  return readContextFrom(scope, scope.block, context);
6316
6358
  }
6359
+ function getRendererOwnerVisibility(scope) {
6360
+ if (findHiddenActivity(scope.block) !== null) return "activity";
6361
+ return findSuspenseHiddenTry(scope.block) !== null ? "suspense" : "visible";
6362
+ }
6363
+ function reportRendererOwnerError(scope, error) {
6364
+ const origin = scope.block;
6365
+ let owner = origin;
6366
+ while (owner !== null && blockSubtreeDisposed(owner)) owner = owner.parentBlock;
6367
+ const handler = findTryHandler(owner);
6368
+ if (handler !== null) reportCaughtError(owner, error, handler(error));
6369
+ else if (!reportUncaughtError(origin, error)) {
6370
+ if (typeof reportError === "function") reportError(error);
6371
+ else console.error(error);
6372
+ }
6373
+ }
6317
6374
  function useContextInternal(context) {
6318
6375
  recordContextDependency(CURRENT_BLOCK, context);
6319
6376
  return readContextFrom(CURRENT_SCOPE, CURRENT_BLOCK, context);
@@ -7292,6 +7349,8 @@ class HydrationCapability {
7292
7349
  abandoned = false;
7293
7350
  freshNodes = /* @__PURE__ */ new WeakSet();
7294
7351
  unframedRootRanges = /* @__PURE__ */ new WeakMap();
7352
+ /** Pairs discovered while matching an outer range; released with this hydration pass. */
7353
+ matchingCloses = null;
7295
7354
  /** First unclaimed root sibling after a compiled root clone; undefined until known. */
7296
7355
  rootRemainder;
7297
7356
  rootCleanupBoundary = null;
@@ -7328,7 +7387,8 @@ class HydrationCapability {
7328
7387
  return isBlockClose(node);
7329
7388
  }
7330
7389
  close(open) {
7331
- const found = findMatchingClose(open);
7390
+ const known = this.matchingCloses?.get(open);
7391
+ const found = known ?? findMatchingClose(open, this.matchingCloses ??= /* @__PURE__ */ new WeakMap());
7332
7392
  if (!this.hasAdjacentRangePair && isBlockOpen(open.previousSibling) && isBlockClose(found.nextSibling)) {
7333
7393
  this.hasAdjacentRangePair = true;
7334
7394
  }
@@ -7981,8 +8041,8 @@ function isBlockClose(node) {
7981
8041
  function isTextSeparator(node) {
7982
8042
  return node !== null && node.nodeType === 8 && node.data === import_constants.HYDRATION_TEXT_SEP;
7983
8043
  }
7984
- function findMatchingClose(open) {
7985
- let depth = 0;
8044
+ function findMatchingClose(open, matches) {
8045
+ let nested = null;
7986
8046
  let node = getNextSibling(open);
7987
8047
  for (; ; ) {
7988
8048
  if (node.nodeType === 8) {
@@ -7998,12 +8058,14 @@ function findMatchingClose(open) {
7998
8058
  }
7999
8059
  }
8000
8060
  if (close) {
8001
- if (depth === 0) {
8002
- return node;
8061
+ const found = node;
8062
+ if (nested === null || nested.length === 0) {
8063
+ matches.set(open, found);
8064
+ return found;
8003
8065
  }
8004
- depth -= 1;
8066
+ matches.set(nested.pop(), found);
8005
8067
  } else if (nestedOpen) {
8006
- depth += 1;
8068
+ (nested ??= []).push(node);
8007
8069
  }
8008
8070
  }
8009
8071
  node = getNextSibling(node);
@@ -9616,7 +9678,7 @@ function namespaceHeadElement(headKey, tag, attrs, text, authoredKey) {
9616
9678
  if (key !== void 0) config.key = key;
9617
9679
  return createElement(namespaceHead, config);
9618
9680
  }
9619
- function injectStyle(id, css) {
9681
+ function injectStyle(id, css, nonce) {
9620
9682
  if (_injectedStyles.has(id)) return;
9621
9683
  if (typeof document !== "undefined" && document.querySelector(`style[data-octane="${id}"], style[data-href="octane-${id}"]`)) {
9622
9684
  _injectedStyles.add(id);
@@ -9625,6 +9687,7 @@ function injectStyle(id, css) {
9625
9687
  _injectedStyles.add(id);
9626
9688
  const el = document.createElement("style");
9627
9689
  el.setAttribute("data-octane", id);
9690
+ if (nonce !== void 0) el.nonce = nonce;
9628
9691
  el.textContent = css;
9629
9692
  document.head.appendChild(el);
9630
9693
  }
@@ -19102,8 +19165,21 @@ function coalesceHydratedRanges(rootBlock, liteRanges) {
19102
19165
  const blockGroups = /* @__PURE__ */ new WeakMap();
19103
19166
  const scopeGroups = /* @__PURE__ */ new WeakMap();
19104
19167
  const ownerGroups = /* @__PURE__ */ new WeakMap();
19168
+ const groups = [];
19105
19169
  const seenBlocks = /* @__PURE__ */ new WeakSet();
19106
19170
  const seenScopes = /* @__PURE__ */ new WeakSet();
19171
+ let redundantMarkers = null;
19172
+ let removalRange = null;
19173
+ function canonicalGroup(group) {
19174
+ let canonical = group;
19175
+ while (canonical.parent !== null) canonical = canonical.parent;
19176
+ while (group.parent !== null && group.parent !== canonical) {
19177
+ const parent = group.parent;
19178
+ group.parent = canonical;
19179
+ group = parent;
19180
+ }
19181
+ return canonical;
19182
+ }
19107
19183
  function makeGroup(startNode, endNode, block, liteScope, owner) {
19108
19184
  if (!isBlockOpen(startNode) || !isBlockClose(endNode) || startNode === endNode) return null;
19109
19185
  if (startNode.parentNode === null || startNode.parentNode !== endNode.parentNode) return null;
@@ -19114,43 +19190,51 @@ function coalesceHydratedRanges(rootBlock, liteRanges) {
19114
19190
  start: startNode,
19115
19191
  end: endNode,
19116
19192
  depth: openDepth,
19193
+ parent: null,
19117
19194
  blocks: block === void 0 ? [] : [block],
19118
19195
  liteScopes: liteScope === void 0 ? [] : [liteScope],
19119
19196
  owners: owner === void 0 ? [] : [owner]
19120
19197
  };
19198
+ groups.push(group);
19121
19199
  if (block !== void 0) blockGroups.set(block, group);
19122
19200
  if (liteScope !== void 0) scopeGroups.set(liteScope, group);
19123
19201
  if (owner !== void 0) ownerGroups.set(owner, group);
19124
19202
  return group;
19125
19203
  }
19126
- function appendUnique(target, source) {
19127
- for (let i = 0; i < source.length; i++) {
19128
- if (target.indexOf(source[i]) === -1) target.push(source[i]);
19129
- }
19130
- }
19131
- function remapGroup(from, to) {
19132
- for (let i = 0; i < from.blocks.length; i++) blockGroups.set(from.blocks[i], to);
19133
- for (let i = 0; i < from.liteScopes.length; i++) scopeGroups.set(from.liteScopes[i], to);
19134
- for (let i = 0; i < from.owners.length; i++) ownerGroups.set(from.owners[i], to);
19135
- }
19136
19204
  function writeMultiplicity(group) {
19137
19205
  group.start.data = group.depth === 1 ? import_constants.HYDRATION_START : import_constants.HYDRATION_START + String(group.depth);
19138
19206
  group.end.data = group.depth === 1 ? import_constants.HYDRATION_END : import_constants.HYDRATION_END + String(group.depth);
19139
19207
  }
19208
+ function removeRedundantMarkerRun(anchor, after) {
19209
+ if (redundantMarkers === null) return;
19210
+ const adjacent = after ? anchor.nextSibling : anchor.previousSibling;
19211
+ if (adjacent === null || adjacent.nodeType !== 8 || !redundantMarkers.has(adjacent)) {
19212
+ return;
19213
+ }
19214
+ let edge = adjacent;
19215
+ for (; ; ) {
19216
+ const next = after ? edge.nextSibling : edge.previousSibling;
19217
+ if (next === null || next.nodeType !== 8 || !redundantMarkers.has(next)) break;
19218
+ edge = next;
19219
+ }
19220
+ const range = removalRange ??= anchor.ownerDocument.createRange();
19221
+ range.setStartBefore(after ? adjacent : edge);
19222
+ range.setEndAfter(after ? edge : adjacent);
19223
+ range.deleteContents();
19224
+ }
19140
19225
  function unifySharedPair(outer, inner) {
19226
+ outer = canonicalGroup(outer);
19227
+ inner = canonicalGroup(inner);
19141
19228
  if (outer === inner) return outer;
19142
19229
  outer.depth = Math.max(outer.depth, inner.depth);
19143
- appendUnique(outer.blocks, inner.blocks);
19144
- appendUnique(outer.liteScopes, inner.liteScopes);
19145
- appendUnique(outer.owners, inner.owners);
19146
- remapGroup(inner, outer);
19230
+ inner.parent = outer;
19147
19231
  writeMultiplicity(outer);
19148
19232
  return outer;
19149
19233
  }
19150
19234
  function rangesAreExactlyNested(outer, inner) {
19151
19235
  return outer.start.parentNode !== null && outer.start.parentNode === inner.start.parentNode && outer.end.parentNode === outer.start.parentNode && inner.end.parentNode === outer.start.parentNode && outer.start.nextSibling === inner.start && inner.end.nextSibling === outer.end;
19152
19236
  }
19153
- function borrowInnerRange(outer, inner) {
19237
+ function borrowGroupMembers(outer, inner) {
19154
19238
  for (let i = 0; i < inner.blocks.length; i++) {
19155
19239
  const block = inner.blocks[i];
19156
19240
  block.startMarker = outer.start;
@@ -19178,6 +19262,8 @@ function coalesceHydratedRanges(rootBlock, liteRanges) {
19178
19262
  }
19179
19263
  }
19180
19264
  function mergeExactRanges(outer, inner) {
19265
+ outer = canonicalGroup(outer);
19266
+ inner = canonicalGroup(inner);
19181
19267
  if (outer === inner) return outer;
19182
19268
  if (outer.start === inner.start && outer.end === inner.end) {
19183
19269
  return unifySharedPair(outer, inner);
@@ -19185,19 +19271,15 @@ function coalesceHydratedRanges(rootBlock, liteRanges) {
19185
19271
  if (!rangesAreExactlyNested(outer, inner)) return outer;
19186
19272
  const mergedDepth = outer.depth + inner.depth;
19187
19273
  if (!Number.isSafeInteger(mergedDepth)) return outer;
19188
- borrowInnerRange(outer, inner);
19189
- inner.start.remove();
19190
- inner.end.remove();
19274
+ (redundantMarkers ??= /* @__PURE__ */ new Set()).add(inner.start).add(inner.end);
19191
19275
  outer.depth = mergedDepth;
19192
- appendUnique(outer.blocks, inner.blocks);
19193
- appendUnique(outer.liteScopes, inner.liteScopes);
19194
- appendUnique(outer.owners, inner.owners);
19195
- remapGroup(inner, outer);
19276
+ inner.parent = outer;
19196
19277
  writeMultiplicity(outer);
19197
19278
  return outer;
19198
19279
  }
19199
19280
  function attachOwner(group, owner) {
19200
19281
  if (group === null) return;
19282
+ group = canonicalGroup(group);
19201
19283
  if (group.owners.indexOf(owner) === -1) group.owners.push(owner);
19202
19284
  ownerGroups.set(owner, group);
19203
19285
  }
@@ -19223,7 +19305,8 @@ function coalesceHydratedRanges(rootBlock, liteRanges) {
19223
19305
  }
19224
19306
  function mappedGroup(value) {
19225
19307
  if (value === null || typeof value !== "object") return void 0;
19226
- return ownerGroups.get(value) ?? scopeGroups.get(value);
19308
+ const group = ownerGroups.get(value) ?? scopeGroups.get(value);
19309
+ return group === void 0 ? void 0 : canonicalGroup(group);
19227
19310
  }
19228
19311
  function soleRangeCandidate(scope) {
19229
19312
  let only = void 0;
@@ -19241,7 +19324,8 @@ function coalesceHydratedRanges(rootBlock, liteRanges) {
19241
19324
  }
19242
19325
  const registered = scope._slots;
19243
19326
  if (registered !== null && registered.length === 1 && scope.children === null && registered[0].__kind === "childSlot" && registered[0].compactable && mayBorrowCandidate(registered[0])) {
19244
- return ownerGroups.get(registered[0]) ?? null;
19327
+ const group = ownerGroups.get(registered[0]);
19328
+ return group === void 0 ? null : canonicalGroup(group);
19245
19329
  }
19246
19330
  return null;
19247
19331
  }
@@ -19324,6 +19408,21 @@ function coalesceHydratedRanges(rootBlock, liteRanges) {
19324
19408
  for (let i = 0; i < registered.length; i++) visitSlot(registered[i]);
19325
19409
  }
19326
19410
  visitBlock(rootBlock);
19411
+ for (let i = 0; i < groups.length; i++) {
19412
+ const group = groups[i];
19413
+ const canonical = canonicalGroup(group);
19414
+ if (group.start !== canonical.start || group.end !== canonical.end) {
19415
+ borrowGroupMembers(canonical, group);
19416
+ }
19417
+ }
19418
+ if (redundantMarkers !== null) {
19419
+ for (let i = 0; i < groups.length; i++) {
19420
+ const group = groups[i];
19421
+ if (group.parent !== null) continue;
19422
+ removeRedundantMarkerRun(group.start, true);
19423
+ removeRedundantMarkerRun(group.end, false);
19424
+ }
19425
+ }
19327
19426
  }
19328
19427
  let ROOT_ERROR_HANDLERS = null;
19329
19428
  function registerRootErrorHandlers(root, options) {
@@ -19400,28 +19499,23 @@ function enqueueInlineCaughtError(state) {
19400
19499
  const handler = rootErrorHandlersFor(block)?.onCaughtError;
19401
19500
  if (handler === void 0) return;
19402
19501
  const error = state.err;
19403
- let parkedOwner = null;
19502
+ let parked = null;
19404
19503
  let cleanupRegistered = false;
19405
19504
  const action = (owner2) => {
19406
- parkedOwner = null;
19505
+ parked = null;
19407
19506
  if (block.disposed || state.block !== block) return;
19408
19507
  const hidden = owner2 ?? findScheduledVisibilityOwner(block, true);
19409
19508
  if (hidden !== null) {
19410
- parkedOwner = hidden;
19411
19509
  if (!cleanupRegistered) {
19412
19510
  cleanupRegistered = true;
19413
19511
  (block.cleanups ??= []).push(() => {
19414
- const owner3 = parkedOwner;
19415
- parkedOwner = null;
19416
- if (owner3 === null) return;
19417
- const actions = HIDDEN_REVEAL_ACTIONS?.get(owner3);
19418
- if (actions === void 0) return;
19419
- const index = actions.indexOf(action);
19420
- if (index !== -1) actions.splice(index, 1);
19421
- if (actions.length === 0) HIDDEN_REVEAL_ACTIONS.delete(owner3);
19512
+ const pending = parked;
19513
+ parked = null;
19514
+ if (pending === null) return;
19515
+ cancelHiddenRevealAction(pending.owner, pending.entry);
19422
19516
  });
19423
19517
  }
19424
- deferHiddenRevealAction(hidden, action);
19518
+ parked = { owner: hidden, entry: deferHiddenRevealAction(hidden, action) };
19425
19519
  return;
19426
19520
  }
19427
19521
  return { state, block, error, handler, resume: action };
@@ -20507,6 +20601,7 @@ function scriptResource(attrs) {
20507
20601
  finishNativeReadWitness,
20508
20602
  flushSync,
20509
20603
  forBlock,
20604
+ getRendererOwnerVisibility,
20510
20605
  getRootRenderRetryKey,
20511
20606
  getTransitionFallbackTimeout,
20512
20607
  hasPendingWork,
@@ -20587,6 +20682,7 @@ function scriptResource(attrs) {
20587
20682
  renderClientContextProvider,
20588
20683
  replaceRef,
20589
20684
  replayNativeReadWitness,
20685
+ reportRendererOwnerError,
20590
20686
  requestFormReset,
20591
20687
  resetFloatResourceState,
20592
20688
  scheduleRenderCleanup,