octane 0.1.46 → 0.1.48

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.
@@ -131,9 +131,15 @@ function adoptionContext(adoption, event) {
131
131
  };
132
132
  return context;
133
133
  }
134
+ function finishPendingAdoption(adoption) {
135
+ if (!adoption.pending) return;
136
+ adoption.pending = false;
137
+ adoption.entry.pendingAdoptionCount--;
138
+ }
134
139
  function disposeAdoption(adoption) {
135
140
  if (adoption.disposed) return;
136
141
  adoption.disposed = true;
142
+ finishPendingAdoption(adoption);
137
143
  adoption.entry.adoptions.delete(adoption.element);
138
144
  adoption.controller.abort();
139
145
  for (const unlink of adoption.unlinks) unlink();
@@ -144,29 +150,47 @@ function disposeAdoption(adoption) {
144
150
  }
145
151
  function flushQueuedEvents(record) {
146
152
  if (record.status !== "active") return;
147
- while (record.queuedEvents.length !== 0) {
148
- const queued = record.queuedEvents[0];
149
- if (!contains(record.root, queued.element)) {
150
- record.queuedEvents.shift();
151
- continue;
152
- }
153
- const range = nearestRange(record.root, queued.element);
154
- if (range !== queued.range || !rangeMatches(record, range)) {
155
- record.queuedEvents.shift();
156
- continue;
153
+ const queue = record.queuedEvents;
154
+ record.queuedEventFlushDepth++;
155
+ try {
156
+ while (record.queuedEventHead < queue.length) {
157
+ const index = record.queuedEventHead;
158
+ const queued = queue[index];
159
+ if (!contains(record.root, queued.element)) {
160
+ record.queuedEventHead = index + 1;
161
+ continue;
162
+ }
163
+ const range = nearestRange(record.root, queued.element);
164
+ if (range !== queued.range || !rangeMatches(record, range)) {
165
+ record.queuedEventHead = index + 1;
166
+ continue;
167
+ }
168
+ if (range?.status === "pending") return;
169
+ let adoption = record.adoptions.get(queued.element);
170
+ if (adoption === void 0) {
171
+ adoption = adoptElement(record, queued.element, range, queued.event);
172
+ }
173
+ if (adoption === void 0 || adoption.pending) return;
174
+ if (record.queuedEventHead !== index || queue[index] !== queued) continue;
175
+ record.queuedEventHead = index + 1;
176
+ record.entry.handleEvent?.(
177
+ queued.event,
178
+ queued.element,
179
+ adoptionContext(adoption, queued.event)
180
+ );
157
181
  }
158
- if (range?.status === "pending") return;
159
- let adoption = record.adoptions.get(queued.element);
160
- if (adoption === void 0) {
161
- adoption = adoptElement(record, queued.element, range, queued.event);
182
+ } finally {
183
+ record.queuedEventFlushDepth--;
184
+ if (record.queuedEventFlushDepth === 0 && record.queuedEventHead !== 0) {
185
+ const consumed = record.queuedEventHead;
186
+ if (consumed >= queue.length) {
187
+ queue.length = 0;
188
+ record.queuedEventHead = 0;
189
+ } else if (consumed >= queue.length - consumed) {
190
+ queue.splice(0, consumed);
191
+ record.queuedEventHead = 0;
192
+ }
162
193
  }
163
- if (adoption === void 0 || adoption.pending) return;
164
- record.queuedEvents.shift();
165
- record.entry.handleEvent?.(
166
- queued.event,
167
- queued.element,
168
- adoptionContext(adoption, queued.event)
169
- );
170
194
  }
171
195
  }
172
196
  function completeBehavior(record) {
@@ -175,9 +199,7 @@ function completeBehavior(record) {
175
199
  if (range.status === "pending") return;
176
200
  record.waitingRanges.delete(range);
177
201
  }
178
- for (const adoption of record.adoptions.values()) {
179
- if (adoption.pending) return;
180
- }
202
+ if (record.pendingAdoptionCount !== 0) return;
181
203
  flushQueuedEvents(record);
182
204
  if (record.queuedEvents.length !== 0) return;
183
205
  record.readiness.resolve();
@@ -227,9 +249,10 @@ function adoptElement(record, element, range, event) {
227
249
  }
228
250
  if (typeof result === "object" && result !== null && typeof result.then === "function") {
229
251
  adoption.pending = true;
252
+ record.pendingAdoptionCount++;
230
253
  const settled = Promise.resolve(result).then(
231
254
  (cleanup) => {
232
- adoption.pending = false;
255
+ finishPendingAdoption(adoption);
233
256
  if (typeof cleanup === "function") {
234
257
  if (adoption.disposed || adoption.controller.signal.aborted) cleanup();
235
258
  else adoption.cleanup = cleanup;
@@ -240,7 +263,7 @@ function adoptElement(record, element, range, event) {
240
263
  }
241
264
  },
242
265
  (error) => {
243
- adoption.pending = false;
266
+ finishPendingAdoption(adoption);
244
267
  if (adoption.disposed || record.controller.signal.aborted) return;
245
268
  disposeAdoption(adoption);
246
269
  failBehavior(record, error);
@@ -375,6 +398,7 @@ function disposeBehavior(record) {
375
398
  record.root.behaviorsById.delete(record.entry.id);
376
399
  }
377
400
  record.queuedEvents.length = 0;
401
+ record.queuedEventHead = 0;
378
402
  record.waitingRanges.clear();
379
403
  let firstError;
380
404
  for (const adoption of [...record.adoptions.values()]) {
@@ -428,8 +452,11 @@ function registerBehavior(root, entry) {
428
452
  readiness,
429
453
  status: "pending",
430
454
  adoptions: /* @__PURE__ */ new Map(),
455
+ pendingAdoptionCount: 0,
431
456
  waitingRanges: /* @__PURE__ */ new Set(),
432
457
  queuedEvents: [],
458
+ queuedEventHead: 0,
459
+ queuedEventFlushDepth: 0,
433
460
  unlinks: [linkSignal(root.controller.signal, controller)],
434
461
  initialScanComplete: false
435
462
  };
@@ -154,9 +154,15 @@ function adoptionContext(adoption, event) {
154
154
  };
155
155
  return context;
156
156
  }
157
+ function finishPendingAdoption(adoption) {
158
+ if (!adoption.pending) return;
159
+ adoption.pending = false;
160
+ adoption.entry.pendingAdoptionCount--;
161
+ }
157
162
  function disposeAdoption(adoption) {
158
163
  if (adoption.disposed) return;
159
164
  adoption.disposed = true;
165
+ finishPendingAdoption(adoption);
160
166
  adoption.entry.adoptions.delete(adoption.element);
161
167
  adoption.controller.abort();
162
168
  for (const unlink of adoption.unlinks) unlink();
@@ -167,29 +173,47 @@ function disposeAdoption(adoption) {
167
173
  }
168
174
  function flushQueuedEvents(record) {
169
175
  if (record.status !== "active") return;
170
- while (record.queuedEvents.length !== 0) {
171
- const queued = record.queuedEvents[0];
172
- if (!contains(record.root, queued.element)) {
173
- record.queuedEvents.shift();
174
- continue;
175
- }
176
- const range = nearestRange(record.root, queued.element);
177
- if (range !== queued.range || !rangeMatches(record, range)) {
178
- record.queuedEvents.shift();
179
- continue;
176
+ const queue = record.queuedEvents;
177
+ record.queuedEventFlushDepth++;
178
+ try {
179
+ while (record.queuedEventHead < queue.length) {
180
+ const index = record.queuedEventHead;
181
+ const queued = queue[index];
182
+ if (!contains(record.root, queued.element)) {
183
+ record.queuedEventHead = index + 1;
184
+ continue;
185
+ }
186
+ const range = nearestRange(record.root, queued.element);
187
+ if (range !== queued.range || !rangeMatches(record, range)) {
188
+ record.queuedEventHead = index + 1;
189
+ continue;
190
+ }
191
+ if (range?.status === "pending") return;
192
+ let adoption = record.adoptions.get(queued.element);
193
+ if (adoption === void 0) {
194
+ adoption = adoptElement(record, queued.element, range, queued.event);
195
+ }
196
+ if (adoption === void 0 || adoption.pending) return;
197
+ if (record.queuedEventHead !== index || queue[index] !== queued) continue;
198
+ record.queuedEventHead = index + 1;
199
+ record.entry.handleEvent?.(
200
+ queued.event,
201
+ queued.element,
202
+ adoptionContext(adoption, queued.event)
203
+ );
180
204
  }
181
- if (range?.status === "pending") return;
182
- let adoption = record.adoptions.get(queued.element);
183
- if (adoption === void 0) {
184
- adoption = adoptElement(record, queued.element, range, queued.event);
205
+ } finally {
206
+ record.queuedEventFlushDepth--;
207
+ if (record.queuedEventFlushDepth === 0 && record.queuedEventHead !== 0) {
208
+ const consumed = record.queuedEventHead;
209
+ if (consumed >= queue.length) {
210
+ queue.length = 0;
211
+ record.queuedEventHead = 0;
212
+ } else if (consumed >= queue.length - consumed) {
213
+ queue.splice(0, consumed);
214
+ record.queuedEventHead = 0;
215
+ }
185
216
  }
186
- if (adoption === void 0 || adoption.pending) return;
187
- record.queuedEvents.shift();
188
- record.entry.handleEvent?.(
189
- queued.event,
190
- queued.element,
191
- adoptionContext(adoption, queued.event)
192
- );
193
217
  }
194
218
  }
195
219
  function completeBehavior(record) {
@@ -198,9 +222,7 @@ function completeBehavior(record) {
198
222
  if (range.status === "pending") return;
199
223
  record.waitingRanges.delete(range);
200
224
  }
201
- for (const adoption of record.adoptions.values()) {
202
- if (adoption.pending) return;
203
- }
225
+ if (record.pendingAdoptionCount !== 0) return;
204
226
  flushQueuedEvents(record);
205
227
  if (record.queuedEvents.length !== 0) return;
206
228
  record.readiness.resolve();
@@ -250,9 +272,10 @@ function adoptElement(record, element, range, event) {
250
272
  }
251
273
  if (typeof result === "object" && result !== null && typeof result.then === "function") {
252
274
  adoption.pending = true;
275
+ record.pendingAdoptionCount++;
253
276
  const settled = Promise.resolve(result).then(
254
277
  (cleanup) => {
255
- adoption.pending = false;
278
+ finishPendingAdoption(adoption);
256
279
  if (typeof cleanup === "function") {
257
280
  if (adoption.disposed || adoption.controller.signal.aborted) cleanup();
258
281
  else adoption.cleanup = cleanup;
@@ -263,7 +286,7 @@ function adoptElement(record, element, range, event) {
263
286
  }
264
287
  },
265
288
  (error) => {
266
- adoption.pending = false;
289
+ finishPendingAdoption(adoption);
267
290
  if (adoption.disposed || record.controller.signal.aborted) return;
268
291
  disposeAdoption(adoption);
269
292
  failBehavior(record, error);
@@ -398,6 +421,7 @@ function disposeBehavior(record) {
398
421
  record.root.behaviorsById.delete(record.entry.id);
399
422
  }
400
423
  record.queuedEvents.length = 0;
424
+ record.queuedEventHead = 0;
401
425
  record.waitingRanges.clear();
402
426
  let firstError;
403
427
  for (const adoption of [...record.adoptions.values()]) {
@@ -451,8 +475,11 @@ function registerBehavior(root, entry) {
451
475
  readiness,
452
476
  status: "pending",
453
477
  adoptions: /* @__PURE__ */ new Map(),
478
+ pendingAdoptionCount: 0,
454
479
  waitingRanges: /* @__PURE__ */ new Set(),
455
480
  queuedEvents: [],
481
+ queuedEventHead: 0,
482
+ queuedEventFlushDepth: 0,
456
483
  unlinks: [linkSignal(root.controller.signal, controller)],
457
484
  initialScanComplete: false
458
485
  };
@@ -1847,11 +1847,6 @@ function scheduleRender(block) {
1847
1847
  }
1848
1848
  let DRAIN_ID = 0;
1849
1849
  const RENDER_PHASE_UPDATE_LIMIT = 25;
1850
- function blockDepth(b) {
1851
- let d = 0;
1852
- for (let p = b.parentBlock; p !== null; p = p.parentBlock) d++;
1853
- return d;
1854
- }
1855
1850
  function belongsToBlockTree(block, root) {
1856
1851
  for (let current = block; current !== null; current = current.parentBlock) {
1857
1852
  if (current === root) return true;
@@ -1885,8 +1880,25 @@ function drainHydrationRenderPhaseUpdates(root) {
1885
1880
  }
1886
1881
  }
1887
1882
  function sortWaveByDepth(wave) {
1883
+ const queued = new Set(wave);
1888
1884
  const depth = /* @__PURE__ */ new Map();
1889
- for (let i = 0; i < wave.length; i++) depth.set(wave[i], blockDepth(wave[i]));
1885
+ const path = [];
1886
+ for (let i = 0; i < wave.length; i++) {
1887
+ let current = wave[i];
1888
+ let knownDepth;
1889
+ while (current !== null) {
1890
+ knownDepth = depth.get(current);
1891
+ if (knownDepth !== void 0) break;
1892
+ path.push(current);
1893
+ current = current.parentBlock;
1894
+ }
1895
+ let currentDepth = knownDepth ?? -1;
1896
+ while (path.length > 0) {
1897
+ const block = path.pop();
1898
+ currentDepth++;
1899
+ if (queued.has(block)) depth.set(block, currentDepth);
1900
+ }
1901
+ }
1890
1902
  wave.sort((a, b) => depth.get(a) - depth.get(b));
1891
1903
  return wave;
1892
1904
  }
@@ -8727,21 +8739,25 @@ function setHostPropSources(el, sources, prev, scope, hasNestedChildren = false)
8727
8739
  }
8728
8740
  }
8729
8741
  const values = /* @__PURE__ */ new Map();
8742
+ let needsWinningOrderSort = false;
8730
8743
  for (const writer of props.values()) {
8731
8744
  if (writer.rawName === "key") continue;
8732
8745
  const [identity, name] = normalizedHostProp(el, writer.rawName);
8733
8746
  const previous = values.get(identity);
8734
- if (previous === void 0 || previous[3] < writer.lastOrder) {
8735
- values.set(identity, [
8736
- process.env.NODE_ENV !== "production" && (writer.rawName === "tabIndex" || writer.rawName === "htmlFor") ? writer.rawName : name,
8737
- writer.value,
8738
- writer.firstOrder,
8739
- writer.lastOrder
8740
- ]);
8747
+ if (previous !== void 0) {
8748
+ if (previous[3] >= writer.lastOrder) continue;
8749
+ needsWinningOrderSort = true;
8741
8750
  }
8751
+ values.set(identity, [
8752
+ process.env.NODE_ENV !== "production" && (writer.rawName === "tabIndex" || writer.rawName === "htmlFor") ? writer.rawName : name,
8753
+ writer.value,
8754
+ writer.firstOrder,
8755
+ writer.lastOrder
8756
+ ]);
8742
8757
  }
8743
8758
  const resolved = /* @__PURE__ */ Object.create(null);
8744
- const ordered = [...values.values()].sort((a, b) => a[2] - b[2]);
8759
+ const ordered = [...values.values()];
8760
+ if (needsWinningOrderSort) ordered.sort((a, b) => a[2] - b[2]);
8745
8761
  for (const [name, value] of ordered) resolved[name] = value;
8746
8762
  const formHost = el.localName === "input" || el.localName === "textarea" || el.localName === "select";
8747
8763
  setSpread(el, resolved, prev, scope, true, formHost);
@@ -9593,6 +9609,9 @@ let CHECKED_RESTORE = null;
9593
9609
  let SELECT_SYNCS = [];
9594
9610
  let SELECT_DEFAULT_SYNCS = [];
9595
9611
  let DEV_FORM_CHECKS = process.env.NODE_ENV === "production" ? null : [];
9612
+ const DEV_FORM_CHECK_MARK = /* @__PURE__ */ Symbol("octane.devFormCheck");
9613
+ const DEV_FORM_CHECK_LINEAR_LIMIT = 8;
9614
+ let DEV_FORM_CHECK_GENERATION = 1;
9596
9615
  let AUTOFOCUS_QUEUE = [];
9597
9616
  function queueControlledCommit(queue, item) {
9598
9617
  queue.push(item);
@@ -9602,6 +9621,18 @@ function queueControlledCommit(queue, item) {
9602
9621
  if (index !== -1) queue.splice(index, 1);
9603
9622
  });
9604
9623
  }
9624
+ function queueDevFormCheck(queue, el) {
9625
+ queue.push(el);
9626
+ if (ROOT_RENDER_TRANSACTION !== null) {
9627
+ const host = el;
9628
+ const generation = DEV_FORM_CHECK_GENERATION;
9629
+ journalUndo(() => {
9630
+ const index = queue.lastIndexOf(el);
9631
+ if (index !== -1) queue.splice(index, 1);
9632
+ if (host[DEV_FORM_CHECK_MARK] === generation) delete host[DEV_FORM_CHECK_MARK];
9633
+ });
9634
+ }
9635
+ }
9605
9636
  function hasControlledSyncs() {
9606
9637
  return SELECT_SYNCS.length > 0 || SELECT_DEFAULT_SYNCS.length > 0 || DEV_FORM_CHECKS !== null && DEV_FORM_CHECKS.length > 0 || AUTOFOCUS_QUEUE.length > 0;
9607
9638
  }
@@ -9755,7 +9786,19 @@ function queueDevFormDiagnostic(el, scope, force = false) {
9755
9786
  const q = DEV_FORM_CHECKS;
9756
9787
  if (q === null || !force && !hasDevFormDiagnosticContext(el, scope)) return;
9757
9788
  if (!force && !hasPotentialFormDiagnostic(el)) return;
9758
- if (q.indexOf(el) === -1) queueControlledCommit(q, el);
9789
+ if (q.length < DEV_FORM_CHECK_LINEAR_LIMIT) {
9790
+ if (q.indexOf(el) !== -1) return;
9791
+ queueDevFormCheck(q, el);
9792
+ if (q.length < DEV_FORM_CHECK_LINEAR_LIMIT) return;
9793
+ for (let i = 0; i < q.length; i++) {
9794
+ q[i][DEV_FORM_CHECK_MARK] = DEV_FORM_CHECK_GENERATION;
9795
+ }
9796
+ return;
9797
+ }
9798
+ const host = el;
9799
+ if (host[DEV_FORM_CHECK_MARK] === DEV_FORM_CHECK_GENERATION) return;
9800
+ queueDevFormCheck(q, el);
9801
+ host[DEV_FORM_CHECK_MARK] = DEV_FORM_CHECK_GENERATION;
9759
9802
  }
9760
9803
  function queueFormAuthoringDiagnostic(el, kind, selected) {
9761
9804
  if (process.env.NODE_ENV === "production") return;
@@ -10170,6 +10213,7 @@ function drainDevFormDiagnostics() {
10170
10213
  const q = DEV_FORM_CHECKS;
10171
10214
  if (q === null || q.length === 0) return;
10172
10215
  DEV_FORM_CHECKS = [];
10216
+ DEV_FORM_CHECK_GENERATION++;
10173
10217
  for (let i = 0; i < q.length; i++) {
10174
10218
  const el = q[i];
10175
10219
  const authoring = getDevFormDiagnosticState(el);
@@ -17469,6 +17513,10 @@ function updateSurvivor(block, newItem, newIdx, itemBody, pure, lite, indexIndep
17469
17513
  }
17470
17514
  }
17471
17515
  }
17516
+ function consumeAdoptQueuePrefix(adopt, count) {
17517
+ if (count < adopt.length) adopt.copyWithin(0, count);
17518
+ adopt.length -= count;
17519
+ }
17472
17520
  function mountItemsLinear(parentBlock, state, items, getKey, itemBody, singleRoot, ssrMarkerless) {
17473
17521
  const newLen = items.length;
17474
17522
  if (newLen === 0) return;
@@ -17476,6 +17524,7 @@ function mountItemsLinear(parentBlock, state, items, getKey, itemBody, singleRoo
17476
17524
  const oldItems = state.items;
17477
17525
  const parentNode = state.end.parentNode;
17478
17526
  const adopt = state.adopt;
17527
+ let adoptIndex = 0;
17479
17528
  let prev = null;
17480
17529
  const mounted = [];
17481
17530
  try {
@@ -17484,9 +17533,14 @@ function mountItemsLinear(parentBlock, state, items, getKey, itemBody, singleRoo
17484
17533
  const key = getKey(item, i);
17485
17534
  let adoptNode = null;
17486
17535
  let anchor = state.end;
17487
- if (adopt !== null && adopt.length !== 0) {
17488
- if (adopt[0].key === key) adoptNode = adopt.shift().node;
17489
- else anchor = adopt[0].node;
17536
+ if (adopt !== null && adoptIndex < adopt.length) {
17537
+ const candidate = adopt[adoptIndex];
17538
+ if (candidate.key === key) {
17539
+ adoptNode = candidate.node;
17540
+ adoptIndex++;
17541
+ } else {
17542
+ anchor = candidate.node;
17543
+ }
17490
17544
  }
17491
17545
  const block = mountItem(
17492
17546
  parentBlock,
@@ -17522,6 +17576,7 @@ function mountItemsLinear(parentBlock, state, items, getKey, itemBody, singleRoo
17522
17576
  state.size = 0;
17523
17577
  throw error;
17524
17578
  }
17579
+ if (adoptIndex !== 0) consumeAdoptQueuePrefix(adopt, adoptIndex);
17525
17580
  }
17526
17581
  function reconcileKeyed(parentBlock, state, items, getKey, itemBody, pure, singleRoot, lite = false, indexIndependent = false, ssrMarkerless = false) {
17527
17582
  const oldItems = state.items;
@@ -1421,6 +1421,7 @@ function ssrAttrs(sources, tag, namespace = "html", skipFormControls = false) {
1421
1421
  }
1422
1422
  }
1423
1423
  const resolved = /* @__PURE__ */ new Map();
1424
+ let needsWinningOrderSort = false;
1424
1425
  for (const writer of props.values()) {
1425
1426
  const { rawName, value, firstOrder, lastOrder } = writer;
1426
1427
  if (rawName === "key" || rawName === "ref" || rawName === "children" || rawName === "dangerouslySetInnerHTML" || rawName === "suppressHydrationWarning" || rawName === "suppressContentEditableWarning" || rawName === "suppressNativeChangeWarning" || rawName === "__octaneNativeChangeDiagnostic")
@@ -1434,17 +1435,20 @@ function ssrAttrs(sources, tag, namespace = "html", skipFormControls = false) {
1434
1435
  if (!import_constants.VALID_ATTR_NAME.test(name)) continue;
1435
1436
  const identity = namespace === "html" ? name.toLowerCase() : name;
1436
1437
  const previous = resolved.get(identity);
1437
- if (previous === void 0 || previous[3] < lastOrder) {
1438
- resolved.set(identity, [
1439
- process.env.NODE_ENV !== "production" && (rawName === "tabIndex" || rawName === "htmlFor") ? rawName : name,
1440
- value,
1441
- firstOrder,
1442
- lastOrder
1443
- ]);
1438
+ if (previous !== void 0) {
1439
+ if (previous[3] >= lastOrder) continue;
1440
+ needsWinningOrderSort = true;
1444
1441
  }
1442
+ resolved.set(identity, [
1443
+ process.env.NODE_ENV !== "production" && (rawName === "tabIndex" || rawName === "htmlFor") ? rawName : name,
1444
+ value,
1445
+ firstOrder,
1446
+ lastOrder
1447
+ ]);
1445
1448
  }
1446
1449
  let out = "";
1447
- const ordered = [...resolved.values()].sort((a, b) => a[2] - b[2]);
1450
+ const ordered = [...resolved.values()];
1451
+ if (needsWinningOrderSort) ordered.sort((a, b) => a[2] - b[2]);
1448
1452
  if (process.env.NODE_ENV !== "production") {
1449
1453
  devValidateSsrAriaProps(
1450
1454
  ordered.map(([name]) => name),
@@ -3931,6 +3935,9 @@ function rewindStreamBoundaryReplay(stream, checkpoint) {
3931
3935
  for (const [key, boundary] of ordered) stream.boundaries.set(key, boundary);
3932
3936
  }
3933
3937
  }
3938
+ function recordStreamBoundaryOwners(stream, owners) {
3939
+ for (const owner of owners) stream.boundaryOwnerKeys.add(owner);
3940
+ }
3934
3941
  let STREAM_REALM_SALT = null;
3935
3942
  function streamRealmSalt() {
3936
3943
  if (STREAM_REALM_SALT !== null) return STREAM_REALM_SALT;
@@ -3944,6 +3951,7 @@ function createStreamToken() {
3944
3951
  }
3945
3952
  let STREAM = null;
3946
3953
  function pruneUnrepresentedStreamDescendants(stream, ownerKey, ownerHtml) {
3954
+ if (!stream.boundaryOwnerKeys.has(ownerKey)) return;
3947
3955
  let removed = true;
3948
3956
  while (removed) {
3949
3957
  removed = false;
@@ -4001,6 +4009,7 @@ function ssrTry(scope, siteKey, tryFn, pendFn, catchFn, namespace = FRAME?.names
4001
4009
  entry = stream.boundaries.get(key);
4002
4010
  if (entry !== void 0) {
4003
4011
  recordStreamBoundaryMutation(stream, key);
4012
+ if (ownerKeys.length !== 0) recordStreamBoundaryOwners(stream, ownerKeys);
4004
4013
  entry.namespace = namespace;
4005
4014
  }
4006
4015
  if (entry !== void 0 && entry.state === "pending") {
@@ -4200,6 +4209,7 @@ function ssrTry(scope, siteKey, tryFn, pendFn, catchFn, namespace = FRAME?.names
4200
4209
  };
4201
4210
  recordStreamBoundaryMutation(stream, key);
4202
4211
  stream.boundaries.set(key, entry);
4212
+ if (ownerKeys.length !== 0) recordStreamBoundaryOwners(stream, ownerKeys);
4203
4213
  enterBoundaryIds(pendingIdOffset);
4204
4214
  } else {
4205
4215
  ID_COUNTER = entry.pendingIdOffset;
@@ -4253,6 +4263,7 @@ function ssrTry(scope, siteKey, tryFn, pendFn, catchFn, namespace = FRAME?.names
4253
4263
  };
4254
4264
  recordStreamBoundaryMutation(stream, key);
4255
4265
  stream.boundaries.set(key, entry);
4266
+ if (ownerKeys.length !== 0) recordStreamBoundaryOwners(stream, ownerKeys);
4256
4267
  enterBoundaryIds(pendingIdOffset);
4257
4268
  } else if (entry.state === "pending") {
4258
4269
  entry.state = "errored";
@@ -4350,6 +4361,7 @@ async function runStream(component, props, options, sink) {
4350
4361
  const resolved = newResolvedMap();
4351
4362
  const stream = {
4352
4363
  boundaries: /* @__PURE__ */ new Map(),
4364
+ boundaryOwnerKeys: /* @__PURE__ */ new Set(),
4353
4365
  nextId: 0,
4354
4366
  token: createStreamToken(),
4355
4367
  activePassBoundaryKeys: null,
@@ -21,7 +21,7 @@ __export(version_exports, {
21
21
  version: () => version
22
22
  });
23
23
  module.exports = __toCommonJS(version_exports);
24
- const version = "0.1.46";
24
+ const version = "0.1.48";
25
25
  // Annotate the CommonJS export names for ESM import in node:
26
26
  0 && (module.exports = {
27
27
  version
@@ -17,7 +17,7 @@ import { parseModule } from '@tsrx/core';
17
17
  import {
18
18
  compile,
19
19
  compileForBundler,
20
- hasLowerableJsxReturnBranches,
20
+ createJsxReturnBranchClassifier,
21
21
  hasOnlyLowerableNullishExits,
22
22
  isVoidJsxCodeBlockFunction,
23
23
  } from './compile.js';
@@ -254,13 +254,14 @@ export function findVoidComponentExports(source, id) {
254
254
  }
255
255
 
256
256
  const voidBindings = new Set();
257
+ const hasLowerableJsxReturnBranches = createJsxReturnBranchClassifier(ast.body || []);
257
258
  // Mirrors the compile-time lowering decisions exactly (nullish-guard @{}
258
259
  // bodies AND React-style conditional JSX returns), so cross-module call-site
259
260
  // classification agrees with what each module actually compiled to.
260
261
  const isVoidFunction = (node) =>
261
262
  isVoidJsxCodeBlockFunction(node) ||
262
263
  hasOnlyLowerableNullishExits(node) ||
263
- hasLowerableJsxReturnBranches(node, ast.body || []);
264
+ hasLowerableJsxReturnBranches(node);
264
265
  for (const declaration of declarations) {
265
266
  if (declaration.type === 'FunctionDeclaration' && declaration.id?.name) {
266
267
  if (isVoidFunction(declaration)) voidBindings.add(declaration.id.name);
@@ -530,6 +531,10 @@ class OctaneBundlerCompiler {
530
531
  return;
531
532
  }
532
533
  const changed = nodePath.resolve(cleanModuleId(path));
534
+ // Both cache families retain only present or missing package manifests.
535
+ // Ordinary source edits still start a diagnostic generation above, but
536
+ // cannot invalidate either cache.
537
+ if (nodePath.basename(changed) !== 'package.json') return;
533
538
  for (const [directory, entry] of this.manifestRuleCache) {
534
539
  if (entry.dependencies.includes(changed) || entry.missingDependencies.includes(changed)) {
535
540
  this.manifestRuleCache.delete(directory);
@@ -520,8 +520,8 @@ function ownerReachableComponentsAst(ast, localSpecializations) {
520
520
  tag: record,
521
521
  });
522
522
  const queue = [...reachable];
523
- while (queue.length > 0) {
524
- for (const dependency of dependencies.get(queue.shift()) ?? []) {
523
+ for (let queueIndex = 0; queueIndex < queue.length; queueIndex++) {
524
+ for (const dependency of dependencies.get(queue[queueIndex]) ?? []) {
525
525
  if (reachable.has(dependency)) continue;
526
526
  reachable.add(dependency);
527
527
  queue.push(dependency);
@@ -708,8 +708,8 @@ function specializeLocalComponentsAst(region, index, state) {
708
708
  ...localCallReferences(region, localNames),
709
709
  ]);
710
710
  const queue = [...selected];
711
- while (queue.length > 0) {
712
- const name = queue.shift();
711
+ for (let queueIndex = 0; queueIndex < queue.length; queueIndex++) {
712
+ const name = queue[queueIndex];
713
713
  const component = state.localSpecializations.components.get(name);
714
714
  if (!component) continue;
715
715
  for (const reference of new Set([
@@ -422,31 +422,6 @@ function inheritGeneratedOrigin(root, origin) {
422
422
  return root;
423
423
  }
424
424
 
425
- function mapAstCow(value, replace) {
426
- if (!value || typeof value !== 'object') return value;
427
- if (Array.isArray(value)) {
428
- let output = null;
429
- for (let index = 0; index < value.length; index++) {
430
- const mapped = mapAstCow(value[index], replace);
431
- if (output === null && mapped !== value[index]) output = value.slice(0, index);
432
- if (output !== null && mapped !== null) output.push(mapped);
433
- }
434
- return output ?? value;
435
- }
436
- const replacement = replace(value);
437
- if (replacement !== undefined) return replacement;
438
- let output = null;
439
- for (const [key, child] of Object.entries(value)) {
440
- if (AST_SKIP_KEYS.has(key)) continue;
441
- const mapped = mapAstCow(child, replace);
442
- if (mapped !== child) {
443
- if (output === null) output = { ...value };
444
- output[key] = mapped;
445
- }
446
- }
447
- return output ?? value;
448
- }
449
-
450
425
  function jsonValueToAst(value, origin) {
451
426
  const valueOrigin =
452
427
  value && typeof value === 'object' && value[PLAN_ORIGIN] ? value[PLAN_ORIGIN] : origin;