opshot 0.3.3 → 0.4.0

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 (4) hide show
  1. package/README.md +33 -33
  2. package/dist/index.d.ts +435 -42
  3. package/dist/index.js +2993 -1241
  4. package/package.json +20 -10
package/dist/index.js CHANGED
@@ -1,69 +1,11 @@
1
- import { memo, useState, useReducer, useEffect, useRef, createElement } from 'react';
1
+ import * as React from 'react';
2
+ import { memo, useState, useReducer, useRef, useEffect, createElement, useLayoutEffect } from 'react';
2
3
 
3
4
  // node_modules/proxy-compare/dist/index.js
4
5
  var GET_ORIGINAL_SYMBOL = /* @__PURE__ */ Symbol();
5
- var HAS_KEY_PROPERTY = "h";
6
- var ALL_OWN_KEYS_PROPERTY = "w";
7
- var HAS_OWN_KEY_PROPERTY = "o";
8
- var KEYS_PROPERTY = "k";
9
6
  var getProto = Object.getPrototypeOf;
10
7
  var objectsToTrack = /* @__PURE__ */ new WeakMap();
11
8
  var isObjectToTrack = (obj) => obj && (objectsToTrack.has(obj) ? objectsToTrack.get(obj) : getProto(obj) === Object.prototype || getProto(obj) === Array.prototype);
12
- var isObject = (x) => typeof x === "object" && x !== null;
13
- var getOriginalObject = (obj) => (
14
- // unwrap proxy
15
- obj[GET_ORIGINAL_SYMBOL] || // otherwise
16
- obj
17
- );
18
- var isAllOwnKeysChanged = (prevObj, nextObj) => {
19
- const prevKeys = Reflect.ownKeys(prevObj);
20
- const nextKeys = Reflect.ownKeys(nextObj);
21
- return prevKeys.length !== nextKeys.length || prevKeys.some((k, i) => k !== nextKeys[i]);
22
- };
23
- var isChanged = (prevObj, nextObj, affected, cache, isEqual = Object.is) => {
24
- if (isEqual(prevObj, nextObj)) {
25
- return false;
26
- }
27
- if (!isObject(prevObj) || !isObject(nextObj))
28
- return true;
29
- const used = affected.get(getOriginalObject(prevObj));
30
- if (!used)
31
- return true;
32
- if (cache) {
33
- const hit = cache.get(prevObj);
34
- if (hit === nextObj) {
35
- return false;
36
- }
37
- cache.set(prevObj, nextObj);
38
- }
39
- let changed = null;
40
- for (const key of used[HAS_KEY_PROPERTY] || []) {
41
- changed = Reflect.has(prevObj, key) !== Reflect.has(nextObj, key);
42
- if (changed)
43
- return changed;
44
- }
45
- if (used[ALL_OWN_KEYS_PROPERTY] === true) {
46
- changed = isAllOwnKeysChanged(prevObj, nextObj);
47
- if (changed)
48
- return changed;
49
- } else {
50
- for (const key of used[HAS_OWN_KEY_PROPERTY] || []) {
51
- const hasPrev = !!Reflect.getOwnPropertyDescriptor(prevObj, key);
52
- const hasNext = !!Reflect.getOwnPropertyDescriptor(nextObj, key);
53
- changed = hasPrev !== hasNext;
54
- if (changed)
55
- return changed;
56
- }
57
- }
58
- for (const key of used[KEYS_PROPERTY] || []) {
59
- changed = isChanged(prevObj[key], nextObj[key], affected, cache, isEqual);
60
- if (changed)
61
- return changed;
62
- }
63
- if (changed === null)
64
- throw new Error("invalid used");
65
- return changed;
66
- };
67
9
  var getUntracked = (obj) => {
68
10
  if (isObjectToTrack(obj)) {
69
11
  return obj[GET_ORIGINAL_SYMBOL] || null;
@@ -75,8 +17,8 @@ var markToTrack = (obj, mark = true) => {
75
17
  };
76
18
 
77
19
  // node_modules/valtio/esm/vanilla.mjs
78
- var isObject2 = (x) => typeof x === "object" && x !== null;
79
- var canProxyDefault = (x) => isObject2(x) && !refSet.has(x) && (Array.isArray(x) || !(Symbol.iterator in x)) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer) && !(x instanceof Promise);
20
+ var isObject = (x) => typeof x === "object" && x !== null;
21
+ var canProxyDefault = (x) => isObject(x) && !refSet.has(x) && (Array.isArray(x) || !(Symbol.iterator in x)) && !(x instanceof WeakMap) && !(x instanceof WeakSet) && !(x instanceof Error) && !(x instanceof Number) && !(x instanceof Date) && !(x instanceof String) && !(x instanceof RegExp) && !(x instanceof ArrayBuffer) && !(x instanceof Promise);
80
22
  var createSnapshotDefault = (target, version) => {
81
23
  const cache = snapCache.get(target);
82
24
  if ((cache == null ? void 0 : cache[0]) === version) {
@@ -130,7 +72,7 @@ var createHandlerDefault = (isInitializing, addPropListener, removePropListener,
130
72
  return true;
131
73
  }
132
74
  removePropListener(prop);
133
- if (isObject2(value)) {
75
+ if (isObject(value)) {
134
76
  value = getUntracked(value) || value;
135
77
  }
136
78
  const nextValue = !proxyStateMap.has(value) && canProxy(value) ? proxy(value) : value;
@@ -151,7 +93,7 @@ var canProxy = canProxyDefault;
151
93
  var createSnapshot = createSnapshotDefault;
152
94
  var createHandler = createHandlerDefault;
153
95
  function proxy(baseObject = {}) {
154
- if (!isObject2(baseObject)) {
96
+ if (!isObject(baseObject)) {
155
97
  throw new Error("object required");
156
98
  }
157
99
  const found = proxyCache.get(baseObject);
@@ -266,31 +208,19 @@ function subscribe(proxyObject, callback, notifyInSync) {
266
208
  if ((import.meta.env ? import.meta.env.MODE : void 0) !== "production" && !proxyState) {
267
209
  console.warn("Please use proxy object");
268
210
  }
269
- let promise;
270
211
  const ops = [];
271
212
  const addListener = proxyState[2];
272
- let isListenerActive = false;
273
213
  const listener = (op) => {
274
214
  if (op) {
275
215
  ops.push(op);
276
216
  }
277
- if (notifyInSync) {
217
+ {
278
218
  callback(ops.splice(0));
279
219
  return;
280
220
  }
281
- if (!promise) {
282
- promise = Promise.resolve().then(() => {
283
- promise = void 0;
284
- if (isListenerActive) {
285
- callback(ops.splice(0));
286
- }
287
- });
288
- }
289
221
  };
290
222
  const removeListener = addListener(listener);
291
- isListenerActive = true;
292
223
  return () => {
293
- isListenerActive = false;
294
224
  removeListener();
295
225
  };
296
226
  }
@@ -302,10 +232,6 @@ function snapshot(proxyObject) {
302
232
  const [target, ensureVersion] = proxyState;
303
233
  return createSnapshot(target, ensureVersion());
304
234
  }
305
- function ref(obj) {
306
- refSet.add(obj);
307
- return obj;
308
- }
309
235
  function unstable_getInternalStates() {
310
236
  return {
311
237
  proxyStateMap,
@@ -337,19 +263,222 @@ function unstable_replaceInternalFunction(name, fn) {
337
263
  }
338
264
  }
339
265
 
340
- // src/unsafeTrack.ts
341
- var unsafeTrackedSet = /* @__PURE__ */ new WeakSet();
342
- function unsafeTrack(value) {
343
- unsafeTrackedSet.add(value);
344
- return value;
266
+ // src/declarations.ts
267
+ function createDeclarationTrie() {
268
+ return { ignored: false, unsafe: false, children: /* @__PURE__ */ new Map() };
269
+ }
270
+ function declarationChild(trie, key) {
271
+ return trie?.children.get(String(key));
272
+ }
273
+ function ensureDeclarationChild(trie, key) {
274
+ const name = String(key);
275
+ const existing = trie.children.get(name);
276
+ if (existing !== void 0) return existing;
277
+ const child = createDeclarationTrie();
278
+ trie.children.set(name, child);
279
+ return child;
280
+ }
281
+ function declarationAtPath(trie, path) {
282
+ let current = trie;
283
+ for (const segment of path) current = ensureDeclarationChild(current, segment);
284
+ return current;
285
+ }
286
+ function graftDeclarationChildren(source, target) {
287
+ for (const [key, sourceChild] of source.children) {
288
+ const targetChild = ensureDeclarationChild(target, key);
289
+ if (sourceChild.ignored) targetChild.ignored = true;
290
+ if (sourceChild.unsafe) targetChild.unsafe = true;
291
+ graftDeclarationChildren(sourceChild, targetChild);
292
+ }
293
+ }
294
+ function hasDeclarations(trie) {
295
+ if (trie.ignored || trie.unsafe) return true;
296
+ for (const child of trie.children.values()) {
297
+ if (hasDeclarations(child)) return true;
298
+ }
299
+ return false;
300
+ }
301
+
302
+ // src/identity.ts
303
+ var isObjectLike = (value) => value !== null && (typeof value === "object" || typeof value === "function");
304
+ var targetRegistry = /* @__PURE__ */ new WeakMap();
305
+ var readProxyTargets = /* @__PURE__ */ new WeakMap();
306
+ var identityRecords = /* @__PURE__ */ new WeakMap();
307
+ var nextInternId = 0;
308
+ var { proxyStateMap: proxyStateMap2 } = unstable_getInternalStates();
309
+ function registerSnapshotCopy(copy, target) {
310
+ targetRegistry.set(copy, target);
311
+ }
312
+ function getRegisteredTarget(copy) {
313
+ return targetRegistry.get(copy);
314
+ }
315
+ var registerReadProxyTarget = (readProxy, target) => {
316
+ readProxyTargets.set(readProxy, target);
317
+ };
318
+ var getRegisteredReadProxyTarget = (readProxy) => readProxyTargets.get(readProxy);
319
+ function peelIdentityLayer(current) {
320
+ const untracked = getUntracked(current);
321
+ if (untracked !== null && untracked !== current) return untracked;
322
+ const readProxyTarget = getRegisteredReadProxyTarget(current);
323
+ if (readProxyTarget !== void 0 && readProxyTarget !== current) return readProxyTarget;
324
+ const registeredTarget = targetRegistry.get(current);
325
+ if (registeredTarget !== void 0 && registeredTarget !== current) return registeredTarget;
326
+ return void 0;
327
+ }
328
+ function resolveIdentity(value) {
329
+ let current = value;
330
+ while (isObjectLike(current)) {
331
+ const peeled = peelIdentityLayer(current);
332
+ if (peeled !== void 0) {
333
+ current = peeled;
334
+ continue;
335
+ }
336
+ const entry = proxyStateMap2.get(current);
337
+ if (entry !== void 0) {
338
+ const target = entry[0];
339
+ if (target !== current) {
340
+ current = target;
341
+ continue;
342
+ }
343
+ }
344
+ break;
345
+ }
346
+ return current;
347
+ }
348
+ var recordFor = (key) => {
349
+ let record = identityRecords.get(key);
350
+ if (record === void 0) {
351
+ record = {};
352
+ identityRecords.set(key, record);
353
+ }
354
+ return record;
355
+ };
356
+ function identify(value) {
357
+ const target = resolveIdentity(value);
358
+ if (!isObjectLike(target)) return value;
359
+ const record = recordFor(target);
360
+ if (record.token !== void 0) return record.token;
361
+ const token = Object.freeze({});
362
+ record.token = token;
363
+ return token;
364
+ }
365
+ var internIdentity = (key) => {
366
+ const resolved = resolveIdentity(key);
367
+ const record = recordFor(resolved);
368
+ if (record.id !== void 0) return record.id;
369
+ const id = nextInternId;
370
+ nextInternId += 1;
371
+ record.id = id;
372
+ return id;
373
+ };
374
+ function isSameIdentity(first, second) {
375
+ const resolvedFirst = resolveIdentity(first);
376
+ const resolvedSecond = resolveIdentity(second);
377
+ return resolvedFirst === resolvedSecond;
378
+ }
379
+
380
+ // src/peelReadProxy.ts
381
+ var { proxyStateMap: proxyStateMap3 } = unstable_getInternalStates();
382
+ var isObjectLike2 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
383
+ function peelReadProxy(value) {
384
+ if (!isObjectLike2(value) || proxyStateMap3.has(value)) return value;
385
+ let current = value;
386
+ while (isObjectLike2(current)) {
387
+ const registeredTarget = getRegisteredReadProxyTarget(current);
388
+ if (registeredTarget === void 0) break;
389
+ current = registeredTarget;
390
+ }
391
+ return current;
392
+ }
393
+
394
+ // src/handle.ts
395
+ var occupancies = /* @__PURE__ */ new WeakMap();
396
+ var { proxyStateMap: proxyStateMap4 } = unstable_getInternalStates();
397
+ var rawTargetOf = (value) => proxyStateMap4.get(value)?.[0] ?? value;
398
+ function registerHandle(target, handle) {
399
+ let occupants = occupancies.get(target);
400
+ if (occupants === void 0) {
401
+ occupants = /* @__PURE__ */ new Set();
402
+ occupancies.set(target, occupants);
403
+ }
404
+ for (const reference of occupants) {
405
+ if (reference.deref() === handle) return;
406
+ }
407
+ occupants.add(new WeakRef(handle));
408
+ }
409
+ var rawOf = (node) => {
410
+ const peeled = peelReadProxy(node);
411
+ return rawTargetOf(typeof peeled === "object" && peeled !== null ? peeled : node);
412
+ };
413
+ function handlesOf(node) {
414
+ const target = rawOf(node);
415
+ const occupants = occupancies.get(target);
416
+ if (occupants === void 0) return [];
417
+ const handles = new Array();
418
+ for (const reference of occupants) {
419
+ const handle = reference.deref();
420
+ if (handle === void 0) {
421
+ occupants.delete(reference);
422
+ continue;
423
+ }
424
+ handles.push(handle);
425
+ }
426
+ return handles;
345
427
  }
346
- function isUnsafeTracked(value) {
347
- return typeof value === "object" && value !== null && unsafeTrackedSet.has(value);
428
+ function handleOf(node) {
429
+ const target = rawOf(node);
430
+ for (const handle of handlesOf(node)) {
431
+ if (rawTargetOf(handle.proxy.root) === target) return handle;
432
+ }
433
+ return void 0;
348
434
  }
435
+ function requireHandle(state, message) {
436
+ const handle = handleOf(state);
437
+ if (handle === void 0) throw new Error(message);
438
+ return handle;
439
+ }
440
+
441
+ // src/ops/predicates.ts
442
+ var MAX_ARRAY_LENGTH = 4294967295;
443
+ var isObjectLike3 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
444
+ var isCanonicalArrayIndex = (segment) => Number.isInteger(segment) && typeof segment === "number" && segment >= 0 && segment < MAX_ARRAY_LENGTH;
445
+ var isCanonicalArrayIndexString = (key) => {
446
+ const index = Number(key);
447
+ return Number.isInteger(index) && index >= 0 && index < MAX_ARRAY_LENGTH && String(index) === key;
448
+ };
449
+
450
+ // src/utils/dataEntries.ts
451
+ var walkDataEntries = (value, includeArrayLength = false) => {
452
+ const entries = new Array();
453
+ for (const key of Object.keys(value)) {
454
+ if (key === "__proto__") continue;
455
+ const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
456
+ if (!descriptor || !("value" in descriptor)) continue;
457
+ entries.push({ key, value: descriptor.value, writable: descriptor.writable === true });
458
+ }
459
+ if (includeArrayLength && Array.isArray(value)) {
460
+ const lengthDescriptor = Reflect.getOwnPropertyDescriptor(value, "length");
461
+ entries.push({
462
+ key: "length",
463
+ value: value.length,
464
+ writable: lengthDescriptor?.writable === true
465
+ });
466
+ }
467
+ return entries;
468
+ };
469
+ var segmentFor = (parent, key) => Array.isArray(parent) && isCanonicalArrayIndexString(key) ? Number(key) : key;
470
+ var dataEntryValuesOf = (value) => {
471
+ const entries = /* @__PURE__ */ new Map();
472
+ for (const entry of walkDataEntries(value)) {
473
+ entries.set(entry.key, entry.value);
474
+ }
475
+ return entries;
476
+ };
477
+ var carriedOwnKeysOf = (value) => Reflect.ownKeys(value).filter((key) => key !== "__proto__");
349
478
 
350
479
  // src/valtio/classify.ts
351
- var { refSet: refSet2 } = unstable_getInternalStates();
352
480
  var sourceCache = /* @__PURE__ */ new WeakMap();
481
+ var kindCache = /* @__PURE__ */ new WeakMap();
353
482
  var readSource = (constructor) => {
354
483
  const cached = sourceCache.get(constructor);
355
484
  if (cached !== void 0) return cached;
@@ -357,16 +486,31 @@ var readSource = (constructor) => {
357
486
  sourceCache.set(constructor, source);
358
487
  return source;
359
488
  };
489
+ var privateNameAccess = /\.\s*#[A-Za-z_$]/;
490
+ var privateNameDeclaration = new RegExp(
491
+ String.raw`[{;}](?:\s|\/\*[\s\S]*?\*\/|\/\/[^\n]*\n|static\b|async\b|get\b|set\b|\*)*` + String.raw`#[A-Za-z_$][\w$]*` + String.raw`(?:[ \t]*(?:\/\*[\s\S]*?\*\/[ \t]*)*[(=;}]|[ \t]*(?:\/\/[^\n]*|\/\*[\s\S]*?\*\/[ \t]*)?(?:\r?\n|$))`,
492
+ "m"
493
+ );
494
+ var hasPrivateName = (source) => privateNameAccess.test(source) || privateNameDeclaration.test(source);
360
495
  var classifyChain = (initialConstructor) => {
496
+ if (typeof initialConstructor !== "function") return "cleanClass";
497
+ const cached = kindCache.get(initialConstructor);
498
+ if (cached !== void 0) return cached;
361
499
  let sawNativeSource = false;
362
500
  let current = initialConstructor;
501
+ let kind = "cleanClass";
363
502
  while (typeof current === "function" && current !== Object && current !== Array && current !== Function.prototype) {
364
503
  const source = readSource(current);
365
- if (source.includes("#")) return "privateClass";
504
+ if (hasPrivateName(source)) {
505
+ kind = "privateClass";
506
+ break;
507
+ }
366
508
  if (source.includes("[native code]")) sawNativeSource = true;
367
509
  current = Reflect.getPrototypeOf(current);
368
510
  }
369
- return sawNativeSource ? "nativeClass" : "cleanClass";
511
+ if (kind !== "privateClass") kind = sawNativeSource ? "nativeClass" : "cleanClass";
512
+ kindCache.set(initialConstructor, kind);
513
+ return kind;
370
514
  };
371
515
  function classifyValue(value) {
372
516
  const prototype = Object.getPrototypeOf(value);
@@ -375,142 +519,71 @@ function classifyValue(value) {
375
519
  if (prototype === Object.prototype || prototype === null) return "plain";
376
520
  return classifyChain(value.constructor);
377
521
  }
378
- function hasOwnEnumerableFunction(value) {
379
- for (const key of Reflect.ownKeys(value)) {
380
- const descriptor = Object.getOwnPropertyDescriptor(value, key);
381
- if (!descriptor?.enumerable || !("value" in descriptor)) continue;
382
- if (typeof descriptor.value === "function") return true;
383
- }
384
- return false;
522
+ function unfrozenAdmissionDecision(value) {
523
+ if (typeof value !== "object" || value === null) return { lane: "leaf" };
524
+ const kind = classifyValue(value);
525
+ if (kind === "plain" || kind === "plainArray" || kind === "cleanClass") return { lane: "tracked" };
526
+ return { lane: "dangerous", kind };
527
+ }
528
+ function admissionDecision(value) {
529
+ if (typeof value !== "object" || value === null) return { lane: "leaf" };
530
+ if (Object.isFrozen(value)) return { lane: "untracked" };
531
+ return unfrozenAdmissionDecision(value);
385
532
  }
386
533
  function admissionLane(value) {
387
- if (typeof value !== "object" || value === null) return "leaf";
388
- if (refSet2.has(value)) return "leaf";
389
- if (isUnsafeTracked(value)) return "track";
390
- const kind = classifyValue(value);
391
- if ((kind === "plain" || kind === "plainArray" || kind === "cleanClass") && Object.isFrozen(value)) return "leaf";
392
- if (kind === "plain" || kind === "plainArray") return "track";
393
- if (kind === "cleanClass" && !hasOwnEnumerableFunction(value)) return "track";
394
- return "reject";
534
+ return admissionDecision(value).lane;
395
535
  }
396
- function isTrackable(value) {
397
- return admissionLane(value) === "track";
536
+ function unfrozenAdmissionLane(value) {
537
+ return unfrozenAdmissionDecision(value).lane;
398
538
  }
399
539
 
400
- // src/ops/path.ts
401
- var createOperationPath = (segments) => Object.freeze([...segments]);
402
- var appendOperationPath = (path, segment) => Object.freeze([...path, segment]);
403
- var escapeSegment = (segment) => segment.replaceAll("~", "~0").replaceAll("/", "~1");
404
- var formatSegment = (segment) => typeof segment === "string" ? escapeSegment(segment) : String(segment);
405
- var formatOperationPath = (path) => path.length === 0 ? "" : `/${path.map(formatSegment).join("/")}`;
406
- var assertSafePath = (path) => {
407
- for (let index = 0; index < path.length; index++) {
408
- const segment = path[index];
409
- if (segment === "__proto__" || segment === "prototype" && path[index - 1] === "constructor") {
410
- throw new Error(`opshot: reserved operation path ${formatOperationPath(path)}`);
411
- }
412
- }
413
- };
414
-
415
540
  // src/ops/cloneValue.ts
416
- var { refSet: refSet3 } = unstable_getInternalStates();
417
- var isPlainArray = (value) => Array.isArray(value) && !refSet3.has(value);
418
- var isPlainObject = (value) => isTrackable(value) && !Array.isArray(value);
419
- var isCloneable = (value) => isTrackable(value);
420
- var CyclicValueError = class extends Error {
421
- constructor(path) {
422
- super(`opshot: cyclic value at ${formatOperationPath(path)}; use ignore() for back-linked structures, or ids`);
423
- this.name = "CyclicValueError";
424
- this.path = createOperationPath(path);
541
+ var { proxyStateMap: proxyStateMap5 } = unstable_getInternalStates();
542
+ var MissingOwnDescriptorError = class extends Error {
543
+ constructor() {
544
+ super("opshot: carried own key has no property descriptor");
545
+ this.name = "MissingOwnDescriptorError";
425
546
  }
426
547
  };
427
- var cyclicError = (path) => new CyclicValueError(path);
428
- var getCyclicPath = (error) => error instanceof CyclicValueError ? error.path : void 0;
429
- var CLONE_IN_PROGRESS = /* @__PURE__ */ Symbol("opshot.cloneValue.inProgress");
548
+ var isInstrumented = (value) => proxyStateMap5.has(value) || getRegisteredTarget(value) !== void 0;
549
+ var isPlainArray = (value) => Array.isArray(value);
550
+ var isPlainObject = (value) => typeof value === "object" && value !== null && !Array.isArray(value) && (admissionLane(value) === "tracked" || isInstrumented(value));
551
+ var isStructurallyCloneableFrozen = (value) => {
552
+ if (!Object.isFrozen(value)) return false;
553
+ if (Array.isArray(value)) return true;
554
+ const prototype = Object.getPrototypeOf(value);
555
+ return prototype === Object.prototype || prototype === null;
556
+ };
557
+ var isCloneable = (value) => typeof value === "object" && value !== null && (admissionLane(value) === "tracked" || isInstrumented(value) || isStructurallyCloneableFrozen(value));
430
558
  var cloneValue = (value, memo2, path) => {
431
559
  if (!isCloneable(value)) return value;
432
560
  const cached = memo2.get(value);
433
- if (cached === CLONE_IN_PROGRESS) throw cyclicError(path);
434
561
  if (cached !== void 0) return cached;
435
- memo2.set(value, CLONE_IN_PROGRESS);
436
562
  const array = isPlainArray(value);
437
563
  const clone = array ? [] : {};
438
564
  Reflect.setPrototypeOf(clone, Reflect.getPrototypeOf(value));
439
- for (const key of Reflect.ownKeys(value)) {
565
+ memo2.set(value, clone);
566
+ for (const key of carriedOwnKeysOf(value)) {
440
567
  const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
441
- if (!descriptor) continue;
568
+ if (descriptor === void 0) throw new MissingOwnDescriptorError();
442
569
  if ("value" in descriptor) {
443
570
  Object.defineProperty(clone, key, {
444
571
  ...descriptor,
445
- value: cloneValue(descriptor.value, memo2, path)
572
+ value: cloneValue(descriptor.value, memo2)
446
573
  });
447
574
  } else {
448
575
  Object.defineProperty(clone, key, descriptor);
449
576
  }
450
577
  }
451
- memo2.set(value, clone);
452
- if (isUnsafeTracked(value)) unsafeTrack(clone);
578
+ if (Object.isFrozen(value)) Object.freeze(clone);
453
579
  return clone;
454
580
  };
455
581
 
456
- // src/react/wrapperRegistry.ts
457
- var wrapperTargets = /* @__PURE__ */ new WeakMap();
458
- var registerWrapperTarget = (wrapper, target) => {
459
- wrapperTargets.set(wrapper, target);
460
- };
461
- var getRegisteredWrapperTarget = (wrapper) => wrapperTargets.get(wrapper);
462
-
463
- // src/identity.ts
464
- var isObjectLike = (value) => value !== null && (typeof value === "object" || typeof value === "function");
465
- var targetRegistry = /* @__PURE__ */ new WeakMap();
466
- var identityTokenRegistry = /* @__PURE__ */ new WeakMap();
467
- var { proxyStateMap: proxyStateMap2 } = unstable_getInternalStates();
468
- function registerSnapshotCopy(copy, target) {
469
- targetRegistry.set(copy, target);
470
- }
471
- function getRegisteredTarget(copy) {
472
- return targetRegistry.get(copy);
473
- }
474
- function peelIdentityLayer(current) {
475
- const untracked = getUntracked(current);
476
- if (untracked !== null && untracked !== current) return untracked;
477
- const wrapperTarget = getRegisteredWrapperTarget(current);
478
- if (wrapperTarget !== void 0 && wrapperTarget !== current) return wrapperTarget;
479
- const registeredTarget = targetRegistry.get(current);
480
- if (registeredTarget !== void 0 && registeredTarget !== current) return registeredTarget;
481
- return void 0;
482
- }
483
- function resolveIdentity(value) {
484
- let current = value;
485
- while (isObjectLike(current)) {
486
- const peeled = peelIdentityLayer(current);
487
- if (peeled !== void 0) {
488
- current = peeled;
489
- continue;
490
- }
491
- const proxyState = proxyStateMap2.get(current);
492
- if (proxyState !== void 0 && proxyState[0] !== current) {
493
- current = proxyState[0];
494
- continue;
495
- }
496
- break;
497
- }
498
- return current;
499
- }
500
- function identify(value) {
501
- const target = resolveIdentity(value);
502
- if (!isObjectLike(target)) return value;
503
- const existing = identityTokenRegistry.get(target);
504
- if (existing !== void 0) return existing;
505
- const token = Object.freeze({});
506
- identityTokenRegistry.set(target, token);
507
- return token;
508
- }
509
- function isSameIdentity(first, second) {
510
- const resolvedFirst = resolveIdentity(first);
511
- const resolvedSecond = resolveIdentity(second);
512
- return resolvedFirst === resolvedSecond || resolvedFirst !== resolvedFirst && resolvedSecond !== resolvedSecond;
513
- }
582
+ // src/ops/path.ts
583
+ var createOperationPath = (segments) => Array.isArray(segments) && Object.isFrozen(segments) ? segments : Object.freeze([...segments]);
584
+ var appendOperationPath = (path, segment) => Object.freeze([...path, segment]);
585
+ var formatSegment = (segment) => String(segment);
586
+ var formatOperationPath = (path) => path.length === 0 ? "/" : `/${path.map(formatSegment).join("/")}`;
514
587
 
515
588
  // src/ops/operation.ts
516
589
  var operationBrand = /* @__PURE__ */ Symbol.for("opshot.operation");
@@ -521,354 +594,1416 @@ var OperationHalf = class {
521
594
  }
522
595
  };
523
596
  Object.defineProperty(OperationHalf.prototype, operationBrand, { value: true });
524
- var ValueHalf = class extends OperationHalf {
525
- get value() {
526
- return cloneValue(valueOriginals.get(this), /* @__PURE__ */ new WeakMap(), this.path);
527
- }
528
- constructor(path, value) {
597
+ var AssignHalf = class extends OperationHalf {
598
+ constructor(path, value, original = value, ids) {
529
599
  super(path);
530
- valueOriginals.set(this, value);
531
- if (!isCloneable(value)) Object.defineProperty(this, "value", { value, enumerable: true });
600
+ this.verb = "assign";
601
+ valueOriginals.set(this, original);
602
+ this.value = cloneValue(value, /* @__PURE__ */ new WeakMap(), this.path);
603
+ if (ids !== void 0) this.ids = ids;
532
604
  }
533
605
  };
534
- var AddHalf = class extends ValueHalf {
606
+ var DeleteHalf = class extends OperationHalf {
535
607
  constructor() {
536
608
  super(...arguments);
537
- this.op = "add";
609
+ this.verb = "delete";
538
610
  }
539
611
  };
540
- var ReplaceHalf = class extends ValueHalf {
541
- constructor() {
542
- super(...arguments);
543
- this.op = "replace";
612
+ var LinkHalf = class extends OperationHalf {
613
+ constructor(path, ref) {
614
+ super(path);
615
+ this.verb = "link";
616
+ this.ref = ref;
544
617
  }
545
618
  };
546
- var RemoveHalf = class extends OperationHalf {
547
- constructor() {
548
- super(...arguments);
549
- this.op = "remove";
550
- }
619
+ var stampOf = (operation) => {
620
+ const value = Object.getOwnPropertyDescriptor(operation, "stamp")?.value;
621
+ return typeof value === "object" && value !== null ? value : void 0;
622
+ };
623
+ var versionOf = (operation) => {
624
+ const value = Reflect.get(operation, "version");
625
+ return typeof value === "number" && Number.isInteger(value) ? value : void 0;
551
626
  };
552
- var isOperation = (value) => typeof value === "object" && value !== null && operationBrand in value;
627
+ var stampOperation = (handle, operation) => {
628
+ handle.version += 1;
629
+ Object.defineProperty(operation, "stamp", { value: handle.stamp, enumerable: false });
630
+ Object.defineProperty(operation, "version", { value: handle.version, enumerable: true });
631
+ };
632
+ var isMutation = (value) => typeof value === "object" && value !== null && operationBrand in value;
553
633
  var getValueOriginal = (half) => valueOriginals.get(half);
554
- var createAddOperation = (path, value) => new AddHalf(path, value);
555
- var createReplaceOperation = (path, value) => new ReplaceHalf(path, value);
556
- var createRemoveOperation = (path) => new RemoveHalf(path);
634
+ var createAssignMutation = (path, value, original = value, ids) => new AssignHalf(path, value, original, ids);
635
+ var createDeleteMutation = (path) => new DeleteHalf(path);
636
+ var createLinkMutation = (path, ref) => new LinkHalf(path, ref);
557
637
 
558
- // src/ops/weight.ts
559
- var NODE_WEIGHT = 32;
560
- var KEY_WEIGHT = 16;
561
- var CHARACTER_WEIGHT = 2;
562
- var LEAF_WEIGHT = 16;
563
- var OPERATION_WEIGHT = 512;
564
- var addWeight = (state, amount) => {
565
- state.weight += amount;
566
- return state.weight <= state.budget;
567
- };
568
- var weigh = (value, state) => {
569
- if (state.weight > state.budget) return;
570
- if (typeof value === "string") {
571
- addWeight(state, LEAF_WEIGHT + CHARACTER_WEIGHT * value.length);
572
- return;
573
- }
574
- if (value === null || typeof value !== "object" && typeof value !== "function") {
575
- addWeight(state, LEAF_WEIGHT);
576
- return;
577
- }
578
- if (state.seen.has(value)) return;
579
- if (isCloneable(value)) {
580
- state.seen.add(value);
581
- if (!addWeight(state, NODE_WEIGHT)) return;
582
- for (const key of Object.keys(value)) {
583
- const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
584
- if (!descriptor || !("value" in descriptor)) continue;
585
- if (!addWeight(state, KEY_WEIGHT)) return;
586
- weigh(descriptor.value, state);
587
- if (state.weight > state.budget) return;
588
- }
589
- }
638
+ // src/intern.ts
639
+ var { proxyStateMap: proxyStateMap6, proxyCache: proxyCache2 } = unstable_getInternalStates();
640
+ var rawTargetOf2 = (value) => proxyStateMap6.get(value)?.[0] ?? value;
641
+ var occupancyNodeOf = (node) => {
642
+ const peeled = peelReadProxy(node);
643
+ const object = typeof peeled === "object" && peeled !== null ? peeled : node;
644
+ return rawTargetOf2(getRegisteredTarget(object) ?? object);
590
645
  };
591
- var weighValue = (value, budget) => {
592
- const state = { weight: 0, budget, seen: /* @__PURE__ */ new WeakSet() };
593
- weigh(value, state);
594
- return state.weight;
646
+ var liveOfInterned = (raw) => proxyCache2.get(raw) ?? raw;
647
+ var departingNodes = /* @__PURE__ */ new WeakMap();
648
+ var committedIdOf = (handle, raw) => handle.nodes.get(raw)?.id;
649
+ var writeId = (handle, raw, id) => {
650
+ const record = handle.nodes.get(raw);
651
+ if (record === void 0) handle.nodes.set(raw, { edges: [], id });
652
+ else {
653
+ if (record.id !== void 0 && record.id !== id) handle.byId.delete(record.id);
654
+ record.id = id;
655
+ }
656
+ handle.byId.set(id, raw);
595
657
  };
596
-
597
- // src/ops/diff.ts
598
- var UNCAPPED_WEIGHT = Number.MAX_SAFE_INTEGER;
599
- var IncompatibleSnapshotRootsError = class extends Error {
600
- constructor() {
601
- super("opshot: diffSnapshots requires compatible supported object roots");
602
- this.name = "IncompatibleSnapshotRootsError";
603
- }
658
+ function internNode(handle, node) {
659
+ const raw = occupancyNodeOf(node);
660
+ const existing = committedIdOf(handle, raw);
661
+ if (existing !== void 0) return existing;
662
+ const id = handle.nextInternId;
663
+ handle.nextInternId += 1;
664
+ writeId(handle, raw, id);
665
+ return id;
666
+ }
667
+ var stagedBindIdOf = (capture, raw) => capture.bindIdByNode.get(raw);
668
+ var stagedMintIdOf = (capture, raw) => capture.mintIdByNode.get(raw);
669
+ var stagedNodeOf = (capture, id) => capture.bindNodeById.get(id) ?? capture.mintNodeById.get(id);
670
+ var nextStagedIdOf = (handle, capture) => Math.max(handle.nextInternId, capture.nextStagedId);
671
+ var stageMint = (capture, raw, id) => {
672
+ capture.mints.push({ node: raw, id });
673
+ capture.mintIdByNode.set(raw, id);
674
+ capture.mintNodeById.set(id, raw);
675
+ if (id + 1 > capture.nextStagedId) capture.nextStagedId = id + 1;
604
676
  };
605
- var addPair = (path, after) => ({
606
- do: createAddOperation(path, after),
607
- undo: createRemoveOperation(path)
608
- });
609
- var removePair = (path, before) => ({
610
- do: createRemoveOperation(path),
611
- undo: createAddOperation(path, before)
612
- });
613
- var replacePair = (path, before, after) => ({
614
- do: createReplaceOperation(path, after),
615
- undo: createReplaceOperation(path, before)
616
- });
617
- var weighCarried = (value) => weighValue(value, UNCAPPED_WEIGHT);
618
- var pushAdd = (ops, path, after) => {
619
- ops.push(addPair(path, after));
620
- return OPERATION_WEIGHT + weighCarried(after);
621
- };
622
- var pushRemove = (ops, path, before) => {
623
- ops.push(removePair(path, before));
624
- return OPERATION_WEIGHT + weighCarried(before);
625
- };
626
- var pushReplace = (ops, path, before, after) => {
627
- ops.push(replacePair(path, before, after));
628
- return OPERATION_WEIGHT + weighCarried(before) + weighCarried(after);
629
- };
630
- var tryCollapse = (before, after, path, ops, opsStart, atomicWeight) => {
631
- if (atomicWeight === 0) return 0;
632
- const beforeWeight = weighValue(before, atomicWeight);
633
- const afterWeight = weighValue(after, atomicWeight - beforeWeight);
634
- const collapsedWeight = OPERATION_WEIGHT + beforeWeight + afterWeight;
635
- if (collapsedWeight < atomicWeight) {
636
- assertSafeSubtree(before, path);
637
- assertSafeSubtree(after, path);
638
- ops.splice(opsStart, ops.length - opsStart, replacePair(path, before, after));
639
- return collapsedWeight;
640
- }
641
- return atomicWeight;
677
+ var stageBind = (capture, raw, id) => {
678
+ capture.binds.push({ node: raw, id });
679
+ capture.bindIdByNode.set(raw, id);
680
+ capture.bindNodeById.set(id, raw);
681
+ if (id + 1 > capture.nextStagedId) capture.nextStagedId = id + 1;
642
682
  };
643
- var hasAncestorPair = (ancestors, before, after) => ancestors.get(before)?.has(after) ?? false;
644
- var enterAncestorPair = (ancestors, before, after) => {
645
- const afterSet = ancestors.get(before) ?? /* @__PURE__ */ new Set();
646
- afterSet.add(after);
647
- ancestors.set(before, afterSet);
683
+ var namedRawOf = (handle, id, capture) => {
684
+ const staged = capture === void 0 ? void 0 : stagedNodeOf(capture, id);
685
+ return staged ?? handle.byId.get(id);
648
686
  };
649
- var exitAncestorPair = (ancestors, before, after) => {
650
- const afterSet = ancestors.get(before);
651
- if (!afterSet) return;
652
- afterSet.delete(after);
653
- if (afterSet.size === 0) ancestors.delete(before);
687
+ function internedIdOf(handle, node, capture) {
688
+ const raw = occupancyNodeOf(node);
689
+ const bound = capture === void 0 ? void 0 : stagedBindIdOf(capture, raw);
690
+ if (bound !== void 0) return bound;
691
+ const committed = committedIdOf(handle, raw);
692
+ if (committed !== void 0) return committed;
693
+ if (capture === void 0) return void 0;
694
+ return stagedMintIdOf(capture, raw);
695
+ }
696
+ function stageVend(handle, capture, node) {
697
+ const raw = occupancyNodeOf(node);
698
+ const bound = stagedBindIdOf(capture, raw);
699
+ if (bound !== void 0) return bound;
700
+ const committed = committedIdOf(handle, raw);
701
+ if (committed !== void 0) return committed;
702
+ const staged = stagedMintIdOf(capture, raw);
703
+ if (staged !== void 0) return staged;
704
+ const id = nextStagedIdOf(handle, capture);
705
+ stageMint(capture, raw, id);
706
+ return id;
707
+ }
708
+ var commitName = (handle, raw, id) => {
709
+ writeId(handle, raw, id);
710
+ if (id >= handle.nextInternId) handle.nextInternId = id + 1;
654
711
  };
655
- var isObjectLike2 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
656
- var sharesStorageIdentity = (before, after) => isObjectLike2(before) && isObjectLike2(after) && isSameIdentity(before, after);
657
- var assertSafeSubtree = (value, path, activeAncestors = /* @__PURE__ */ new WeakSet()) => {
658
- if (!isPlainArray(value) && !isPlainObject(value)) return;
659
- if (activeAncestors.has(value)) return;
660
- activeAncestors.add(value);
661
- try {
662
- for (const key of Object.keys(value)) {
663
- const nextPath = appendOperationPath(path, key);
664
- assertSafePath(nextPath);
665
- const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
666
- if (descriptor && "value" in descriptor) assertSafeSubtree(descriptor.value, nextPath, activeAncestors);
712
+ function commitVends(handle, capture) {
713
+ for (const { node, id } of capture.mints) commitName(handle, node, id);
714
+ capture.mints.length = 0;
715
+ for (const { node, id } of capture.binds) commitName(handle, node, id);
716
+ capture.binds.length = 0;
717
+ capture.bindIdByNode.clear();
718
+ capture.bindNodeById.clear();
719
+ capture.mintIdByNode.clear();
720
+ capture.mintNodeById.clear();
721
+ capture.nextStagedId = 0;
722
+ }
723
+ function nodeOfInternedId(handle, id, capture) {
724
+ const raw = namedRawOf(handle, id, capture);
725
+ if (raw === void 0) return void 0;
726
+ return liveOfInterned(raw);
727
+ }
728
+ var walkTracked = (node, visits, chains, resolve, visit) => {
729
+ const walk = (current, currentChains, parent, key) => {
730
+ const raw = occupancyNodeOf(current);
731
+ if (visits.has(raw)) return;
732
+ visits.add(raw);
733
+ if (admissionLane(current) === "untracked") return;
734
+ if (!visit(current, raw, parent, key)) return;
735
+ const source = getRegisteredTarget(current) ?? current;
736
+ for (const entry of walkDataEntries(source)) {
737
+ if (typeof entry.value !== "object" || entry.value === null) continue;
738
+ if (currentChains === void 0 || resolve === void 0) {
739
+ walk(entry.value, currentChains, current, entry.key);
740
+ continue;
741
+ }
742
+ const childChains = resolve(source, currentChains, segmentFor(source, entry.key), entry);
743
+ if (childChains === void 0) continue;
744
+ walk(entry.value, childChains, current, entry.key);
667
745
  }
668
- } finally {
669
- activeAncestors.delete(value);
670
- }
746
+ };
747
+ walk(node, chains);
671
748
  };
672
- var isCanonicalArrayIndex = (key) => {
673
- const index = Number(key);
674
- return Number.isInteger(index) && index >= 0 && index < 4294967295 && String(index) === key;
749
+ function internSubtree(handle, node, chains, resolve, capture) {
750
+ walkTracked(node, /* @__PURE__ */ new Set(), chains, resolve, (current) => {
751
+ if (capture === void 0) internNode(handle, current);
752
+ else stageVend(handle, capture, current);
753
+ return true;
754
+ });
755
+ }
756
+ function queueDeparture(handle, node) {
757
+ const raw = occupancyNodeOf(node);
758
+ let queued = departingNodes.get(handle);
759
+ if (queued === void 0) {
760
+ queued = /* @__PURE__ */ new Set();
761
+ departingNodes.set(handle, queued);
762
+ }
763
+ queued.add(raw);
764
+ }
765
+ var parentOfEdge = (parent) => occupancyNodeOf(parent);
766
+ var isOccupiedMember = (handle, node) => {
767
+ const root = rawTargetOf2(handle.proxy.root);
768
+ const raw = occupancyNodeOf(node);
769
+ if (raw === root) return true;
770
+ const seen = /* @__PURE__ */ new Set();
771
+ const walk = (current) => {
772
+ if (current === root) return true;
773
+ if (seen.has(current)) return false;
774
+ seen.add(current);
775
+ const edges = handle.nodes.get(current)?.edges;
776
+ if (edges === void 0) return false;
777
+ for (const edge of edges) {
778
+ if (walk(parentOfEdge(edge.parent))) return true;
779
+ }
780
+ return false;
781
+ };
782
+ return walk(raw);
675
783
  };
676
- var diffObjectProperties = (before, after, path, ops, ancestors, ignoreArrayIndexes) => {
677
- let weight = 0;
678
- for (const key of /* @__PURE__ */ new Set([...Object.keys(before), ...Object.keys(after)])) {
679
- if (ignoreArrayIndexes && isCanonicalArrayIndex(key)) continue;
680
- const nextPath = appendOperationPath(path, key);
681
- assertSafePath(nextPath);
682
- const beforeDescriptor = Reflect.getOwnPropertyDescriptor(before, key);
683
- const afterDescriptor = Reflect.getOwnPropertyDescriptor(after, key);
684
- if (beforeDescriptor?.get || afterDescriptor?.get) continue;
685
- if (!beforeDescriptor) {
686
- assertSafeSubtree(Reflect.get(after, key), nextPath);
687
- weight += pushAdd(ops, nextPath, Reflect.get(after, key));
688
- } else if (!afterDescriptor) {
689
- assertSafeSubtree(Reflect.get(before, key), nextPath);
690
- weight += pushRemove(ops, nextPath, Reflect.get(before, key));
691
- } else {
692
- weight += diffValue(Reflect.get(before, key), Reflect.get(after, key), nextPath, ops, ancestors);
784
+ var walkUnoccupiedCluster = (handle, node, visit) => {
785
+ walkTracked(node, /* @__PURE__ */ new Set(), void 0, void 0, (_current, raw) => {
786
+ if (isOccupiedMember(handle, raw)) return false;
787
+ visit(raw, committedIdOf(handle, raw));
788
+ return true;
789
+ });
790
+ };
791
+ var isNamedSlot = (handle, raw, evicted) => handle.nodes.has(raw) || evicted?.has(raw) === true;
792
+ var walkSlots = (carried, node, isTracked, visit) => {
793
+ const visits = /* @__PURE__ */ new Set();
794
+ const walk = (carriedCurrent, current, parent, key) => {
795
+ const raw = occupancyNodeOf(current);
796
+ const looping = visits.has(raw);
797
+ if (!looping) visits.add(raw);
798
+ if (admissionLane(current) === "untracked") return;
799
+ if (!isTracked(raw)) return;
800
+ if (!visit(raw, parent, key) || looping) return;
801
+ for (const entry of walkDataEntries(carriedCurrent)) {
802
+ if (typeof entry.value !== "object" || entry.value === null) continue;
803
+ const child = Reflect.get(current, entry.key);
804
+ if (typeof child !== "object" || child === null) continue;
805
+ walk(entry.value, child, current, entry.key);
693
806
  }
694
- }
695
- return weight;
807
+ };
808
+ walk(carried, node);
696
809
  };
697
- var diffArray = (before, after, path, ops, ancestors) => {
698
- const overlap = Math.min(before.length, after.length);
699
- let weight = 0;
700
- for (let index = 0; index < overlap; index++) {
701
- const beforePresent = Object.hasOwn(before, index);
702
- const afterPresent = Object.hasOwn(after, index);
703
- const nextPath = appendOperationPath(path, index);
704
- if (!beforePresent && !afterPresent) continue;
705
- if (!beforePresent) weight += pushAdd(ops, nextPath, after[index]);
706
- else if (!afterPresent) weight += pushRemove(ops, nextPath, before[index]);
707
- else weight += diffValue(before[index], after[index], nextPath, ops, ancestors);
810
+ function evictDepartedClusters(handle) {
811
+ const evicted = /* @__PURE__ */ new Map();
812
+ const queued = departingNodes.get(handle);
813
+ if (queued === void 0) return evicted;
814
+ const ungrounded = new Array();
815
+ for (const node of queued) {
816
+ if (!isOccupiedMember(handle, node)) ungrounded.push(node);
817
+ }
818
+ queued.clear();
819
+ const members = new Array();
820
+ for (const node of ungrounded) {
821
+ walkUnoccupiedCluster(handle, node, (raw, id) => {
822
+ members.push(raw);
823
+ if (id !== void 0) evicted.set(raw, id);
824
+ });
708
825
  }
709
- if (after.length > before.length) {
710
- weight += pushReplace(ops, appendOperationPath(path, "length"), before.length, after.length);
711
- for (let index = before.length; index < after.length; index++) {
712
- if (Object.hasOwn(after, index)) weight += pushAdd(ops, appendOperationPath(path, index), after[index]);
826
+ for (const raw of members) handle.nodes.delete(raw);
827
+ for (const id of evicted.values()) handle.byId.delete(id);
828
+ return evicted;
829
+ }
830
+ function bindVendedIds(handle, node, carried, ids, capture, parent, key) {
831
+ let index = 0;
832
+ walkSlots(
833
+ carried,
834
+ node,
835
+ (raw) => isNamedSlot(handle, raw),
836
+ (raw, walkParent, walkKey) => {
837
+ const id = ids[index];
838
+ if (id === void 0) return true;
839
+ index += 1;
840
+ const held = namedRawOf(handle, id, capture);
841
+ const slotParent = walkParent ?? parent;
842
+ const slotKey = walkKey ?? key;
843
+ if (held !== void 0) {
844
+ if (occupancyNodeOf(held) !== raw && slotParent !== void 0 && slotKey !== void 0) {
845
+ Reflect.set(slotParent, slotKey, liveOfInterned(held));
846
+ }
847
+ return false;
848
+ }
849
+ if (capture === void 0) commitName(handle, raw, id);
850
+ else stageBind(capture, raw, id);
851
+ return true;
713
852
  }
714
- } else if (after.length < before.length) {
715
- for (let index = after.length; index < before.length; index++) {
716
- if (Object.hasOwn(before, index)) weight += pushRemove(ops, appendOperationPath(path, index), before[index]);
853
+ );
854
+ }
855
+ function rewindAdmission(handle, node) {
856
+ const ids = new Array();
857
+ walkUnoccupiedCluster(handle, node, (raw, id) => {
858
+ if (id === void 0) return;
859
+ ids.push(id);
860
+ const record = handle.nodes.get(raw);
861
+ if (record !== void 0) record.id = void 0;
862
+ handle.byId.delete(id);
863
+ });
864
+ return ids;
865
+ }
866
+ function annotateDepartureUndos(handle, ops, evicted) {
867
+ if (evicted.size === 0) return;
868
+ const claimedMembers = /* @__PURE__ */ new Set();
869
+ for (let index = ops.length - 1; index >= 0; index--) {
870
+ const operation = ops[index];
871
+ if (operation === void 0) continue;
872
+ const undo = operation.undo;
873
+ if (undo.verb !== "assign") continue;
874
+ const original = getValueOriginal(undo) ?? undo.value;
875
+ if (typeof original !== "object" || original === null) continue;
876
+ const restoredId = evicted.get(occupancyNodeOf(original));
877
+ if (restoredId === void 0) continue;
878
+ const ids = new Array();
879
+ const claimsBefore = claimedMembers.size;
880
+ walkSlots(
881
+ original,
882
+ original,
883
+ (raw) => isNamedSlot(handle, raw, evicted),
884
+ (raw) => {
885
+ const retiredId = evicted.get(raw);
886
+ const id = retiredId ?? committedIdOf(handle, raw);
887
+ if (id !== void 0) ids.push(id);
888
+ if (retiredId === void 0 || claimedMembers.has(raw)) return false;
889
+ claimedMembers.add(raw);
890
+ return true;
891
+ }
892
+ );
893
+ operation.undo = claimedMembers.size > claimsBefore ? createAssignMutation(undo.path, undo.value, original, ids) : createLinkMutation(undo.path, restoredId);
894
+ }
895
+ }
896
+
897
+ // src/edges.ts
898
+ var { proxyStateMap: proxyStateMap7 } = unstable_getInternalStates();
899
+ var rawTargetOf3 = (value) => proxyStateMap7.get(value)?.[0] ?? value;
900
+ var rawOf2 = (node) => {
901
+ const peeled = peelReadProxy(node);
902
+ return rawTargetOf3(typeof peeled === "object" && peeled !== null ? peeled : node);
903
+ };
904
+ var occupancyRootOf = (handle) => rawTargetOf3(handle.proxy.root);
905
+ var edgesOf = (handle, node) => handle.nodes.get(node)?.edges;
906
+ var pathHasIgnored = (trie, path) => {
907
+ if (trie.ignored) return true;
908
+ let current = trie;
909
+ for (const key of path) {
910
+ current = declarationChild(current, key);
911
+ if (current === void 0) return false;
912
+ if (current.ignored) return true;
913
+ }
914
+ return false;
915
+ };
916
+ var pathIsTainted = (trie, path) => {
917
+ if (trie.unsafe) return true;
918
+ let current = trie;
919
+ for (const key of path) {
920
+ current = declarationChild(current, key);
921
+ if (current === void 0) return false;
922
+ if (current.unsafe) return true;
923
+ }
924
+ return false;
925
+ };
926
+ var walkGroundedChains = (handle, node, onGround) => {
927
+ const root = occupancyRootOf(handle);
928
+ const walk = (current, reverseKeys, pathVisited) => {
929
+ if (current === root) return onGround([...reverseKeys].reverse());
930
+ if (pathVisited.has(current)) return false;
931
+ pathVisited.add(current);
932
+ const edges = edgesOf(handle, current);
933
+ if (edges !== void 0) {
934
+ for (const edge of edges) {
935
+ if (walk(rawOf2(edge.parent), [...reverseKeys, edge.key], pathVisited)) {
936
+ pathVisited.delete(current);
937
+ return true;
938
+ }
939
+ }
940
+ }
941
+ pathVisited.delete(current);
942
+ return false;
943
+ };
944
+ walk(rawOf2(node), [], /* @__PURE__ */ new Set());
945
+ };
946
+ function addInEdge(handle, node, parent, key) {
947
+ const rawNode = rawOf2(node);
948
+ const rawParent = rawOf2(parent);
949
+ let record = handle.nodes.get(rawNode);
950
+ if (record === void 0) {
951
+ record = { edges: [], id: void 0 };
952
+ handle.nodes.set(rawNode, record);
953
+ }
954
+ if (record.edges.some((edge) => rawOf2(edge.parent) === rawParent && edge.key === key)) return;
955
+ record.edges.push({ parent: rawParent, key });
956
+ registerHandle(rawNode, handle);
957
+ }
958
+ function hasOtherRoutes(handle, node, parent, key) {
959
+ const edges = handle.nodes.get(rawOf2(node))?.edges;
960
+ if (edges === void 0) return false;
961
+ const rawParent = rawOf2(parent);
962
+ return edges.some((edge) => rawOf2(edge.parent) !== rawParent || edge.key !== key);
963
+ }
964
+ function removeInEdge(handle, node, parent, key) {
965
+ const rawNode = rawOf2(node);
966
+ const rawParent = rawOf2(parent);
967
+ const record = handle.nodes.get(rawNode);
968
+ if (record === void 0) return;
969
+ const index = record.edges.findIndex((edge) => rawOf2(edge.parent) === rawParent && edge.key === key);
970
+ if (index === -1) return;
971
+ record.edges.splice(index, 1);
972
+ if (rawNode !== occupancyRootOf(handle)) queueDeparture(handle, rawNode);
973
+ }
974
+ function edgeStatusOf(handle, node) {
975
+ const rawNode = rawOf2(node);
976
+ const root = occupancyRootOf(handle);
977
+ if (rawNode === root) {
978
+ return { occupied: true, unsafe: handle.declarations?.unsafe === true };
979
+ }
980
+ if (handle.declarations === void 0) {
981
+ let occupied = false;
982
+ walkGroundedChains(handle, rawNode, () => {
983
+ occupied = true;
984
+ return true;
985
+ });
986
+ return { occupied, unsafe: false };
987
+ }
988
+ const declarations = handle.declarations;
989
+ const status = { occupied: false, hasClean: false };
990
+ walkGroundedChains(handle, rawNode, (pathFromRoot) => {
991
+ status.occupied = true;
992
+ if (!pathIsTainted(declarations, pathFromRoot)) {
993
+ status.hasClean = true;
994
+ return true;
995
+ }
996
+ return false;
997
+ });
998
+ return { occupied: status.occupied, unsafe: status.occupied && !status.hasClean };
999
+ }
1000
+ function isIgnoredFrontier(handle, parent, key) {
1001
+ const trie = handle.declarations;
1002
+ if (trie === void 0) return false;
1003
+ let hit = false;
1004
+ walkGroundedChains(handle, parent, (pathFromRoot) => {
1005
+ if (pathHasIgnored(trie, [...pathFromRoot, key])) {
1006
+ hit = true;
1007
+ return true;
1008
+ }
1009
+ return false;
1010
+ });
1011
+ return hit;
1012
+ }
1013
+ var uniqueNodeChains = (entries) => {
1014
+ const unique = new Array();
1015
+ const undefinedFlags = /* @__PURE__ */ new Set();
1016
+ const definedFlags = /* @__PURE__ */ new WeakMap();
1017
+ for (const entry of entries) {
1018
+ const flags = `${entry.tainted ? "1" : "0"}${entry.ignored ? "1" : "0"}`;
1019
+ if (entry.residual === void 0) {
1020
+ if (undefinedFlags.has(flags)) continue;
1021
+ undefinedFlags.add(flags);
1022
+ unique.push(entry);
1023
+ continue;
1024
+ }
1025
+ let seen = definedFlags.get(entry.residual);
1026
+ if (seen === void 0) {
1027
+ seen = /* @__PURE__ */ new Set();
1028
+ definedFlags.set(entry.residual, seen);
1029
+ }
1030
+ if (seen.has(flags)) continue;
1031
+ seen.add(flags);
1032
+ unique.push(entry);
1033
+ }
1034
+ return unique;
1035
+ };
1036
+ var uniqueResiduals = (residuals) => {
1037
+ const unique = new Array();
1038
+ let sawUndefined = false;
1039
+ const seen = /* @__PURE__ */ new Set();
1040
+ for (const residual of residuals) {
1041
+ if (residual === void 0) {
1042
+ if (sawUndefined) continue;
1043
+ sawUndefined = true;
1044
+ unique.push(void 0);
1045
+ continue;
1046
+ }
1047
+ if (seen.has(residual)) continue;
1048
+ seen.add(residual);
1049
+ unique.push(residual);
1050
+ }
1051
+ return unique;
1052
+ };
1053
+ var chainsAtNode = (handle, node, memo2, computing) => {
1054
+ const raw = rawOf2(node);
1055
+ const cached = memo2.get(raw);
1056
+ if (cached !== void 0) return cached;
1057
+ if (computing.has(raw)) return { occupied: false, entries: [], cut: true };
1058
+ if (raw === occupancyRootOf(handle)) {
1059
+ const trie = handle.declarations;
1060
+ const result2 = {
1061
+ occupied: true,
1062
+ entries: [
1063
+ {
1064
+ residual: trie,
1065
+ tainted: trie?.unsafe === true,
1066
+ ignored: trie?.ignored === true
1067
+ }
1068
+ ],
1069
+ cut: false
1070
+ };
1071
+ memo2.set(raw, result2);
1072
+ return result2;
1073
+ }
1074
+ computing.add(raw);
1075
+ const aggregated = new Array();
1076
+ let occupied = false;
1077
+ let cut = false;
1078
+ const edges = edgesOf(handle, raw);
1079
+ if (edges !== void 0) {
1080
+ for (const edge of edges) {
1081
+ const parent = chainsAtNode(handle, edge.parent, memo2, computing);
1082
+ if (parent.cut) cut = true;
1083
+ if (!parent.occupied) continue;
1084
+ occupied = true;
1085
+ for (const entry of parent.entries) {
1086
+ const child = entry.residual === void 0 ? void 0 : declarationChild(entry.residual, edge.key);
1087
+ aggregated.push({
1088
+ residual: child,
1089
+ tainted: entry.tainted || child?.unsafe === true,
1090
+ ignored: entry.ignored || child?.ignored === true
1091
+ });
1092
+ }
1093
+ }
1094
+ }
1095
+ computing.delete(raw);
1096
+ const result = { occupied, entries: uniqueNodeChains(aggregated), cut };
1097
+ if (!cut) memo2.set(raw, result);
1098
+ return result;
1099
+ };
1100
+ function descendChains(chains, key) {
1101
+ const next = new Array();
1102
+ let ignored = false;
1103
+ for (const residual of chains) {
1104
+ if (residual === void 0) {
1105
+ next.push(void 0);
1106
+ continue;
1107
+ }
1108
+ const child = declarationChild(residual, key);
1109
+ if (child?.ignored === true) ignored = true;
1110
+ if (child?.unsafe === true) continue;
1111
+ next.push(child);
1112
+ }
1113
+ return {
1114
+ ignored,
1115
+ unsafe: chains.length > 0 && next.length === 0,
1116
+ chains: uniqueResiduals(next)
1117
+ };
1118
+ }
1119
+ var childChainsOf = (chains, key) => descendChains(chains, key).chains;
1120
+ var isChainsIgnored = (chains) => chains.some((chain) => chain?.ignored === true);
1121
+ var isChainsUnsafe = (chains) => chains.length === 0;
1122
+ var chainsAtRoot = (declarations) => declarations?.unsafe === true ? [] : [declarations];
1123
+ function nodeChainsOf(handle, node) {
1124
+ const nodeChains = chainsAtNode(handle, node, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Set());
1125
+ if (!nodeChains.occupied) return void 0;
1126
+ const chains = new Array();
1127
+ for (const entry of nodeChains.entries) {
1128
+ if (entry.tainted) continue;
1129
+ chains.push(entry.residual);
1130
+ }
1131
+ return uniqueResiduals(chains);
1132
+ }
1133
+ function slotStatusOf(handle, parent, key) {
1134
+ const parentChains = chainsAtNode(handle, parent, /* @__PURE__ */ new Map(), /* @__PURE__ */ new Set());
1135
+ if (!parentChains.occupied) {
1136
+ return { occupied: false, unsafe: false, ignored: false, chains: [] };
1137
+ }
1138
+ const chains = new Array();
1139
+ let ignored = false;
1140
+ for (const entry of parentChains.entries) {
1141
+ const child = entry.residual === void 0 ? void 0 : declarationChild(entry.residual, key);
1142
+ const slotIgnored = entry.ignored || child?.ignored === true;
1143
+ const tainted = entry.tainted || child?.unsafe === true;
1144
+ if (slotIgnored) ignored = true;
1145
+ if (!tainted) chains.push(child);
1146
+ }
1147
+ return {
1148
+ ignored,
1149
+ occupied: true,
1150
+ unsafe: chains.length === 0,
1151
+ chains: uniqueResiduals(chains)
1152
+ };
1153
+ }
1154
+ var isTrackedEdge = (entry) => {
1155
+ const value = entry.value;
1156
+ const target = isObjectLike3(value) ? getRegisteredTarget(value) ?? value : value;
1157
+ return entry.writable && admissionLane(target) === "tracked";
1158
+ };
1159
+ var graphNodeOf = (value) => rawOf2(getRegisteredTarget(value) ?? value);
1160
+ function resolveChildChains(handle, parent, parentChains, key, child) {
1161
+ const descended = descendChains(parentChains, key).chains;
1162
+ const ignoredResidual = isChainsIgnored(parentChains) || isChainsIgnored(descended);
1163
+ if (!isObjectLike3(parent) || !isObjectLike3(child)) {
1164
+ if (ignoredResidual) return void 0;
1165
+ return { chains: descended, descended, otherRoutes: false };
1166
+ }
1167
+ const graphParent = graphNodeOf(parent);
1168
+ const graphChild = graphNodeOf(child);
1169
+ const otherRoutes = hasOtherRoutes(handle, graphChild, graphParent, key);
1170
+ const ignored = ignoredResidual || otherRoutes && isIgnoredFrontier(handle, graphParent, key);
1171
+ if (ignored) return void 0;
1172
+ const chains = otherRoutes ? nodeChainsOf(handle, graphChild) ?? descended : descended;
1173
+ return { chains, descended, otherRoutes };
1174
+ }
1175
+ var seedFrom = (handle, node, chains, visits) => {
1176
+ if (isChainsIgnored(chains)) return;
1177
+ const raw = rawOf2(node);
1178
+ if (visits.has(raw)) return;
1179
+ visits.add(raw);
1180
+ for (const entry of walkDataEntries(raw)) {
1181
+ if (!isTrackedEdge(entry)) continue;
1182
+ if (typeof entry.value !== "object" || entry.value === null) continue;
1183
+ const key = segmentFor(raw, entry.key);
1184
+ const resolved = resolveChildChains(handle, raw, chains, key, entry.value);
1185
+ if (resolved === void 0) continue;
1186
+ addInEdge(handle, entry.value, raw, key);
1187
+ seedFrom(handle, entry.value, resolved.chains, visits);
1188
+ }
1189
+ };
1190
+ function seedInEdges(handle) {
1191
+ seedFrom(handle, handle.proxy.root, chainsAtRoot(handle.declarations), /* @__PURE__ */ new Set());
1192
+ }
1193
+ function seedInEdgesUnder(handle, node, chains) {
1194
+ seedFrom(handle, node, chains, /* @__PURE__ */ new Set());
1195
+ }
1196
+
1197
+ // src/occupancy.ts
1198
+ var { proxyStateMap: proxyStateMap8 } = unstable_getInternalStates();
1199
+ var rawTargetOf4 = (value) => proxyStateMap8.get(value)?.[0] ?? value;
1200
+ var liveOf = (value) => getRegisteredTarget(value) ?? rawTargetOf4(value);
1201
+ var createCaptureTables = () => ({
1202
+ mints: [],
1203
+ binds: [],
1204
+ bindIdByNode: /* @__PURE__ */ new Map(),
1205
+ bindNodeById: /* @__PURE__ */ new Map(),
1206
+ mintIdByNode: /* @__PURE__ */ new Map(),
1207
+ mintNodeById: /* @__PURE__ */ new Map(),
1208
+ nextStagedId: 0
1209
+ });
1210
+ var occupancyKeyOf = (key) => typeof key === "number" ? String(key) : key;
1211
+ function bindVisitedOccupancy(handle, path, parent, key, child, unsafe = false, ignoredFrontier) {
1212
+ if (path.length === 0) return "continue";
1213
+ if (ignoredFrontier ?? isIgnoredFrontier(handle, parent, key)) return "skip";
1214
+ const parentRaw = liveOf(parent);
1215
+ const occupancyKey = occupancyKeyOf(key);
1216
+ const admitted = unsafe || !handle.strict;
1217
+ if (typeof child === "function") {
1218
+ const parentKind = classifyValue(parentRaw);
1219
+ if (parentKind === "plain" || parentKind === "plainArray") return "continue";
1220
+ if (admitted) return "continue";
1221
+ return "skip";
1222
+ }
1223
+ const stored = Reflect.get(parentRaw, occupancyKey);
1224
+ const occupantSource = isObjectLike3(stored) ? stored : child;
1225
+ if (typeof occupantSource !== "object" || occupantSource === null) return "continue";
1226
+ const childLive = liveOf(occupantSource);
1227
+ const descriptor = Reflect.getOwnPropertyDescriptor(parentRaw, occupancyKey);
1228
+ if (descriptor !== void 0 && descriptor.writable !== true && admissionDecision(childLive).lane !== "untracked")
1229
+ return "skip";
1230
+ const decision = admissionDecision(childLive);
1231
+ if (decision.lane === "untracked") return "skip";
1232
+ if (decision.lane === "dangerous") {
1233
+ if (admitted) return "continue";
1234
+ return "skip";
1235
+ }
1236
+ if (!admitted && classifyValue(childLive) === "cleanClass") {
1237
+ for (const entry of walkDataEntries(childLive)) {
1238
+ if (typeof entry.value !== "function") continue;
1239
+ return "skip";
1240
+ }
1241
+ }
1242
+ return "continue";
1243
+ }
1244
+ function markDirtyPath(dirty, handle, path, parentLive) {
1245
+ let current = handle.proxy.root;
1246
+ if (isObjectLike3(current)) dirty.nodes.add(rawTargetOf4(current));
1247
+ for (const segment of path) {
1248
+ if (!isObjectLike3(current)) break;
1249
+ current = Reflect.get(current, segment);
1250
+ if (isObjectLike3(current)) dirty.nodes.add(rawTargetOf4(current));
1251
+ }
1252
+ if (parentLive === void 0 || path.length === 0) return;
1253
+ const lastSegment = path[path.length - 1];
1254
+ if (lastSegment === void 0) return;
1255
+ const edge = typeof lastSegment === "number" ? String(lastSegment) : lastSegment;
1256
+ const parentRaw = rawTargetOf4(parentLive);
1257
+ let edges = dirty.edges.get(parentRaw);
1258
+ if (edges === void 0) {
1259
+ edges = /* @__PURE__ */ new Set();
1260
+ dirty.edges.set(parentRaw, edges);
1261
+ }
1262
+ edges.add(edge);
1263
+ }
1264
+ var walkLiveOccupancies = (handle, capture) => {
1265
+ const root = handle.proxy.root;
1266
+ const visits = /* @__PURE__ */ new Set();
1267
+ const rootChains = handle.declarations?.unsafe === true ? [] : [handle.declarations];
1268
+ const walk = (node, path, chains) => {
1269
+ if (chains.some((residual) => residual?.ignored === true)) return;
1270
+ stageVend(handle, capture, node);
1271
+ const nodeRaw = rawTargetOf4(node);
1272
+ if (visits.has(nodeRaw)) return;
1273
+ visits.add(nodeRaw);
1274
+ for (const entry of walkDataEntries(node)) {
1275
+ const key = segmentFor(node, entry.key);
1276
+ const childPath = appendOperationPath(path, key);
1277
+ const slot = slotStatusOf(handle, node, key);
1278
+ const descended = descendChains(chains, key);
1279
+ const ignored = slot.ignored || descended.ignored;
1280
+ const unsafe = slot.occupied ? slot.unsafe : descended.unsafe;
1281
+ const childChains = slot.occupied ? slot.chains : descended.chains;
1282
+ if (ignored) continue;
1283
+ const visit = bindVisitedOccupancy(handle, childPath, node, entry.key, entry.value, unsafe);
1284
+ if (visit !== "continue") continue;
1285
+ if (typeof entry.value === "object" && entry.value !== null) walk(entry.value, childPath, childChains);
717
1286
  }
718
- weight += pushReplace(ops, appendOperationPath(path, "length"), before.length, after.length);
1287
+ };
1288
+ walk(root, createOperationPath([]), rootChains);
1289
+ };
1290
+ function seedOccupancies(handle) {
1291
+ const capture = createCaptureTables();
1292
+ walkLiveOccupancies(handle, capture);
1293
+ commitVends(handle, capture);
1294
+ }
1295
+ function syncHandleTables(handle, capture) {
1296
+ walkLiveOccupancies(handle, capture);
1297
+ }
1298
+
1299
+ // src/ops/admission.ts
1300
+ var { proxyStateMap: proxyStateMap9 } = unstable_getInternalStates();
1301
+ var rawTargetOf5 = (value) => proxyStateMap9.get(value)?.[0] ?? value;
1302
+ var MissingDiffParentError = class extends Error {
1303
+ constructor() {
1304
+ super("opshot: admitStep could not resolve a live parent");
1305
+ this.name = "MissingDiffParentError";
1306
+ }
1307
+ };
1308
+ var admitStep = (handle, dirty, path, liveParent, residual) => {
1309
+ if (path.length === 0) {
1310
+ return { visit: "continue", ignored: isChainsIgnored(residual), liveChild: liveParent, chains: residual };
1311
+ }
1312
+ const key = path[path.length - 1];
1313
+ const liveChild = isObjectLike3(liveParent) && key !== void 0 ? Reflect.get(liveParent, key) : void 0;
1314
+ if (handle === void 0) {
1315
+ const childChains = key === void 0 ? residual : childChainsOf(residual, key);
1316
+ return { visit: "continue", ignored: isChainsIgnored(childChains), liveChild, chains: childChains };
1317
+ }
1318
+ if (key === void 0) {
1319
+ return { visit: "continue", ignored: isChainsIgnored(residual), liveChild: liveParent, chains: residual };
1320
+ }
1321
+ const resolved = resolveChildChains(handle, liveParent, residual, key, liveChild);
1322
+ const ignored = resolved === void 0;
1323
+ const chains = resolved?.chains ?? childChainsOf(residual, key);
1324
+ if (dirty === void 0) return { visit: "continue", ignored, liveChild, chains };
1325
+ if (ignored) return { visit: "skip", ignored, liveChild, chains };
1326
+ if (resolved.otherRoutes) {
1327
+ if (!isObjectLike3(liveParent) || !isObjectLike3(liveChild)) throw new MissingDiffParentError();
1328
+ const slot = slotStatusOf(handle, liveParent, key);
1329
+ let unsafe = slot.occupied ? slot.unsafe : isChainsUnsafe(resolved.descended);
1330
+ const status = edgeStatusOf(handle, liveChild);
1331
+ if (status.occupied) unsafe = status.unsafe;
1332
+ return {
1333
+ visit: bindVisitedOccupancy(handle, path, liveParent, key, liveChild, unsafe, false),
1334
+ ignored,
1335
+ liveChild,
1336
+ chains
1337
+ };
1338
+ }
1339
+ if (!isObjectLike3(liveParent)) throw new MissingDiffParentError();
1340
+ return {
1341
+ visit: bindVisitedOccupancy(handle, path, liveParent, key, liveChild, isChainsUnsafe(resolved.descended), false),
1342
+ ignored,
1343
+ liveChild,
1344
+ chains
1345
+ };
1346
+ };
1347
+ var admitDescendants = (handle, path, visits, residual, liveNode, unsafe = false) => {
1348
+ if (handle === void 0) return;
1349
+ if (!isObjectLike3(liveNode)) return;
1350
+ const nodeKey = rawTargetOf5(liveNode);
1351
+ if (visits.has(nodeKey)) return;
1352
+ visits.add(nodeKey);
1353
+ if (isChainsIgnored(residual)) return;
1354
+ const nodeUnsafe = unsafe || isChainsUnsafe(residual);
1355
+ for (const entry of walkDataEntries(liveNode)) {
1356
+ if (typeof entry.value !== "object" || entry.value === null) continue;
1357
+ const key = segmentFor(liveNode, entry.key);
1358
+ const childPath = appendOperationPath(path, key);
1359
+ const descended = descendChains(residual, key);
1360
+ let ignored;
1361
+ let childChains;
1362
+ let childUnsafe;
1363
+ let ignoredFrontier;
1364
+ if (hasOtherRoutes(handle, entry.value, liveNode, key)) {
1365
+ const slot = slotStatusOf(handle, liveNode, key);
1366
+ ignored = slot.ignored || descended.ignored;
1367
+ childChains = nodeChainsOf(handle, entry.value) ?? descended.chains;
1368
+ childUnsafe = slot.occupied ? slot.unsafe : nodeUnsafe || descended.unsafe;
1369
+ ignoredFrontier = void 0;
1370
+ } else {
1371
+ ignored = descended.ignored || isChainsIgnored(descended.chains);
1372
+ childChains = descended.chains;
1373
+ childUnsafe = nodeUnsafe || descended.unsafe;
1374
+ ignoredFrontier = false;
1375
+ }
1376
+ if (ignored) continue;
1377
+ const visit = bindVisitedOccupancy(
1378
+ handle,
1379
+ childPath,
1380
+ liveNode,
1381
+ entry.key,
1382
+ entry.value,
1383
+ childUnsafe,
1384
+ ignoredFrontier
1385
+ );
1386
+ if (visit !== "continue") continue;
1387
+ admitDescendants(handle, childPath, visits, childChains, Reflect.get(liveNode, key), childUnsafe);
1388
+ }
1389
+ };
1390
+ var markChangedPath = (handle, dirty, path, liveParent) => {
1391
+ if (handle === void 0 || dirty === void 0 || path.length === 0) return;
1392
+ if (!isObjectLike3(liveParent)) return;
1393
+ markDirtyPath(dirty, handle, path, liveParent);
1394
+ };
1395
+ var emitsSkippedOccupancy = (value) => isObjectLike3(value) && admissionLane(value) === "untracked";
1396
+
1397
+ // src/ops/ancestorPairs.ts
1398
+ var MissingAncestorPairError = class extends Error {
1399
+ constructor() {
1400
+ super("opshot: exitAncestorPair without matching enterAncestorPair");
1401
+ this.name = "MissingAncestorPairError";
719
1402
  }
720
- weight += diffObjectProperties(before, after, path, ops, ancestors, true);
721
- return weight;
722
1403
  };
723
- var walkContainer = (before, after, path, ops, ancestors, walk) => {
724
- if (hasAncestorPair(ancestors, before, after)) throw cyclicError(path);
1404
+ var hasAncestorPair = (ancestors, before, after) => ancestors.get(before)?.has(after) ?? false;
1405
+ var enterAncestorPair = (ancestors, before, after) => {
1406
+ const afterSet = ancestors.get(before) ?? /* @__PURE__ */ new Set();
1407
+ afterSet.add(after);
1408
+ ancestors.set(before, afterSet);
1409
+ };
1410
+ var exitAncestorPair = (ancestors, before, after) => {
1411
+ const afterSet = ancestors.get(before);
1412
+ if (afterSet === void 0) throw new MissingAncestorPairError();
1413
+ afterSet.delete(after);
1414
+ if (afterSet.size === 0) ancestors.delete(before);
1415
+ };
1416
+ var walkContainer = (ancestors, before, after, walk) => {
1417
+ if (hasAncestorPair(ancestors, before, after)) return;
725
1418
  enterAncestorPair(ancestors, before, after);
726
1419
  try {
727
- if (path.length === 0) {
728
- walk();
729
- return 0;
730
- }
731
- const opsStart = ops.length;
732
- const atomicWeight = walk();
733
- return tryCollapse(before, after, path, ops, opsStart, atomicWeight);
1420
+ walk();
734
1421
  } finally {
735
1422
  exitAncestorPair(ancestors, before, after);
736
1423
  }
737
1424
  };
738
- var diffValue = (before, after, path, ops, ancestors) => {
739
- if (Object.is(before, after)) return 0;
740
- if (path.length > 0 && isObjectLike2(before) && isObjectLike2(after) && !sharesStorageIdentity(before, after)) {
741
- assertSafeSubtree(before, path);
742
- assertSafeSubtree(after, path);
743
- return pushReplace(ops, path, before, after);
1425
+
1426
+ // src/ops/internedOccupancy.ts
1427
+ var { proxyStateMap: proxyStateMap10 } = unstable_getInternalStates();
1428
+ var rawTargetOf6 = (value) => proxyStateMap10.get(value)?.[0] ?? value;
1429
+ var liveOf2 = (node) => getRegisteredTarget(node) ?? node;
1430
+ var occupancyNodeOf2 = (node) => rawTargetOf6(liveOf2(node));
1431
+ var internedOccupied = (handle, node, capture) => internedIdOf(handle, node, capture) !== void 0 && edgeStatusOf(handle, occupancyNodeOf2(node)).occupied;
1432
+
1433
+ // src/ops/mintPairs.ts
1434
+ var additionPair = (path, after, ids) => ({
1435
+ do: createAssignMutation(path, after, after, ids),
1436
+ undo: createDeleteMutation(path)
1437
+ });
1438
+ var removalPair = (path, before) => ({
1439
+ do: createDeleteMutation(path),
1440
+ undo: createAssignMutation(path, before)
1441
+ });
1442
+ var linkUndo = (path, before, beforePresent, handle, capture) => {
1443
+ if (!beforePresent) return createDeleteMutation(path);
1444
+ if (handle !== void 0 && isObjectLike3(before) && internedOccupied(handle, before, capture)) {
1445
+ const id = internedIdOf(handle, before, capture);
1446
+ if (id !== void 0) return createLinkMutation(path, id);
1447
+ }
1448
+ return createAssignMutation(path, before);
1449
+ };
1450
+ var linkOperation = (path, ref, before, beforePresent, handle, capture) => ({
1451
+ do: createLinkMutation(path, ref),
1452
+ undo: linkUndo(path, before, beforePresent, handle, capture)
1453
+ });
1454
+ var changePair = (path, before, after, handle, capture, ids) => ({
1455
+ do: createAssignMutation(path, after, after, ids),
1456
+ undo: linkUndo(path, before, true, handle, capture)
1457
+ });
1458
+
1459
+ // src/ops/diff.ts
1460
+ var IncompatibleObjectRootsError = class extends Error {
1461
+ constructor() {
1462
+ super("opshot: diffObjects requires compatible supported object roots");
1463
+ this.name = "IncompatibleObjectRootsError";
1464
+ }
1465
+ };
1466
+ var commitOperation = (context, pair) => {
1467
+ context.ops.push(pair);
1468
+ };
1469
+ var commitLink = (context, path, ref, before, beforePresent) => {
1470
+ commitOperation(context, linkOperation(path, ref, before, beforePresent, context.handle, context.capture));
1471
+ };
1472
+ var emptyContainerOf = (value) => isPlainArray(value) ? [] : {};
1473
+ var namedArrayEntriesOf = (value) => {
1474
+ const named = /* @__PURE__ */ new Map();
1475
+ for (const key of Object.keys(value)) {
1476
+ if (key === "__proto__" || isCanonicalArrayIndexString(key)) continue;
1477
+ const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
1478
+ if (!descriptor || !("value" in descriptor)) continue;
1479
+ named.set(key, descriptor.value);
1480
+ }
1481
+ return named;
1482
+ };
1483
+ var mintDecomposedContents = (context, path, after, verdict) => {
1484
+ const residual = verdict.chains;
1485
+ const liveNode = verdict.liveChild;
1486
+ if (isPlainArray(after)) {
1487
+ if (after.length > 0)
1488
+ commitOperation(
1489
+ context,
1490
+ changePair(appendOperationPath(path, "length"), 0, after.length, context.handle, context.capture)
1491
+ );
1492
+ for (let index = 0; index < after.length; index++) {
1493
+ if (!Object.hasOwn(after, index)) continue;
1494
+ const nextPath = appendOperationPath(path, index);
1495
+ const childVerdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1496
+ pushAddition(context, nextPath, after[index], childVerdict, liveNode);
1497
+ }
1498
+ for (const [key, value] of namedArrayEntriesOf(after)) {
1499
+ const nextPath = appendOperationPath(path, key);
1500
+ const childVerdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1501
+ pushAddition(context, nextPath, value, childVerdict, liveNode);
1502
+ }
1503
+ } else {
1504
+ for (const entry of walkDataEntries(after)) {
1505
+ const nextPath = appendOperationPath(path, entry.key);
1506
+ const childVerdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1507
+ pushAddition(context, nextPath, entry.value, childVerdict, liveNode);
1508
+ }
1509
+ }
1510
+ };
1511
+ var mintDecomposedAddition = (context, path, after, verdict) => {
1512
+ commitOperation(context, {
1513
+ do: createAssignMutation(path, emptyContainerOf(after), after),
1514
+ undo: createDeleteMutation(path)
1515
+ });
1516
+ mintDecomposedContents(context, path, after, verdict);
1517
+ };
1518
+ var mintDecomposedChange = (context, path, before, after, verdict) => {
1519
+ commitOperation(context, {
1520
+ do: createAssignMutation(path, emptyContainerOf(after), after),
1521
+ undo: linkUndo(path, before, true, context.handle, context.capture)
1522
+ });
1523
+ mintDecomposedContents(context, path, after, verdict);
1524
+ };
1525
+ var surveyAssignedSubtree = (handle, capture, node, residual, stopAtInternedOccupied) => {
1526
+ const visits = /* @__PURE__ */ new Set();
1527
+ const pending = new Array();
1528
+ const visit = (current, currentResidual) => {
1529
+ const raw = occupancyNodeOf2(current);
1530
+ if (visits.has(raw)) return false;
1531
+ visits.add(raw);
1532
+ if (admissionLane(current) === "untracked") return false;
1533
+ if (stopAtInternedOccupied) {
1534
+ if (current !== node) pending.push(current);
1535
+ } else stageVend(handle, capture, current);
1536
+ const source = liveOf2(current);
1537
+ for (const entry of walkDataEntries(source)) {
1538
+ if (typeof entry.value !== "object" || entry.value === null) continue;
1539
+ if (!isTrackedEdge(entry)) continue;
1540
+ const key = segmentFor(source, entry.key);
1541
+ const resolved = resolveChildChains(handle, source, currentResidual, key, entry.value);
1542
+ if (resolved === void 0) continue;
1543
+ const child = entry.value;
1544
+ if (stopAtInternedOccupied && internedOccupied(handle, child, capture)) return true;
1545
+ if (visit(child, resolved.chains)) return true;
1546
+ }
1547
+ return false;
1548
+ };
1549
+ if (stopAtInternedOccupied) stageVend(handle, capture, node);
1550
+ const reachesInternedOccupied = visit(node, residual);
1551
+ if (stopAtInternedOccupied && !reachesInternedOccupied) {
1552
+ for (const pendingNode of pending) stageVend(handle, capture, pendingNode);
1553
+ }
1554
+ return { reachesInternedOccupied };
1555
+ };
1556
+ var internIdsOfSubtree = (handle, node, capture) => {
1557
+ const seen = /* @__PURE__ */ new Set();
1558
+ const ids = new Array();
1559
+ const walk = (current) => {
1560
+ const id = internedIdOf(handle, current, capture);
1561
+ if (id === void 0 || seen.has(id)) return;
1562
+ seen.add(id);
1563
+ ids.push(id);
1564
+ for (const entry of walkDataEntries(liveOf2(current))) {
1565
+ if (typeof entry.value === "object" && entry.value !== null) walk(entry.value);
1566
+ }
1567
+ };
1568
+ walk(node);
1569
+ return ids.length === 0 ? void 0 : ids;
1570
+ };
1571
+ var mintAssignment = (context, path, before, after, beforePresent, verdict) => {
1572
+ if (verdict.ignored) return;
1573
+ const handle = context.handle;
1574
+ if (isObjectLike3(after) && handle !== void 0) {
1575
+ const internedId = internedIdOf(handle, after, context.capture);
1576
+ if (internedId !== void 0 && internedOccupied(handle, after, context.capture)) {
1577
+ const sameOccupant = isObjectLike3(before) && occupancyNodeOf2(before) === occupancyNodeOf2(after);
1578
+ const beforeInterned = isObjectLike3(before) && internedIdOf(handle, before, context.capture) !== void 0;
1579
+ const uninternedTrackedBefore = isObjectLike3(before) && !beforeInterned && admissionLane(before) !== "untracked";
1580
+ if (!sameOccupant && !uninternedTrackedBefore) {
1581
+ commitLink(context, path, internedId, before, beforePresent);
1582
+ return;
1583
+ }
1584
+ surveyAssignedSubtree(handle, context.capture, after, verdict.chains, false);
1585
+ } else if (admissionLane(after) !== "untracked" && (isPlainObject(after) || isPlainArray(after))) {
1586
+ const { reachesInternedOccupied } = surveyAssignedSubtree(
1587
+ handle,
1588
+ context.capture,
1589
+ after,
1590
+ verdict.chains,
1591
+ true
1592
+ );
1593
+ if (reachesInternedOccupied) {
1594
+ if (!beforePresent) {
1595
+ mintDecomposedAddition(context, path, after, verdict);
1596
+ return;
1597
+ }
1598
+ mintDecomposedChange(context, path, before, after, verdict);
1599
+ return;
1600
+ }
1601
+ } else {
1602
+ admitDescendants(handle, path, /* @__PURE__ */ new Set(), verdict.chains, verdict.liveChild);
1603
+ internSubtree(
1604
+ handle,
1605
+ after,
1606
+ verdict.chains,
1607
+ (parent, parentChains, key, entry) => isTrackedEdge(entry) ? resolveChildChains(handle, parent, parentChains, key, entry.value)?.chains : void 0,
1608
+ context.capture
1609
+ );
1610
+ }
1611
+ } else if (isObjectLike3(after)) admitDescendants(context.handle, path, /* @__PURE__ */ new Set(), verdict.chains, verdict.liveChild);
1612
+ const ids = isObjectLike3(after) && handle !== void 0 ? internIdsOfSubtree(handle, after, context.capture) : void 0;
1613
+ if (beforePresent) commitOperation(context, changePair(path, before, after, handle, context.capture, ids));
1614
+ else commitOperation(context, additionPair(path, after, ids));
1615
+ };
1616
+ var pushAddition = (context, path, after, verdict, liveParent) => {
1617
+ const { visit, ignored } = verdict;
1618
+ if (visit === "skip") {
1619
+ if (ignored || !emitsSkippedOccupancy(after)) return;
1620
+ } else if (ignored) return;
1621
+ markChangedPath(context.handle, context.dirty, path, liveParent);
1622
+ mintAssignment(context, path, void 0, after, false, verdict);
1623
+ };
1624
+ var pushRemoval = (context, path, before, verdict, liveParent) => {
1625
+ if (verdict.ignored) return;
1626
+ markChangedPath(context.handle, context.dirty, path, liveParent);
1627
+ const handle = context.handle;
1628
+ if (isObjectLike3(before) && handle !== void 0) {
1629
+ const id = internedIdOf(handle, before, context.capture);
1630
+ if (id !== void 0 && internedOccupied(handle, before, context.capture)) {
1631
+ commitOperation(context, {
1632
+ do: createDeleteMutation(path),
1633
+ undo: createLinkMutation(path, id)
1634
+ });
1635
+ return;
1636
+ }
1637
+ }
1638
+ commitOperation(context, removalPair(path, before));
1639
+ };
1640
+ var pushChange = (context, path, before, after, verdict, liveParent) => {
1641
+ markChangedPath(context.handle, context.dirty, path, liveParent);
1642
+ mintAssignment(context, path, before, after, true, verdict);
1643
+ };
1644
+ var sharesStorageIdentity = (before, after) => isObjectLike3(before) && isObjectLike3(after) && isSameIdentity(before, after);
1645
+ var diffCollectedProperties = (context, before, after, path, residual, liveNode, beforeEntries, afterEntries) => {
1646
+ const keys = /* @__PURE__ */ new Set([...beforeEntries.keys(), ...afterEntries.keys()]);
1647
+ for (const key of keys) {
1648
+ const nextPath = appendOperationPath(path, key);
1649
+ const beforePresent = beforeEntries.has(key);
1650
+ const afterPresent = afterEntries.has(key);
1651
+ if (beforePresent && afterPresent) {
1652
+ diffValue(context, beforeEntries.get(key), afterEntries.get(key), nextPath, residual, liveNode);
1653
+ } else if (beforePresent && !Object.hasOwn(after, key)) {
1654
+ const verdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1655
+ pushRemoval(context, nextPath, beforeEntries.get(key), verdict, liveNode);
1656
+ } else if (afterPresent && !Object.hasOwn(before, key)) {
1657
+ const verdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1658
+ pushAddition(context, nextPath, afterEntries.get(key), verdict, liveNode);
1659
+ }
1660
+ }
1661
+ };
1662
+ var diffObjectProperties = (context, before, after, path, residual, liveNode) => {
1663
+ diffCollectedProperties(
1664
+ context,
1665
+ before,
1666
+ after,
1667
+ path,
1668
+ residual,
1669
+ liveNode,
1670
+ dataEntryValuesOf(before),
1671
+ dataEntryValuesOf(after)
1672
+ );
1673
+ };
1674
+ var diffArray = (context, before, after, path, residual, liveNode) => {
1675
+ const overlap = Math.min(before.length, after.length);
1676
+ for (let index = 0; index < overlap; index++) {
1677
+ const beforePresent = Object.hasOwn(before, index);
1678
+ const afterPresent = Object.hasOwn(after, index);
1679
+ if (!beforePresent && !afterPresent) continue;
1680
+ const nextPath = appendOperationPath(path, index);
1681
+ if (!beforePresent) {
1682
+ const verdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1683
+ pushAddition(context, nextPath, after[index], verdict, liveNode);
1684
+ } else if (!afterPresent) {
1685
+ const verdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1686
+ pushRemoval(context, nextPath, before[index], verdict, liveNode);
1687
+ } else diffValue(context, before[index], after[index], nextPath, residual, liveNode);
1688
+ }
1689
+ if (after.length > before.length) {
1690
+ const lengthPath = appendOperationPath(path, "length");
1691
+ const lengthVerdict = admitStep(context.handle, context.dirty, lengthPath, liveNode, residual);
1692
+ pushChange(context, lengthPath, before.length, after.length, lengthVerdict, liveNode);
1693
+ for (let index = before.length; index < after.length; index++) {
1694
+ if (!Object.hasOwn(after, index)) continue;
1695
+ const nextPath = appendOperationPath(path, index);
1696
+ const verdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1697
+ pushAddition(context, nextPath, after[index], verdict, liveNode);
1698
+ }
1699
+ } else if (after.length < before.length) {
1700
+ for (let index = after.length; index < before.length; index++) {
1701
+ if (!Object.hasOwn(before, index)) continue;
1702
+ const nextPath = appendOperationPath(path, index);
1703
+ const verdict = admitStep(context.handle, context.dirty, nextPath, liveNode, residual);
1704
+ pushRemoval(context, nextPath, before[index], verdict, liveNode);
1705
+ }
1706
+ const lengthPath = appendOperationPath(path, "length");
1707
+ const lengthVerdict = admitStep(context.handle, context.dirty, lengthPath, liveNode, residual);
1708
+ pushChange(context, lengthPath, before.length, after.length, lengthVerdict, liveNode);
1709
+ }
1710
+ diffCollectedProperties(
1711
+ context,
1712
+ before,
1713
+ after,
1714
+ path,
1715
+ residual,
1716
+ liveNode,
1717
+ namedArrayEntriesOf(before),
1718
+ namedArrayEntriesOf(after)
1719
+ );
1720
+ };
1721
+ var diffValue = (context, before, after, path, residual, liveParent) => {
1722
+ const replacing = path.length > 0 && isObjectLike3(before) && isObjectLike3(after) && !sharesStorageIdentity(before, after);
1723
+ const verdict = admitStep(context.handle, context.dirty, path, liveParent, residual);
1724
+ const { visit, ignored, liveChild, chains } = verdict;
1725
+ if (visit === "skip" || ignored) {
1726
+ if (Object.is(before, after)) return;
1727
+ if (isObjectLike3(before) && isObjectLike3(after) && sharesStorageIdentity(before, after)) return;
1728
+ if (ignored || !emitsSkippedOccupancy(after)) return;
1729
+ pushChange(context, path, before, after, verdict, liveParent);
1730
+ return;
1731
+ }
1732
+ if (Object.is(before, after)) return;
1733
+ if (replacing) {
1734
+ pushChange(context, path, before, after, verdict, liveParent);
1735
+ return;
744
1736
  }
745
1737
  if (isPlainArray(before) && isPlainArray(after)) {
746
- return walkContainer(before, after, path, ops, ancestors, () => diffArray(before, after, path, ops, ancestors));
1738
+ walkContainer(context.ancestors, before, after, () => diffArray(context, before, after, path, chains, liveChild));
1739
+ return;
747
1740
  }
748
1741
  if (isPlainObject(before) && isPlainObject(after)) {
749
- return walkContainer(
1742
+ walkContainer(
1743
+ context.ancestors,
750
1744
  before,
751
1745
  after,
752
- path,
753
- ops,
754
- ancestors,
755
- () => diffObjectProperties(before, after, path, ops, ancestors, false)
1746
+ () => diffObjectProperties(context, before, after, path, chains, liveChild)
756
1747
  );
1748
+ return;
757
1749
  }
758
- assertSafeSubtree(before, path);
759
- assertSafeSubtree(after, path);
760
- return pushReplace(ops, path, before, after);
1750
+ pushChange(context, path, before, after, verdict, liveParent);
761
1751
  };
762
1752
  var getRootKind = (value) => {
763
1753
  if (isPlainArray(value)) return "plainArray";
764
1754
  if (isPlainObject(value)) return "plainObject";
765
1755
  return void 0;
766
1756
  };
767
- function diffSnapshots(before, after) {
1757
+ function diffObjects(before, after, handle, dirty, capture) {
768
1758
  const beforeKind = getRootKind(before);
769
1759
  const afterKind = getRootKind(after);
770
- if (beforeKind === void 0 || beforeKind !== afterKind) throw new IncompatibleSnapshotRootsError();
1760
+ if (beforeKind === void 0 || beforeKind !== afterKind) throw new IncompatibleObjectRootsError();
771
1761
  const ops = new Array();
772
- diffValue(before, after, createOperationPath([]), ops, /* @__PURE__ */ new Map());
1762
+ const context = {
1763
+ ops,
1764
+ ancestors: /* @__PURE__ */ new Map(),
1765
+ handle,
1766
+ dirty,
1767
+ capture: capture ?? createCaptureTables()
1768
+ };
1769
+ diffValue(
1770
+ context,
1771
+ before,
1772
+ after,
1773
+ createOperationPath([]),
1774
+ handle === void 0 ? [void 0] : chainsAtRoot(handle.declarations),
1775
+ handle?.proxy.root
1776
+ );
773
1777
  return ops;
774
1778
  }
775
1779
 
776
1780
  // src/emit/emitterDeliver.ts
777
- var deliver = (record, ops, meta) => {
778
- const groupDelivers = [...record.groupListeners?.values() ?? []].flatMap((byChannel) => [...byChannel.values()]);
779
- for (const deliverToListener of groupDelivers) deliverToListener(record.target, ops, meta);
780
- const ownDelivers = [...record.listeners.values()].flatMap((byChannel) => [...byChannel.values()]);
781
- for (const deliverToListener of ownDelivers) deliverToListener(ops, meta);
1781
+ var collectDeliveries = (handle) => {
1782
+ const deliveries = [];
1783
+ for (const groupListeners of handle.groups ?? []) {
1784
+ for (const byChannel of groupListeners.values()) {
1785
+ for (const deliverToListener of byChannel.values()) {
1786
+ deliveries.push({ kind: "group", deliver: deliverToListener });
1787
+ }
1788
+ }
1789
+ }
1790
+ for (const byChannel of handle.subscribers.values()) {
1791
+ for (const deliverToListener of byChannel.values()) {
1792
+ deliveries.push({ kind: "own", deliver: deliverToListener });
1793
+ }
1794
+ }
1795
+ return deliveries;
782
1796
  };
783
-
784
- // src/emit/resolveEmitterTarget.ts
785
- var { proxyStateMap: proxyStateMap3 } = unstable_getInternalStates();
786
- var isObjectLike3 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
787
- function resolveEmitterTarget(state) {
788
- let current = state;
789
- while (isObjectLike3(current)) {
790
- if (proxyStateMap3.has(current)) return current;
791
- const peeled = peelIdentityLayer(current);
792
- if (peeled === void 0) break;
793
- current = peeled;
1797
+ var runDelivery = (pending, failures) => {
1798
+ const handle = handleOf(pending.writeProxy);
1799
+ if (handle !== void 0) handle.lastDirty = pending.dirty;
1800
+ for (const delivery of pending.deliveries) {
1801
+ try {
1802
+ if (delivery.kind === "group") {
1803
+ delivery.deliver(pending.writeProxy, pending.ops, pending.meta, pending.channelId);
1804
+ } else {
1805
+ delivery.deliver(pending.ops, pending.meta, pending.channelId);
1806
+ }
1807
+ } catch (error) {
1808
+ failures.push(error);
1809
+ }
794
1810
  }
795
- if (!isObjectLike3(current) || !proxyStateMap3.has(current)) throw new Error("opshot: expected a state object");
796
- return current;
797
- }
1811
+ };
1812
+ var raiseFailures = (failures) => {
1813
+ if (failures.length === 0) return;
1814
+ if (failures.length > 1) throw new AggregateError(failures, "opshot: listeners failed during delivery");
1815
+ throw failures[0];
1816
+ };
1817
+ var queuedDeliveries = [];
1818
+ var deliveryFailures = [];
1819
+ var isDraining = false;
1820
+ var prepareDelivery = (handle, ops, meta, channelId, dirty) => ({
1821
+ writeProxy: handle.proxy.root,
1822
+ deliveries: collectDeliveries(handle),
1823
+ ops,
1824
+ meta,
1825
+ channelId,
1826
+ dirty
1827
+ });
1828
+ var enqueueDelivery = (pending) => {
1829
+ queuedDeliveries.push(pending);
1830
+ };
1831
+ var drainDeliveries = () => {
1832
+ if (isDraining) return;
1833
+ isDraining = true;
1834
+ let failures = [];
1835
+ try {
1836
+ while (queuedDeliveries.length > 0) {
1837
+ for (const queued of queuedDeliveries.splice(0, queuedDeliveries.length)) {
1838
+ runDelivery(queued, deliveryFailures);
1839
+ }
1840
+ }
1841
+ } finally {
1842
+ isDraining = false;
1843
+ failures = deliveryFailures.splice(0, deliveryFailures.length);
1844
+ }
1845
+ raiseFailures(failures);
1846
+ };
798
1847
 
799
1848
  // src/emit/emitterRegistry.ts
800
- var emitters = /* @__PURE__ */ new WeakMap();
801
- function getEmitter(state) {
802
- return emitters.get(resolveEmitterTarget(state));
803
- }
804
- var hasListeners = (record) => record.listeners.size > 0 || (record.groupListeners?.size ?? 0) > 0;
805
- function getOrCreateEmitter(target, groupListeners) {
806
- const resolved = resolveEmitterTarget(target);
807
- const existing = emitters.get(resolved);
808
- if (existing !== void 0) return existing;
809
- const record = {
810
- listeners: /* @__PURE__ */ new Map(),
811
- groupListeners,
812
- lastReported: snapshot(resolved),
813
- isMutating: false,
814
- target: resolved
1849
+ var { proxyStateMap: proxyStateMap11 } = unstable_getInternalStates();
1850
+ var targetOf = (writeProxy) => proxyStateMap11.get(writeProxy)?.[0] ?? writeProxy;
1851
+
1852
+ // src/emit/emitter.ts
1853
+ function scheduleFlush(handle) {
1854
+ if (handle.isFlushScheduled) return;
1855
+ handle.isFlushScheduled = true;
1856
+ const generation = handle.flushGeneration;
1857
+ const run = () => {
1858
+ if (generation !== handle.flushGeneration) return;
1859
+ handle.isFlushScheduled = false;
1860
+ emitWrites(handle);
815
1861
  };
816
- emitters.set(resolved, record);
817
- return record;
1862
+ void Promise.resolve().then(() => {
1863
+ const emitOn = handle.emitOn;
1864
+ if (emitOn === void 0) {
1865
+ run();
1866
+ return;
1867
+ }
1868
+ emitOn(run);
1869
+ });
818
1870
  }
819
- function deleteEmitter(target) {
820
- emitters.delete(target);
1871
+ function armWatch(handle) {
1872
+ handle.disarmWatch = subscribe(
1873
+ handle.proxy.root,
1874
+ () => {
1875
+ handle.hasPendingWrites = true;
1876
+ if (handle.isFlushHeld) return;
1877
+ scheduleFlush(handle);
1878
+ });
821
1879
  }
822
-
823
- // src/emit/emitterBare.ts
824
- var augmentBareCycleError = (error) => {
825
- const path = getCyclicPath(error);
826
- if (path === void 0) return void 0;
827
- return new Error(
828
- `opshot: a bare write created a cyclic value at ${formatOperationPath(path)}. Cycles cannot be tracked. This surfaced asynchronously because the write was not inside transact. Use transact for catchable cycle errors, ignore() for back-linked structures, or ids.`
829
- );
1880
+ var cloneSnapshotNode = (snap) => {
1881
+ const clone = Array.isArray(snap) ? [] : Object.create(Reflect.getPrototypeOf(snap));
1882
+ for (const key of carriedOwnKeysOf(snap)) {
1883
+ const descriptor = Reflect.getOwnPropertyDescriptor(snap, key);
1884
+ if (descriptor !== void 0) Object.defineProperty(clone, key, descriptor);
1885
+ }
1886
+ if (Array.isArray(snap)) clone.length = snap.length;
1887
+ registerSnapshotCopy(clone, getRegisteredTarget(snap) ?? targetOf(snap));
1888
+ return clone;
830
1889
  };
831
- var requireObjectSnapshot = (value) => {
832
- if (value !== null && (typeof value === "object" || typeof value === "function")) return value;
833
- throw new Error("opshot: state snapshots must have an object root");
1890
+ var reconcileUntracked = (snap, live, seen) => {
1891
+ if (seen.has(live)) return snap;
1892
+ seen.add(live);
1893
+ let result;
1894
+ const written = () => {
1895
+ result ??= cloneSnapshotNode(snap);
1896
+ return result;
1897
+ };
1898
+ for (const key of carriedOwnKeysOf(live)) {
1899
+ const liveValue = Reflect.get(live, key);
1900
+ if (typeof liveValue !== "object" || liveValue === null) continue;
1901
+ if (admissionLane(liveValue) === "untracked") {
1902
+ if (Reflect.get(snap, key) === liveValue) continue;
1903
+ const snapChild2 = Reflect.get(snap, key);
1904
+ if (typeof snapChild2 !== "object" || snapChild2 === null) continue;
1905
+ if (getRegisteredTarget(snapChild2) !== targetOf(liveValue)) continue;
1906
+ const descriptor = Reflect.getOwnPropertyDescriptor(live, key);
1907
+ if (descriptor === void 0 || descriptor.get !== void 0 || descriptor.set !== void 0) continue;
1908
+ Object.defineProperty(written(), key, {
1909
+ value: liveValue,
1910
+ enumerable: descriptor.enumerable,
1911
+ configurable: true
1912
+ });
1913
+ continue;
1914
+ }
1915
+ const snapChild = Reflect.get(snap, key);
1916
+ if (typeof snapChild !== "object" || snapChild === null) continue;
1917
+ const reconciled = reconcileUntracked(snapChild, liveValue, seen);
1918
+ if (reconciled === snapChild) continue;
1919
+ Object.defineProperty(written(), key, {
1920
+ value: reconciled,
1921
+ enumerable: true,
1922
+ configurable: true
1923
+ });
1924
+ }
1925
+ return result ?? snap;
834
1926
  };
835
- var armWatchdog = (record) => {
836
- if (record.disarm !== void 0) return;
837
- record.lastReported = snapshot(record.target);
838
- record.disarm = subscribe(record.target, () => {
839
- emitBareFlush(record.target);
840
- });
1927
+ var captureDiffOf = (handle, from, capture) => {
1928
+ const to = snapshot(handle.proxy.root);
1929
+ const dirty = { edges: /* @__PURE__ */ new WeakMap(), nodes: /* @__PURE__ */ new WeakSet() };
1930
+ if (from === to) {
1931
+ syncHandleTables(handle, capture);
1932
+ return { to, ops: [], dirty, capture };
1933
+ }
1934
+ return {
1935
+ to,
1936
+ ops: diffObjects(reconcileUntracked(from, handle.proxy.root, /* @__PURE__ */ new WeakSet()), to, handle, dirty, capture),
1937
+ dirty,
1938
+ capture
1939
+ };
841
1940
  };
842
- var disarmWatchdog = (record) => {
843
- record.disarm?.();
844
- record.disarm = void 0;
1941
+ var captureRange = (handle, meta, channelId) => {
1942
+ handle.hasPendingWrites = false;
1943
+ const from = handle.lastSnapshot;
1944
+ const capture = handle.transactionCapture ?? createCaptureTables();
1945
+ const committed = captureDiffOf(handle, from, capture);
1946
+ const ops = committed.ops;
1947
+ commitVends(handle, committed.capture);
1948
+ handle.lastSnapshot = committed.to;
1949
+ const evicted = evictDepartedClusters(handle);
1950
+ if (ops.length > 0) annotateDepartureUndos(handle, ops, evicted);
1951
+ if (ops.length > 0 && !handle.replaying) {
1952
+ for (const operation of ops) stampOperation(handle, operation);
1953
+ }
1954
+ return ops.length > 0 ? prepareDelivery(handle, ops, meta, channelId, committed.dirty) : void 0;
845
1955
  };
846
- var reportBareDiff = (record) => {
847
- const current = snapshot(record.target);
848
- if (current === record.lastReported) return;
849
- const previous = record.lastReported;
850
- record.lastReported = current;
851
- if (!hasListeners(record)) return;
852
- try {
853
- const ops = diffSnapshots(requireObjectSnapshot(previous), requireObjectSnapshot(current));
854
- if (ops.length === 0) return;
855
- deliver(record, ops, void 0);
856
- } catch (error) {
857
- throw augmentBareCycleError(error) ?? error;
1956
+ function deliverCapturedRanges(ranges) {
1957
+ for (const captured of ranges) {
1958
+ if (captured !== void 0) enqueueDelivery(captured);
858
1959
  }
1960
+ drainDeliveries();
1961
+ }
1962
+ var emitRange = (handle, meta, channelId) => {
1963
+ const captured = captureRange(handle, meta, channelId);
1964
+ if (captured !== void 0) enqueueDelivery(captured);
1965
+ drainDeliveries();
859
1966
  };
860
- var settlePendingBare = (record) => {
861
- reportBareDiff(record);
1967
+ function captureWrites(handle) {
1968
+ return captureRange(handle, void 0, void 0);
1969
+ }
1970
+ function captureTransactionWrites(handle, meta, channelId) {
1971
+ return captureRange(handle, meta, channelId);
1972
+ }
1973
+ function emitWrites(handle) {
1974
+ emitRange(handle, void 0, void 0);
1975
+ }
1976
+
1977
+ // src/emit/requireObjectSnapshot.ts
1978
+ var ObjectRootSnapshotError = class extends Error {
1979
+ constructor() {
1980
+ super("opshot: state snapshots must have an object root");
1981
+ this.name = "ObjectRootSnapshotError";
1982
+ }
862
1983
  };
863
- function emitBareFlush(target) {
864
- const record = getEmitter(target);
865
- if (record === void 0) return;
866
- reportBareDiff(record);
1984
+ var requireObjectSnapshot = (value) => {
1985
+ if (value !== null && (typeof value === "object" || typeof value === "function")) return value;
1986
+ throw new ObjectRootSnapshotError();
1987
+ };
1988
+
1989
+ // src/ignore.ts
1990
+ var ignoreMarker = /* @__PURE__ */ Symbol("opshot.ignore");
1991
+ function ignore(value) {
1992
+ return { [ignoreMarker]: value };
867
1993
  }
868
- function mintGroupedEmitter(target, groupListeners) {
869
- const record = getOrCreateEmitter(target, groupListeners);
870
- armWatchdog(record);
871
- return record;
1994
+
1995
+ // src/isState.ts
1996
+ var { proxyStateMap: proxyStateMap12 } = unstable_getInternalStates();
1997
+ function isState(value) {
1998
+ const resolved = peelReadProxy(value);
1999
+ if (typeof resolved !== "object" || resolved === null) return false;
2000
+ return proxyStateMap12.has(resolved);
2001
+ }
2002
+
2003
+ // src/unsafeTrack.ts
2004
+ var unsafeMarker = /* @__PURE__ */ Symbol("opshot.unsafe");
2005
+ function unsafeTrack(value) {
2006
+ return { [unsafeMarker]: value };
872
2007
  }
873
2008
 
874
2009
  // src/utils/constructorName.ts
@@ -880,198 +2015,96 @@ var unsafeTrackDataOption = "unsafeTrack(value) to track its data anyway";
880
2015
  var unsafeTrackPrivateOption = "unsafeTrack(value) tracks public fields while private methods throw on snapshots and undo drops that state";
881
2016
  var unsafeTrackSlotOption = "unsafeTrack(value) tracks public fields while slot methods throw on snapshots and undo drops that state";
882
2017
  var unsafeTrackLossyOption = "unsafeTrack(value) to track it lossily";
883
- var boundaryError = (className, reason, options) => new Error(
884
- `opshot: ${className} cannot be tracked (${reason}). Options:
2018
+ var locationClause = (path) => path === void 0 || path.length === 0 ? "" : ` at /${path.join("/")}`;
2019
+ var boundaryError = (className, reason, options, path) => new Error(
2020
+ `opshot: ${className}${locationClause(path)} cannot be tracked (${reason}). Options:
885
2021
  ${options.map((option) => `- ${option}`).join("\n")}`
886
2022
  );
887
- var slotContainerError = (className, trackedName) => boundaryError(className, "its state lives in internal slots", [
888
- `use ${trackedName} for a tracked equivalent`,
889
- unsafeTrackLossyOption,
890
- ignoreOption
891
- ]);
892
- var arraySubclassError = (className) => boundaryError(className, "array subclasses lose their prototype in snapshots", [
893
- unsafeTrackDataOption,
894
- ignoreOption
895
- ]);
896
- var cleanClassError = (className) => boundaryError(className, "arrow-method writes won't be tracked", [unsafeTrackDataOption, ignoreOption]);
897
- var privateClassError = (className) => boundaryError(className, "its state is hidden in private fields", [unsafeTrackPrivateOption, ignoreOption]);
898
- var nativeClassError = (className) => boundaryError(className, "its state is hidden in internal slots", [unsafeTrackSlotOption, ignoreOption]);
2023
+ var slotContainerError = (className, trackedName, path) => boundaryError(
2024
+ className,
2025
+ "its state lives in internal slots",
2026
+ [`use ${trackedName} for a tracked equivalent`, unsafeTrackLossyOption, ignoreOption],
2027
+ path
2028
+ );
2029
+ var arraySubclassError = (className, path) => boundaryError(
2030
+ className,
2031
+ "array subclasses lose their prototype in snapshots",
2032
+ [unsafeTrackDataOption, ignoreOption],
2033
+ path
2034
+ );
2035
+ var cleanClassError = (className, path) => boundaryError(className, "arrow-method writes won't be tracked", [unsafeTrackDataOption, ignoreOption], path);
2036
+ var privateClassError = (className, path) => boundaryError(className, "its state is hidden in private fields", [unsafeTrackPrivateOption, ignoreOption], path);
2037
+ var nativeClassError = (className, path) => boundaryError(className, "its state is hidden in internal slots", [unsafeTrackSlotOption, ignoreOption], path);
2038
+ var nonWritablePropertyError = (value, path) => boundaryError(
2039
+ constructorName(value.constructor),
2040
+ "a non-writable property's interior is silently mutable and untracked",
2041
+ ["make the property writable", "ignore(value) to declare the escape"],
2042
+ path
2043
+ );
899
2044
  var snapshotDonationError = (key) => new Error(
900
- `opshot: cannot assign a snapshot generation at "${String(key)}": a snapshot generation is a read-view, and assigning it creates a dead region. Clone the value, or replay through applyOps.`
2045
+ `opshot: cannot assign a snapshot generation at "${String(key)}": a snapshot generation is a read-view, and assigning it creates a dead region. Clone the value, or replay through applyOperations.`
901
2046
  );
902
- var reservedDataPathError = (path) => new Error(`opshot: reserved data path /${path.join("/")}`);
903
2047
  var inheritsFromPrototype = (value, prototype) => {
904
2048
  for (let current = Reflect.getPrototypeOf(value); current !== null; current = Reflect.getPrototypeOf(current))
905
2049
  if (current === prototype) return true;
906
2050
  return false;
907
2051
  };
908
- var rejectionError = (value, kind) => {
2052
+ var rejectionError = (value, kind, path) => {
909
2053
  const className = constructorName(value.constructor);
910
- if (inheritsFromPrototype(value, Map.prototype)) return slotContainerError(className, "TrackedMap");
911
- if (inheritsFromPrototype(value, Set.prototype)) return slotContainerError(className, "TrackedSet");
912
- if (inheritsFromPrototype(value, Date.prototype)) return slotContainerError(className, "TrackedDate");
2054
+ if (inheritsFromPrototype(value, Map.prototype)) return slotContainerError(className, "TrackedMap", path);
2055
+ if (inheritsFromPrototype(value, Set.prototype)) return slotContainerError(className, "TrackedSet", path);
2056
+ if (inheritsFromPrototype(value, Date.prototype)) return slotContainerError(className, "TrackedDate", path);
913
2057
  switch (kind) {
914
2058
  case "arraySubclass":
915
- return arraySubclassError(className);
2059
+ return arraySubclassError(className, path);
916
2060
  case "cleanClass":
917
- return cleanClassError(className);
2061
+ return cleanClassError(className, path);
918
2062
  case "privateClass":
919
- return privateClassError(className);
2063
+ return privateClassError(className, path);
920
2064
  case "nativeClass":
921
- return nativeClassError(className);
2065
+ return nativeClassError(className, path);
922
2066
  }
923
2067
  };
924
2068
 
925
- // src/valtio/constructorPathGuard.ts
926
- var { refSet: refSet4 } = unstable_getInternalStates();
927
- var constructorPathTargetCounts = /* @__PURE__ */ new WeakMap();
928
- var rootGraphsByRoot = /* @__PURE__ */ new WeakMap();
929
- var rootGraphReferences = /* @__PURE__ */ new WeakMap();
930
- var rootGraphsByTarget = /* @__PURE__ */ new WeakMap();
931
- var getRawObject = (value) => {
932
- const resolved = resolveIdentity(value);
933
- return typeof resolved === "object" && resolved !== null ? resolved : void 0;
934
- };
935
- var getTrackedRawObject = (value) => {
936
- const target = getRawObject(value);
937
- if (!target || refSet4.has(target) || Object.isFrozen(target)) return void 0;
938
- return isTrackable(target) ? target : void 0;
939
- };
940
- var getEnumerableDataChild = (target, key) => {
941
- if (typeof key !== "string") return void 0;
942
- const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
943
- if (!descriptor?.enumerable || !("value" in descriptor)) return void 0;
944
- return getTrackedRawObject(descriptor.value);
945
- };
946
- var adjustConstructorPathTarget = (target, change) => {
947
- const next = (constructorPathTargetCounts.get(target) ?? 0) + change;
948
- if (next > 0) constructorPathTargetCounts.set(target, next);
949
- else constructorPathTargetCounts.delete(target);
950
- };
951
- var constructorPathTargetCount = (target) => constructorPathTargetCounts.get(target) ?? 0;
952
- var releaseFinalizationState = (state) => {
953
- if (!state.active) return;
954
- state.active = false;
955
- for (const { target, count } of state.constructorTargets) {
956
- const resolved = target.deref();
957
- if (resolved) adjustConstructorPathTarget(resolved, -count);
958
- }
959
- state.constructorTargets = [];
960
- };
961
- var rootGraphFinalizer = new FinalizationRegistry(releaseFinalizationState);
962
- var getRootGraphReference = (graph) => {
963
- const existing = rootGraphReferences.get(graph);
964
- if (existing) return existing;
965
- const reference = new WeakRef(graph);
966
- rootGraphReferences.set(graph, reference);
967
- return reference;
968
- };
969
- var releaseRootGraph = (graph) => {
970
- const reference = getRootGraphReference(graph);
971
- for (const target of graph.targets) {
972
- const references = rootGraphsByTarget.get(target);
973
- references?.delete(reference);
974
- if (references?.size === 0) rootGraphsByTarget.delete(target);
975
- }
976
- const root = graph.root.deref();
977
- if (root) rootGraphsByRoot.delete(root);
978
- releaseFinalizationState(graph.finalizationState);
979
- rootGraphFinalizer.unregister(graph.finalizationState);
980
- graph.targets.clear();
981
- graph.constructorTargets.clear();
982
- };
983
- var getRootGraphs = (target) => {
984
- const references = rootGraphsByTarget.get(target);
985
- if (!references) return [];
986
- const graphs = new Array();
987
- for (const reference of references) {
988
- const graph = reference.deref();
989
- if (!graph) {
990
- references.delete(reference);
991
- continue;
992
- }
993
- if (!graph.root.deref()) {
994
- releaseRootGraph(graph);
995
- continue;
996
- }
997
- graphs.push(graph);
998
- }
999
- if (references.size === 0) rootGraphsByTarget.delete(target);
1000
- return graphs;
1001
- };
1002
- var recomputeRootGraph = (graph) => {
1003
- const root = graph.root.deref();
1004
- if (!root) {
1005
- releaseRootGraph(graph);
1006
- return;
2069
+ // src/valtio/snapshotAccessors.ts
2070
+ var { proxyStateMap: proxyStateMap13, snapCache: snapCache2 } = unstable_getInternalStates();
2071
+ var MissingOwnDescriptorError2 = class extends Error {
2072
+ constructor() {
2073
+ super("opshot: carried own key has no property descriptor");
2074
+ this.name = "MissingOwnDescriptorError";
1007
2075
  }
1008
- const targets = /* @__PURE__ */ new Set();
1009
- const constructorTargets = /* @__PURE__ */ new Map();
1010
- const visit = (target) => {
1011
- if (targets.has(target)) return;
1012
- targets.add(target);
1013
- const constructorTarget = getEnumerableDataChild(target, "constructor");
1014
- if (constructorTarget)
1015
- constructorTargets.set(constructorTarget, (constructorTargets.get(constructorTarget) ?? 0) + 1);
1016
- for (const key of Object.keys(target)) {
1017
- const child = getEnumerableDataChild(target, key);
1018
- if (child) visit(child);
1019
- }
1020
- };
1021
- visit(root);
1022
- for (const [target, count] of graph.constructorTargets) adjustConstructorPathTarget(target, -count);
1023
- for (const [target, count] of constructorTargets) adjustConstructorPathTarget(target, count);
1024
- for (const target of graph.targets) {
1025
- if (targets.has(target)) continue;
1026
- const references = rootGraphsByTarget.get(target);
1027
- references?.delete(getRootGraphReference(graph));
1028
- if (references?.size === 0) rootGraphsByTarget.delete(target);
1029
- }
1030
- for (const target of targets) {
1031
- if (graph.targets.has(target)) continue;
1032
- const references = rootGraphsByTarget.get(target) ?? /* @__PURE__ */ new Set();
1033
- references.add(getRootGraphReference(graph));
1034
- rootGraphsByTarget.set(target, references);
1035
- }
1036
- graph.targets = targets;
1037
- graph.constructorTargets = constructorTargets;
1038
- graph.finalizationState.constructorTargets = [...constructorTargets].map(([target, count]) => ({
1039
- target: new WeakRef(target),
1040
- count
1041
- }));
1042
- };
1043
- var registerTrackedRoot = (value) => {
1044
- const root = getTrackedRawObject(value);
1045
- if (!root || rootGraphsByRoot.has(root)) return;
1046
- const finalizationState = { active: true, constructorTargets: [] };
1047
- const graph = {
1048
- root: new WeakRef(root),
1049
- finalizationState,
1050
- targets: /* @__PURE__ */ new Set(),
1051
- constructorTargets: /* @__PURE__ */ new Map()
1052
- };
1053
- rootGraphsByRoot.set(root, graph);
1054
- rootGraphFinalizer.register(root, finalizationState, finalizationState);
1055
- recomputeRootGraph(graph);
1056
2076
  };
1057
-
1058
- // src/valtio/snapshotAccessors.ts
1059
- var { refSet: refSet5, proxyStateMap: proxyStateMap4, snapCache: snapCache2 } = unstable_getInternalStates();
1060
2077
  var createSnapshotPreservingAccessors = (target, version) => {
1061
2078
  const cached = snapCache2.get(target);
1062
2079
  if (cached?.[0] === version) {
1063
2080
  const cachedSnapshot = cached[1];
1064
- registerSnapshotCopy(cachedSnapshot, target);
2081
+ for (const key of carriedOwnKeysOf(target)) {
2082
+ const value = Reflect.get(target, key);
2083
+ if (typeof value !== "object" || value === null) continue;
2084
+ if (admissionLane(value) !== "untracked") continue;
2085
+ if (Reflect.get(cachedSnapshot, key) === value) continue;
2086
+ const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
2087
+ if (descriptor === void 0 || descriptor.get !== void 0 || descriptor.set !== void 0) continue;
2088
+ Object.defineProperty(cachedSnapshot, key, {
2089
+ value,
2090
+ enumerable: descriptor.enumerable,
2091
+ configurable: true
2092
+ });
2093
+ markToTrack(value, false);
2094
+ }
2095
+ if (getRegisteredTarget(cachedSnapshot) === void 0) {
2096
+ registerSnapshotCopy(cachedSnapshot, target);
2097
+ }
1065
2098
  return cachedSnapshot;
1066
2099
  }
1067
2100
  const snap = Array.isArray(target) ? [] : Object.create(Reflect.getPrototypeOf(target));
1068
2101
  registerSnapshotCopy(snap, target);
1069
2102
  markToTrack(snap, true);
1070
2103
  snapCache2.set(target, [version, snap]);
1071
- for (const key of Reflect.ownKeys(target)) {
2104
+ for (const key of carriedOwnKeysOf(target)) {
1072
2105
  if (Object.getOwnPropertyDescriptor(snap, key)) continue;
1073
2106
  const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
1074
- if (!descriptor) continue;
2107
+ if (descriptor === void 0) throw new MissingOwnDescriptorError2();
1075
2108
  if (descriptor.get || descriptor.set) {
1076
2109
  Object.defineProperty(snap, key, {
1077
2110
  get: descriptor.get,
@@ -1084,10 +2117,10 @@ var createSnapshotPreservingAccessors = (target, version) => {
1084
2117
  const value = Reflect.get(target, key);
1085
2118
  const snapshotDescriptor = { value, enumerable: descriptor.enumerable, configurable: true };
1086
2119
  if (typeof value === "object" && value !== null) {
1087
- if (refSet5.has(value)) {
2120
+ if (admissionLane(value) === "untracked") {
1088
2121
  markToTrack(value, false);
1089
2122
  } else {
1090
- const childState = proxyStateMap4.get(value);
2123
+ const childState = proxyStateMap13.get(value);
1091
2124
  if (childState)
1092
2125
  snapshotDescriptor.value = createSnapshotPreservingAccessors(childState[0], childState[1]());
1093
2126
  }
@@ -1097,96 +2130,320 @@ var createSnapshotPreservingAccessors = (target, version) => {
1097
2130
  if (Array.isArray(target) && snap.length !== target.length) {
1098
2131
  snap.length = target.length;
1099
2132
  }
1100
- if (isUnsafeTracked(target)) unsafeTrack(snap);
1101
2133
  return snap;
1102
2134
  };
1103
2135
 
1104
2136
  // src/valtio/boundary.ts
1105
- var assertSafeDataPaths = (value, path = new Array(), activeAncestors = /* @__PURE__ */ new WeakSet()) => {
1106
- if (typeof value !== "object" || value === null || activeAncestors.has(value)) return;
1107
- activeAncestors.add(value);
1108
- try {
1109
- for (const key of Object.keys(value)) {
1110
- const nextPath = [...path, key];
1111
- if (key === "__proto__" || key === "prototype" && path[path.length - 1] === "constructor")
1112
- throw reservedDataPathError(nextPath);
1113
- const descriptor = Reflect.getOwnPropertyDescriptor(value, key);
1114
- if (descriptor && "value" in descriptor) assertSafeDataPaths(descriptor.value, nextPath, activeAncestors);
2137
+ var { proxyStateMap: proxyStateMap14, proxyCache: proxyCache3 } = unstable_getInternalStates();
2138
+ var rawTargetOf7 = (value) => proxyStateMap14.get(value)?.[0] ?? value;
2139
+ var handleOwning = (target) => {
2140
+ const handles = handlesOf(target);
2141
+ const raw = rawTargetOf7(target);
2142
+ for (const handle of handles) {
2143
+ if (rawTargetOf7(handle.proxy.root) === raw) return handle;
2144
+ }
2145
+ return handles[0];
2146
+ };
2147
+ var segmentForProp = (parent, prop) => isPlainArray(parent) && isCanonicalArrayIndexString(prop) ? Number(prop) : prop;
2148
+ var setFrameStack = new Array();
2149
+ var currentSetParentOf = () => setFrameStack[setFrameStack.length - 1]?.target;
2150
+ var currentStatuses = () => setFrameStack[setFrameStack.length - 1]?.statuses;
2151
+ var heldStatusesOf = (target, prop) => {
2152
+ const key = segmentForProp(target, prop);
2153
+ const statuses = new Array();
2154
+ for (const handle of handlesOf(target)) {
2155
+ const slot = slotStatusOf(handle, target, key);
2156
+ if (!slot.occupied) continue;
2157
+ statuses.push({ handle, ignored: slot.ignored, unsafe: slot.unsafe, chains: slot.chains });
2158
+ }
2159
+ return statuses.length === 0 ? void 0 : statuses;
2160
+ };
2161
+ var inheritedStatusesOf = (target, prop) => {
2162
+ const parent = setFrameStack[setFrameStack.length - 1];
2163
+ if (parent?.statuses === void 0) return void 0;
2164
+ const key = segmentForProp(target, prop);
2165
+ return parent.statuses.map((status) => {
2166
+ const descended = descendChains(status.chains, key);
2167
+ return {
2168
+ handle: status.handle,
2169
+ ignored: status.ignored || descended.ignored,
2170
+ unsafe: status.unsafe || descended.unsafe,
2171
+ chains: descended.chains
2172
+ };
2173
+ });
2174
+ };
2175
+ var statusesForFrame = (target, prop, initializing) => {
2176
+ if (typeof prop !== "string") return void 0;
2177
+ if (!initializing) return heldStatusesOf(target, prop);
2178
+ return inheritedStatusesOf(target, prop) ?? heldStatusesOf(target, prop);
2179
+ };
2180
+ var certifyAdmission = (value, path, unsafe = false) => {
2181
+ const decision = admissionDecision(value);
2182
+ if (decision.lane === "dangerous" && !unsafe) throw rejectionError(value, decision.kind, path);
2183
+ return decision.lane;
2184
+ };
2185
+ var peelSnapshotsAndReadProxies = (value) => {
2186
+ let current = value;
2187
+ while (typeof current === "object" && current !== null) {
2188
+ const untracked = getUntracked(current);
2189
+ const next = peelReadProxy(untracked ?? current);
2190
+ if (next === current) break;
2191
+ current = next;
2192
+ }
2193
+ return current;
2194
+ };
2195
+ var walkDataPaths = (value, path, visits, mode, chains, ignored, unsafe) => {
2196
+ const node = mode === "admission" ? rawTargetOf7(value) : value;
2197
+ if (visits.has(node)) return;
2198
+ visits.add(node);
2199
+ if (ignored) return;
2200
+ for (const entry of walkDataEntries(node)) {
2201
+ const childPath = [...path, entry.key];
2202
+ const descended = descendChains(chains, segmentForProp(node, entry.key));
2203
+ const childIgnored = descended.ignored;
2204
+ const childUnsafe = unsafe || descended.unsafe;
2205
+ const childChains = descended.chains;
2206
+ const child = entry.value;
2207
+ if (mode === "admission" && classifyValue(node) === "cleanClass" && !unsafe && typeof child === "function")
2208
+ throw rejectionError(node, "cleanClass", childPath);
2209
+ if (typeof child !== "object" || child === null) continue;
2210
+ if (!entry.writable) {
2211
+ if (mode === "admission" && !childIgnored && !childUnsafe && admissionLane(child) !== "untracked")
2212
+ throw nonWritablePropertyError(child, childPath);
2213
+ continue;
1115
2214
  }
1116
- } finally {
1117
- activeAncestors.delete(value);
2215
+ if (childIgnored) continue;
2216
+ let childNode = child;
2217
+ if (proxyStateMap14.has(childNode)) {
2218
+ if (mode !== "admission") continue;
2219
+ childNode = rawTargetOf7(childNode);
2220
+ }
2221
+ if (mode === "admission") {
2222
+ if (childUnsafe) {
2223
+ walkDataPaths(childNode, childPath, visits, mode, childChains, childIgnored, childUnsafe);
2224
+ continue;
2225
+ }
2226
+ if (certifyAdmission(childNode, childPath, childUnsafe) === "tracked")
2227
+ walkDataPaths(childNode, childPath, visits, mode, childChains, childIgnored, childUnsafe);
2228
+ continue;
2229
+ }
2230
+ if (admissionLane(childNode) === "untracked") continue;
2231
+ walkDataPaths(childNode, childPath, visits, mode, childChains, childIgnored, childUnsafe);
1118
2232
  }
1119
2233
  };
2234
+ var assertSafeDataPaths = (value, path, visits, mode = "admission", chains = []) => {
2235
+ walkDataPaths(
2236
+ value,
2237
+ path,
2238
+ visits,
2239
+ mode,
2240
+ chains,
2241
+ chains.some((residual) => residual?.ignored === true),
2242
+ chains.some((residual) => residual?.unsafe === true)
2243
+ );
2244
+ };
2245
+ var certifyCurrentAssignment = (target, prop, resolved) => {
2246
+ if (typeof prop !== "string") return;
2247
+ const assignments = currentStatuses();
2248
+ if (assignments === void 0) return;
2249
+ const path = [prop];
2250
+ for (const assignment of assignments) {
2251
+ if (!assignment.handle.strict || assignment.ignored || assignment.unsafe) continue;
2252
+ if (typeof resolved === "function") {
2253
+ const parentKind = classifyValue(rawTargetOf7(target));
2254
+ if (parentKind !== "plain" && parentKind !== "plainArray")
2255
+ throw rejectionError(rawTargetOf7(target), parentKind, path);
2256
+ continue;
2257
+ }
2258
+ const decision = admissionDecision(resolved);
2259
+ if (decision.lane === "dangerous") throw rejectionError(resolved, decision.kind, path);
2260
+ if (decision.lane === "tracked")
2261
+ walkDataPaths(
2262
+ resolved,
2263
+ path,
2264
+ /* @__PURE__ */ new Set(),
2265
+ "admission",
2266
+ assignment.chains,
2267
+ assignment.ignored,
2268
+ assignment.unsafe
2269
+ );
2270
+ }
2271
+ };
2272
+ var writesThroughAccessor = (target, property) => {
2273
+ let holder = target;
2274
+ while (holder !== null) {
2275
+ const descriptor = Reflect.getOwnPropertyDescriptor(holder, property);
2276
+ if (descriptor !== void 0) return !("value" in descriptor);
2277
+ holder = Reflect.getPrototypeOf(holder);
2278
+ }
2279
+ return false;
2280
+ };
2281
+ var refusesWrite = (target, property, value) => {
2282
+ if (Array.isArray(target)) {
2283
+ if (property === "length") {
2284
+ const coercible = value === null || typeof value !== "object" && typeof value !== "function";
2285
+ const newLength = coercible ? Number(value) : Number.NaN;
2286
+ if (Number.isInteger(newLength) && newLength >= 0 && newLength < target.length) {
2287
+ for (const key of Reflect.ownKeys(target)) {
2288
+ if (typeof key !== "string") continue;
2289
+ const index = Number(key);
2290
+ if (Number.isInteger(index) && index >= newLength && index < 2 ** 32 - 1 && String(index) === key && Reflect.getOwnPropertyDescriptor(target, key)?.configurable !== true)
2291
+ return true;
2292
+ }
2293
+ }
2294
+ } else if (typeof property === "string") {
2295
+ const index = Number(property);
2296
+ if (Number.isInteger(index) && index >= 0 && index < 2 ** 32 - 1 && String(index) === property && index >= target.length && Reflect.getOwnPropertyDescriptor(target, "length")?.writable === false)
2297
+ return true;
2298
+ }
2299
+ }
2300
+ let holder = target;
2301
+ while (holder !== null) {
2302
+ const descriptor = Reflect.getOwnPropertyDescriptor(holder, property);
2303
+ if (descriptor !== void 0) {
2304
+ if ("value" in descriptor) {
2305
+ if (descriptor.writable !== true) return true;
2306
+ return holder !== target && !Object.isExtensible(target);
2307
+ }
2308
+ return descriptor.set === void 0;
2309
+ }
2310
+ holder = Reflect.getPrototypeOf(holder);
2311
+ }
2312
+ return !Object.isExtensible(target);
2313
+ };
2314
+ function canProxy2(value, parentTarget, unsafe = false) {
2315
+ if (typeof value !== "object" || value === null) return false;
2316
+ if (admissionLane(value) === "tracked") return true;
2317
+ if (unsafe) return true;
2318
+ if (proxyStateMap14.has(value)) return true;
2319
+ const rootHandle = handleOwning(value);
2320
+ if (rootHandle !== void 0 && rawTargetOf7(rootHandle.proxy.root) === rawTargetOf7(value) && (!rootHandle.strict || rootHandle.declarations?.unsafe === true))
2321
+ return true;
2322
+ if (parentTarget === void 0) return false;
2323
+ const handles = handlesOf(parentTarget);
2324
+ return handles.length === 1 && handles[0]?.strict === false && admissionLane(value) === "dangerous";
2325
+ }
2326
+ var MissingMutationTrapError = class extends Error {
2327
+ constructor() {
2328
+ super("opshot: valtio default handler is missing a mutation trap");
2329
+ this.name = "MissingMutationTrapError";
2330
+ }
2331
+ };
2332
+ var canProxyCurrentAssignment = (value) => {
2333
+ const assignments = currentStatuses();
2334
+ if (assignments === void 0) return canProxy2(value, currentSetParentOf());
2335
+ const judging = assignments.filter((assignment) => !assignment.ignored);
2336
+ if (judging.length === 0) return false;
2337
+ return canProxy2(
2338
+ value,
2339
+ currentSetParentOf(),
2340
+ judging.every((assignment) => assignment.unsafe || !assignment.handle.strict)
2341
+ );
2342
+ };
2343
+ var truncatedOccupantsOf = (target, prop, next) => {
2344
+ if (!Array.isArray(target) || prop !== "length") return void 0;
2345
+ const coercible = next === null || typeof next !== "object" && typeof next !== "function";
2346
+ const newLength = coercible ? Number(next) : Number.NaN;
2347
+ if (!Number.isInteger(newLength) || newLength < 0 || newLength >= target.length) return void 0;
2348
+ const truncated = new Array();
2349
+ for (let index = newLength; index < target.length; index++) {
2350
+ const occupant = Reflect.get(target, index);
2351
+ if (typeof occupant === "object" && occupant !== null) truncated.push({ index, occupant });
2352
+ }
2353
+ return truncated;
2354
+ };
2355
+ var commitSetInEdges = (target, prop, previous, next, truncated) => {
2356
+ const handles = handlesOf(target);
2357
+ if (handles.length === 0) return;
2358
+ if (truncated !== void 0) {
2359
+ for (const { index, occupant } of truncated) {
2360
+ for (const handle of handles) removeInEdge(handle, occupant, target, index);
2361
+ }
2362
+ return;
2363
+ }
2364
+ if (typeof prop !== "string") return;
2365
+ const key = segmentForProp(target, prop);
2366
+ const previousObject = typeof previous === "object" && previous !== null ? previous : void 0;
2367
+ const nextObject = typeof next === "object" && next !== null && admissionLane(next) !== "untracked" ? next : void 0;
2368
+ for (const handle of handles) {
2369
+ if (isIgnoredFrontier(handle, target, key)) {
2370
+ if (previousObject !== void 0) removeInEdge(handle, previousObject, target, key);
2371
+ continue;
2372
+ }
2373
+ if (previousObject !== void 0) removeInEdge(handle, previousObject, target, key);
2374
+ if (nextObject === void 0) continue;
2375
+ const rawNext = rawTargetOf7(nextObject);
2376
+ const wasOccupied = rawNext === rawTargetOf7(handle.proxy.root) || (handle.nodes.get(rawNext)?.edges.length ?? 0) > 0;
2377
+ addInEdge(handle, nextObject, target, key);
2378
+ if (wasOccupied) continue;
2379
+ const slot = slotStatusOf(handle, target, key);
2380
+ seedInEdgesUnder(handle, nextObject, slot.chains);
2381
+ }
2382
+ };
2383
+ var commitDeleteInEdges = (target, prop, previous) => {
2384
+ if (typeof prop !== "string") return;
2385
+ if (typeof previous !== "object" || previous === null) return;
2386
+ const key = segmentForProp(target, prop);
2387
+ for (const handle of handlesOf(target)) removeInEdge(handle, previous, target, key);
2388
+ };
1120
2389
  var installed = false;
1121
2390
  function installBoundary() {
1122
2391
  if (installed) return;
1123
2392
  installed = true;
1124
- unstable_replaceInternalFunction("canProxy", () => (value) => {
1125
- if (typeof value !== "object" || value === null) return false;
1126
- const lane = admissionLane(value);
1127
- if (lane !== "reject") return lane === "track";
1128
- const kind = classifyValue(value);
1129
- if (kind === "plain" || kind === "plainArray") return true;
1130
- throw rejectionError(value, kind);
1131
- });
2393
+ unstable_replaceInternalFunction("canProxy", () => (value) => canProxyCurrentAssignment(value));
1132
2394
  unstable_replaceInternalFunction("createSnapshot", () => createSnapshotPreservingAccessors);
1133
2395
  unstable_replaceInternalFunction(
1134
2396
  "createHandler",
1135
2397
  (createHandler2) => (isInitializing, addPropListener, removePropListener, notifyUpdate) => {
1136
- let setDepth = 0;
1137
2398
  const handler = createHandler2(isInitializing, addPropListener, removePropListener, notifyUpdate);
1138
2399
  const defaultDelete = handler.deleteProperty;
1139
2400
  const defaultSet = handler.set;
1140
- if (!defaultDelete || !defaultSet)
1141
- throw new Error("opshot: valtio default handler is missing a mutation trap");
2401
+ if (!defaultDelete || !defaultSet) throw new MissingMutationTrapError();
1142
2402
  return {
1143
2403
  ...handler,
1144
- deleteProperty(target, prop) {
1145
- const rootGraphs = getRootGraphs(target);
1146
- const previousChild = rootGraphs.length > 0 ? getEnumerableDataChild(target, prop) : void 0;
1147
- const hadOwn = Object.hasOwn(target, prop);
1148
- const deleted = defaultDelete(target, prop);
1149
- if (deleted && hadOwn && previousChild && !Object.hasOwn(target, prop))
1150
- for (const graph of rootGraphs) recomputeRootGraph(graph);
1151
- return deleted;
1152
- },
1153
2404
  set(target, prop, value, receiver) {
1154
2405
  const assigned = value;
1155
- if (prop === "__proto__") throw reservedDataPathError(["__proto__"]);
1156
- if (prop === "prototype" && constructorPathTargetCount(target) > 0)
1157
- throw reservedDataPathError(["constructor", "prototype"]);
1158
- if (prop === "constructor" && typeof assigned === "object" && assigned !== null) {
1159
- const prototypeDescriptor = Reflect.getOwnPropertyDescriptor(assigned, "prototype");
1160
- if (prototypeDescriptor?.enumerable) throw reservedDataPathError(["constructor", "prototype"]);
1161
- }
1162
- assertSafeDataPaths(assigned, typeof prop === "string" ? [prop] : []);
1163
- if (typeof assigned === "object" && assigned !== null) {
1164
- const untracked = getUntracked(assigned) ?? assigned;
1165
- if (getRegisteredTarget(untracked) !== void 0) throw snapshotDonationError(prop);
1166
- }
1167
- const rootGraphs = getRootGraphs(target);
1168
- const previousChild = rootGraphs.length > 0 ? getEnumerableDataChild(target, prop) : void 0;
1169
- const previousLength = rootGraphs.length > 0 && Array.isArray(target) && prop === "length" ? Reflect.get(target, "length") : void 0;
1170
- setDepth += 1;
2406
+ const resolved = peelSnapshotsAndReadProxies(assigned);
2407
+ const truncated = truncatedOccupantsOf(target, prop, resolved);
2408
+ const previous = typeof prop === "string" ? Reflect.get(target, prop) : void 0;
2409
+ const initializing = isInitializing();
2410
+ setFrameStack.push({ target, prop, statuses: statusesForFrame(target, prop, initializing) });
1171
2411
  try {
1172
- const written = defaultSet(target, prop, value, receiver);
1173
- const currentChild = rootGraphs.length > 0 ? getEnumerableDataChild(target, prop) : void 0;
1174
- const currentLength = previousLength === void 0 ? void 0 : Reflect.get(target, "length");
1175
- if (previousChild !== currentChild || previousLength !== currentLength)
1176
- for (const graph of rootGraphs) recomputeRootGraph(graph);
1177
- return written;
2412
+ if (typeof resolved === "object" && resolved !== null) {
2413
+ if (getRegisteredTarget(resolved) !== void 0) throw snapshotDonationError(prop);
2414
+ if (refusesWrite(target, prop, resolved)) return false;
2415
+ if (!initializing && !writesThroughAccessor(target, prop))
2416
+ certifyCurrentAssignment(target, prop, resolved);
2417
+ const alreadyTracked = proxyStateMap14.has(resolved) || proxyCache3.has(resolved);
2418
+ const instrumented = !alreadyTracked && canProxyCurrentAssignment(resolved) ? proxy(resolved) : resolved;
2419
+ const result2 = defaultSet(target, prop, instrumented, receiver);
2420
+ if (result2 && !initializing) commitSetInEdges(target, prop, previous, instrumented, truncated);
2421
+ return result2;
2422
+ }
2423
+ if (refusesWrite(target, prop, resolved)) return false;
2424
+ if (!initializing && typeof resolved === "function" && !writesThroughAccessor(target, prop))
2425
+ certifyCurrentAssignment(target, prop, resolved);
2426
+ const result = defaultSet(target, prop, resolved, receiver);
2427
+ if (result && !initializing) commitSetInEdges(target, prop, previous, resolved, truncated);
2428
+ return result;
1178
2429
  } finally {
1179
- setDepth -= 1;
2430
+ setFrameStack.pop();
1180
2431
  }
1181
2432
  },
2433
+ deleteProperty(target, prop) {
2434
+ const previous = typeof prop === "string" ? Reflect.get(target, prop) : void 0;
2435
+ const result = defaultDelete(target, prop);
2436
+ if (result && !isInitializing()) commitDeleteInEdges(target, prop, previous);
2437
+ return result;
2438
+ },
1182
2439
  defineProperty(target, prop, descriptor) {
1183
- if (setDepth > 0 || isInitializing()) return Reflect.defineProperty(target, prop, descriptor);
1184
- throw new Error(
1185
- "opshot: defineProperty is not supported on tracked state; define properties in the createMutableState input"
1186
- );
2440
+ return Reflect.defineProperty(target, prop, descriptor);
1187
2441
  },
1188
- setPrototypeOf() {
1189
- throw new Error("opshot: setPrototypeOf is not supported on tracked state");
2442
+ setPrototypeOf(target, proto) {
2443
+ return Reflect.setPrototypeOf(target, proto);
2444
+ },
2445
+ preventExtensions(target) {
2446
+ return Reflect.preventExtensions(target);
1190
2447
  }
1191
2448
  };
1192
2449
  }
@@ -1194,180 +2451,299 @@ function installBoundary() {
1194
2451
  }
1195
2452
 
1196
2453
  // src/createMutableState.ts
1197
- function createMutableState(properties, group) {
2454
+ var isIgnoredWrapper = (value) => typeof value === "object" && value !== null && Object.hasOwn(value, ignoreMarker);
2455
+ var isUnsafeWrapper = (value) => typeof value === "object" && value !== null && Object.hasOwn(value, unsafeMarker);
2456
+ var consumeMarkerTree = (node, path, walk) => {
2457
+ if (Object.isFrozen(node)) return;
2458
+ const firstPath = walk.firstOccupancyByNode.get(node);
2459
+ if (firstPath !== void 0) {
2460
+ const laterOccupancies = walk.laterOccupanciesByNode.get(node);
2461
+ if (laterOccupancies === void 0) walk.laterOccupanciesByNode.set(node, [path]);
2462
+ else laterOccupancies.push(path);
2463
+ return;
2464
+ }
2465
+ walk.firstOccupancyByNode.set(node, path);
2466
+ for (const entry of walkDataEntries(node)) {
2467
+ const childPath = appendOperationPath(path, segmentFor(node, entry.key));
2468
+ const next = unwrapValue(entry.value, childPath, walk);
2469
+ if (!Object.is(next, entry.value) && entry.writable) Reflect.set(node, entry.key, next);
2470
+ }
2471
+ };
2472
+ var unwrapValue = (value, path, walk) => {
2473
+ let current = value;
2474
+ while (isIgnoredWrapper(current) || isUnsafeWrapper(current)) {
2475
+ const node = declarationAtPath(walk.trie, path);
2476
+ walk.marked = true;
2477
+ if (isIgnoredWrapper(current)) {
2478
+ node.ignored = true;
2479
+ current = current[ignoreMarker];
2480
+ } else {
2481
+ node.unsafe = true;
2482
+ current = current[unsafeMarker];
2483
+ }
2484
+ }
2485
+ if (typeof current === "object" && current !== null) consumeMarkerTree(current, path, walk);
2486
+ return current;
2487
+ };
2488
+ var trieAtPath = (trie, path) => {
2489
+ let current = trie;
2490
+ for (const segment of path) {
2491
+ current = current.children.get(String(segment));
2492
+ if (current === void 0) return void 0;
2493
+ }
2494
+ return current;
2495
+ };
2496
+ var applyCopiedMarkerPaths = (walk) => {
2497
+ for (const [node, firstPath] of walk.firstOccupancyByNode) {
2498
+ const laterOccupancies = walk.laterOccupanciesByNode.get(node);
2499
+ if (laterOccupancies === void 0) continue;
2500
+ const source = trieAtPath(walk.trie, firstPath);
2501
+ if (source === void 0 || source.children.size === 0) continue;
2502
+ for (const laterPath of laterOccupancies) {
2503
+ graftDeclarationChildren(source, declarationAtPath(walk.trie, laterPath));
2504
+ }
2505
+ }
2506
+ };
2507
+ function createMutableState(properties, options) {
1198
2508
  installBoundary();
1199
- assertSafeDataPaths(properties);
1200
- const base = Object.create(Reflect.getPrototypeOf(properties));
1201
- Object.defineProperties(base, Object.getOwnPropertyDescriptors(properties));
1202
- const proxied = proxy(base);
1203
- registerTrackedRoot(base);
1204
- if (group !== void 0) {
1205
- mintGroupedEmitter(proxied, getGroupListeners(group));
2509
+ const trie = createDeclarationTrie();
2510
+ let marked = false;
2511
+ let root = properties;
2512
+ while (isIgnoredWrapper(root) || isUnsafeWrapper(root)) {
2513
+ if (isIgnoredWrapper(root)) {
2514
+ trie.ignored = true;
2515
+ marked = true;
2516
+ root = root[ignoreMarker];
2517
+ } else {
2518
+ trie.unsafe = true;
2519
+ marked = true;
2520
+ root = root[unsafeMarker];
2521
+ }
1206
2522
  }
1207
- return proxied;
2523
+ if (trie.ignored) return root;
2524
+ if (typeof root !== "object" || root === null) return root;
2525
+ if (Object.isFrozen(root)) return root;
2526
+ if (isState(root)) {
2527
+ const peeled = peelReadProxy(root);
2528
+ if (typeof peeled === "object" && peeled !== null) return peeled;
2529
+ }
2530
+ const decision = admissionDecision(root);
2531
+ const strict = options?.strict !== false;
2532
+ if (decision.lane === "leaf") return root;
2533
+ const base = Object.create(Reflect.getPrototypeOf(root));
2534
+ Object.defineProperties(base, Object.getOwnPropertyDescriptors(root));
2535
+ const walk = {
2536
+ trie,
2537
+ marked,
2538
+ firstOccupancyByNode: /* @__PURE__ */ new Map(),
2539
+ laterOccupanciesByNode: /* @__PURE__ */ new Map()
2540
+ };
2541
+ consumeMarkerTree(base, createOperationPath([]), walk);
2542
+ applyCopiedMarkerPaths(walk);
2543
+ const declarations = walk.marked || hasDeclarations(trie) ? trie : void 0;
2544
+ if (decision.lane === "dangerous" && strict && declarations?.unsafe !== true) {
2545
+ throw rejectionError(base, decision.kind);
2546
+ }
2547
+ assertSafeDataPaths(base, [], /* @__PURE__ */ new Set(), strict ? "admission" : "rootsOnly", [declarations]);
2548
+ const handle = {
2549
+ proxy: { root: base },
2550
+ lastSnapshot: base,
2551
+ hasPendingWrites: false,
2552
+ isFlushScheduled: false,
2553
+ isFlushHeld: false,
2554
+ flushGeneration: 0,
2555
+ subscribers: /* @__PURE__ */ new Map(),
2556
+ groups: options?.group !== void 0 ? getGroupChain(options.group) : void 0,
2557
+ emitOn: options?.emitOn,
2558
+ strict,
2559
+ declarations,
2560
+ nodes: /* @__PURE__ */ new WeakMap(),
2561
+ byId: /* @__PURE__ */ new Map(),
2562
+ nextInternId: 1,
2563
+ stamp: {},
2564
+ version: 0,
2565
+ replaying: false
2566
+ };
2567
+ registerHandle(base, handle);
2568
+ handle.nodes.set(base, { edges: [], id: 0 });
2569
+ handle.byId.set(0, base);
2570
+ const instrumented = proxy({ root: base });
2571
+ handle.proxy = instrumented;
2572
+ handle.lastSnapshot = requireObjectSnapshot(snapshot(instrumented.root));
2573
+ seedInEdges(handle);
2574
+ seedOccupancies(handle);
2575
+ armWatch(handle);
2576
+ return instrumented.root;
1208
2577
  }
1209
2578
 
1210
2579
  // src/createGroup.ts
1211
- var groupListenersByGroup = /* @__PURE__ */ new WeakMap();
2580
+ var UnknownGroupError = class extends Error {
2581
+ constructor() {
2582
+ super("opshot: unknown group");
2583
+ this.name = "UnknownGroupError";
2584
+ }
2585
+ };
2586
+ var groupChainByGroup = /* @__PURE__ */ new WeakMap();
1212
2587
  function isGroup(value) {
1213
- return typeof value === "object" && value !== null && groupListenersByGroup.has(value);
2588
+ return typeof value === "object" && value !== null && groupChainByGroup.has(value);
1214
2589
  }
1215
2590
  function getGroupListeners(group) {
1216
- const listeners = groupListenersByGroup.get(group);
1217
- if (listeners === void 0) throw new Error("opshot: unknown group");
2591
+ const chain = groupChainByGroup.get(group);
2592
+ const listeners = chain?.at(-1);
2593
+ if (listeners === void 0) throw new UnknownGroupError();
1218
2594
  return listeners;
1219
2595
  }
1220
- function createGroup() {
2596
+ function getGroupChain(group) {
2597
+ const chain = groupChainByGroup.get(group);
2598
+ if (chain === void 0) throw new UnknownGroupError();
2599
+ return chain;
2600
+ }
2601
+ function createGroup(parent) {
2602
+ if (parent !== void 0 && !isGroup(parent)) {
2603
+ throw new Error("opshot: parent is not a group");
2604
+ }
1221
2605
  const listeners = /* @__PURE__ */ new Map();
1222
2606
  const group = {
1223
- createMutableState(properties) {
1224
- return createMutableState(properties, group);
2607
+ createMutableState(properties, options) {
2608
+ return createMutableState(properties, { ...options, group });
1225
2609
  }
1226
2610
  };
1227
- groupListenersByGroup.set(group, listeners);
2611
+ const chain = parent === void 0 ? [listeners] : [...getGroupChain(parent), listeners];
2612
+ groupChainByGroup.set(group, chain);
1228
2613
  return group;
1229
2614
  }
1230
2615
 
1231
2616
  // src/emit/emitterListeners.ts
1232
- function addStateListener(state, listener, channelId, deliver2) {
1233
- const target = resolveEmitterTarget(state);
1234
- const record = getOrCreateEmitter(target);
1235
- if (record.disarm === void 0 && record.groupListeners === void 0) {
1236
- armWatchdog(record);
2617
+ var bindings = /* @__PURE__ */ new WeakMap();
2618
+ var dropListenerChannel = (byListener, listener, channelId, unsubscribe) => {
2619
+ const channels = byListener.get(listener);
2620
+ if (channels?.has(channelId) !== true) {
2621
+ bindings.delete(unsubscribe);
2622
+ return;
1237
2623
  }
1238
- let byChannel = record.listeners.get(listener);
2624
+ channels.delete(channelId);
2625
+ if (channels.size === 0) byListener.delete(listener);
2626
+ bindings.delete(unsubscribe);
2627
+ };
2628
+ function addStateListener(state, listener, channelId, deliver) {
2629
+ const handle = requireHandle(state, "opshot: subscribe requires a state");
2630
+ let byChannel = handle.subscribers.get(listener);
1239
2631
  if (byChannel === void 0) {
1240
2632
  byChannel = /* @__PURE__ */ new Map();
1241
- record.listeners.set(listener, byChannel);
2633
+ handle.subscribers.set(listener, byChannel);
1242
2634
  }
1243
- byChannel.set(channelId, deliver2);
1244
- return () => {
1245
- const channels = record.listeners.get(listener);
1246
- if (channels?.has(channelId) !== true) return;
1247
- settlePendingBare(record);
1248
- channels.delete(channelId);
1249
- if (channels.size === 0) record.listeners.delete(listener);
1250
- if (record.groupListeners === void 0 && record.listeners.size === 0) {
1251
- disarmWatchdog(record);
1252
- deleteEmitter(target);
1253
- }
2635
+ byChannel.set(channelId, deliver);
2636
+ const unsubscribe = () => {
2637
+ const held = bindings.get(unsubscribe);
2638
+ if (held === void 0) return;
2639
+ dropListenerChannel(held.handle.subscribers, held.listener, held.channelId, unsubscribe);
1254
2640
  };
2641
+ bindings.set(unsubscribe, { handle, listener, channelId });
2642
+ return unsubscribe;
1255
2643
  }
1256
- function addGroupListener(groupListeners, listener, channelId, deliver2) {
2644
+ function addGroupListener(groupListeners, listener, channelId, deliver) {
1257
2645
  let byChannel = groupListeners.get(listener);
1258
2646
  if (byChannel === void 0) {
1259
2647
  byChannel = /* @__PURE__ */ new Map();
1260
2648
  groupListeners.set(listener, byChannel);
1261
2649
  }
1262
- byChannel.set(channelId, deliver2);
1263
- return () => {
1264
- const channels = groupListeners.get(listener);
1265
- if (channels?.has(channelId) !== true) return;
1266
- channels.delete(channelId);
1267
- if (channels.size === 0) groupListeners.delete(listener);
2650
+ byChannel.set(channelId, deliver);
2651
+ const unsubscribe = () => {
2652
+ const held = bindings.get(unsubscribe);
2653
+ if (held === void 0) return;
2654
+ dropListenerChannel(held.listeners, held.listener, held.channelId, unsubscribe);
1268
2655
  };
2656
+ bindings.set(unsubscribe, { listeners: groupListeners, listener, channelId });
2657
+ return unsubscribe;
1269
2658
  }
1270
2659
 
1271
- // src/transact.ts
1272
- function transact(state, mutate, meta) {
1273
- const record = getEmitter(state);
1274
- if (record === void 0) {
1275
- mutate();
1276
- return;
2660
+ // src/emit/resolveWriteProxy.ts
2661
+ var { proxyStateMap: proxyStateMap15 } = unstable_getInternalStates();
2662
+ var ExpectedStateObjectError = class extends Error {
2663
+ constructor() {
2664
+ super("opshot: expected a state object");
2665
+ this.name = "ExpectedStateObjectError";
1277
2666
  }
1278
- if (record.isMutating) throw new Error("opshot: nested transact on the same state");
1279
- settlePendingBare(record);
1280
- record.isMutating = true;
1281
- try {
1282
- mutate();
1283
- } finally {
1284
- record.isMutating = false;
2667
+ };
2668
+ var isObjectLike4 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
2669
+ function resolveWriteProxy(state) {
2670
+ let current = state;
2671
+ while (isObjectLike4(current)) {
2672
+ if (proxyStateMap15.has(current)) return current;
2673
+ const peeled = peelIdentityLayer(current);
2674
+ if (peeled === void 0) break;
2675
+ current = peeled;
1285
2676
  }
1286
- const after = snapshot(record.target);
1287
- const before = record.lastReported;
1288
- record.lastReported = after;
1289
- if (before === after) return;
1290
- if (!hasListeners(record)) return;
1291
- const ops = diffSnapshots(requireObjectSnapshot(before), requireObjectSnapshot(after));
1292
- if (ops.length === 0) return;
1293
- deliver(record, ops, meta);
2677
+ if (!isObjectLike4(current) || !proxyStateMap15.has(current)) throw new ExpectedStateObjectError();
2678
+ return current;
1294
2679
  }
1295
2680
 
1296
- // src/ops/applyOps.ts
1297
- var isObjectLike4 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
1298
- var sameValueZero = (first, second) => first === second || first !== first && second !== second;
1299
- var sameIdentity = (first, second) => sameValueZero(resolveIdentity(first), resolveIdentity(second));
1300
- var assertApplicable = (operation) => {
1301
- if (typeof operation === "object" && operation !== null && "do" in operation) {
1302
- throw new Error("opshot: applyOps applies operation halves; pass op.do or op.undo.");
1303
- }
1304
- if (!isOperation(operation)) {
1305
- throw new Error(
1306
- "opshot: this op is a copy (spread, JSON, or structuredClone) and has lost its value. Apply the op objects the listener delivered; never copy them."
1307
- );
1308
- }
2681
+ // src/transact/nest.ts
2682
+ var transactionOpen = false;
2683
+ var isTransactionOpen = () => transactionOpen;
2684
+ var openTransaction = () => {
2685
+ transactionOpen = true;
1309
2686
  };
1310
- var unresolvedError = (path) => new Error(`opshot: ${formatOperationPath(path)} does not resolve to a supported operation address`);
1311
- var matchesAppliedValue = (current, expected) => {
1312
- if (isObjectLike4(current) && isObjectLike4(expected)) return sameIdentity(current, expected);
1313
- return Object.is(current, expected);
2687
+ var closeTransaction = () => {
2688
+ transactionOpen = false;
1314
2689
  };
1315
- var setOrThrow = (target, key, value) => {
1316
- const written = Reflect.set(target, key, value);
1317
- const descriptor = Reflect.getOwnPropertyDescriptor(target, key);
1318
- const current = descriptor && "value" in descriptor ? Reflect.get(target, key) : void 0;
1319
- if (!written || !descriptor || !("value" in descriptor) || !matchesAppliedValue(current, value)) {
1320
- throw new Error(`opshot: replay could not restore ${String(key)}`);
2690
+
2691
+ // src/ops/applyMutations.ts
2692
+ var ReplayReattachError = class extends Error {
2693
+ constructor(message) {
2694
+ super(message);
2695
+ this.name = "ReplayReattachError";
1321
2696
  }
1322
2697
  };
1323
- var deleteOrThrow = (target, key) => {
1324
- if (!Reflect.deleteProperty(target, key)) throw new Error(`opshot: replay could not remove ${String(key)}`);
1325
- };
1326
- var restoreRecordedContent = (attached, recorded, restored) => {
2698
+ var unresolvedError = (path) => new Error(`opshot: ${formatOperationPath(path)} does not resolve to a supported operation address`);
2699
+ var linkError = (path, ref, reason) => new Error(`opshot: link at ${formatOperationPath(path)} with ref ${String(ref)} ${reason}`);
2700
+ var isWritableDataDescriptor = (descriptor) => descriptor !== void 0 && "value" in descriptor && descriptor.writable === true;
2701
+ var restoreRecordedContent = (attached, recorded, restored, identity) => {
1327
2702
  if (restored.has(recorded)) return;
1328
2703
  restored.add(recorded);
1329
- const recordedKeys = Reflect.ownKeys(recorded);
1330
- const orderedKeys = Array.isArray(recorded) ? ["length", ...recordedKeys.filter((key) => key !== "length")] : recordedKeys;
1331
- for (const key of orderedKeys) {
1332
- const descriptor = Reflect.getOwnPropertyDescriptor(recorded, key);
2704
+ for (const entry of walkDataEntries(recorded, true)) {
2705
+ const key = entry.key;
1333
2706
  const attachedDescriptor = Reflect.getOwnPropertyDescriptor(attached, key);
1334
- if (!descriptor || !("value" in descriptor) || attachedDescriptor && !("value" in attachedDescriptor)) continue;
1335
- const value = descriptor.value;
1336
- if (isObjectLike4(value)) {
2707
+ if (attachedDescriptor !== void 0 && !isWritableDataDescriptor(attachedDescriptor)) continue;
2708
+ const value = entry.value;
2709
+ if (identity === "restore" && isObjectLike3(value)) {
1337
2710
  const target = getRegisteredTarget(value);
1338
2711
  if (target !== void 0) {
1339
- setOrThrow(attached, key, target);
2712
+ const present = attachedDescriptor?.value;
2713
+ if (!isObjectLike3(present) || resolveIdentity(present) !== resolveIdentity(target)) {
2714
+ Reflect.set(attached, key, target);
2715
+ }
1340
2716
  const child = Reflect.get(attached, key);
1341
- if (!isObjectLike4(child)) throw new Error(`opshot: replay could not reattach ${String(key)}`);
1342
- restoreRecordedContent(child, value, restored);
2717
+ if (!isObjectLike3(child)) throw new ReplayReattachError(`opshot: replay could not reattach ${key}`);
2718
+ restoreRecordedContent(child, value, restored, identity);
1343
2719
  continue;
1344
2720
  }
1345
2721
  }
1346
- setOrThrow(attached, key, value);
2722
+ Reflect.set(attached, key, value);
1347
2723
  }
1348
- for (const key of Reflect.ownKeys(attached)) {
1349
- if (Object.hasOwn(recorded, key)) continue;
1350
- const descriptor = Reflect.getOwnPropertyDescriptor(attached, key);
1351
- if (descriptor && "value" in descriptor) deleteOrThrow(attached, key);
2724
+ for (const entry of walkDataEntries(attached)) {
2725
+ if (!entry.writable) continue;
2726
+ if (Object.hasOwn(recorded, entry.key)) continue;
2727
+ Reflect.deleteProperty(attached, entry.key);
1352
2728
  }
1353
2729
  };
1354
- var getValuePayload = (operation) => {
1355
- const original = getValueOriginal(operation);
1356
- if (original !== void 0) {
1357
- if (isObjectLike4(original) && getRegisteredTarget(original) !== void 0)
1358
- return { recorded: original, fallback: void 0 };
1359
- return { recorded: original, fallback: operation.value };
1360
- }
1361
- return { recorded: operation.value, fallback: operation.value };
2730
+ var getValuePayload = (operation, identity) => {
2731
+ const original = identity === "restore" ? getValueOriginal(operation) ?? operation.value : operation.value;
2732
+ return {
2733
+ recorded: original,
2734
+ fallback: isObjectLike3(original) ? cloneValue(original, /* @__PURE__ */ new WeakMap(), operation.path) : original
2735
+ };
1362
2736
  };
1363
- var restoreValue = (payload, attach, readAttached) => {
1364
- if (isObjectLike4(payload.recorded)) {
2737
+ var restoreValue = (payload, attach, readAttached, identity) => {
2738
+ if (identity === "restore" && isObjectLike3(payload.recorded)) {
1365
2739
  const target = getRegisteredTarget(payload.recorded);
1366
2740
  if (target !== void 0) {
1367
2741
  attach(target);
1368
2742
  const attached = readAttached();
1369
- if (!isObjectLike4(attached)) throw new Error("opshot: replay could not read a reattached target");
1370
- restoreRecordedContent(attached, payload.recorded, /* @__PURE__ */ new WeakSet());
2743
+ if (!isObjectLike3(attached)) {
2744
+ throw new ReplayReattachError("opshot: replay could not read a reattached target");
2745
+ }
2746
+ restoreRecordedContent(attached, payload.recorded, /* @__PURE__ */ new WeakSet(), identity);
1371
2747
  return;
1372
2748
  }
1373
2749
  }
@@ -1382,14 +2758,9 @@ var getInheritedDescriptor = (target, key) => {
1382
2758
  }
1383
2759
  return void 0;
1384
2760
  };
1385
- var isCanonicalArrayIndex2 = (segment) => Number.isInteger(segment) && typeof segment === "number" && segment >= 0 && segment < 4294967295;
1386
- var isCanonicalArrayIndexString = (segment) => {
1387
- const index = Number(segment);
1388
- return Number.isInteger(index) && index >= 0 && index < 4294967295 && String(index) === segment;
1389
- };
1390
2761
  var requirePlainSegment = (parent, segment, path) => {
1391
2762
  if (Array.isArray(parent)) {
1392
- if (isCanonicalArrayIndex2(segment)) return segment;
2763
+ if (isCanonicalArrayIndex(segment)) return segment;
1393
2764
  if (typeof segment === "string" && !isCanonicalArrayIndexString(segment)) return segment;
1394
2765
  throw unresolvedError(path);
1395
2766
  }
@@ -1404,152 +2775,365 @@ var requirePlainProperty = (parent, segment, path) => {
1404
2775
  return Reflect.get(parent, key);
1405
2776
  };
1406
2777
  var resolveTraversalSegment = (parent, segment, path) => {
1407
- if (!isObjectLike4(parent)) throw unresolvedError(path);
2778
+ if (!isObjectLike3(parent)) throw unresolvedError(path);
1408
2779
  return requirePlainProperty(parent, segment, path);
1409
2780
  };
1410
2781
  var resolveTerminal = (root, path) => {
1411
- assertSafePath(path);
1412
- if (path.length === 0) throw new Error("opshot: root operations are not supported");
2782
+ if (path.length === 0) throw unresolvedError(path);
1413
2783
  let parent = root;
1414
2784
  for (let index = 0; index < path.length - 1; index++) parent = resolveTraversalSegment(parent, path[index], path);
1415
- if (!isObjectLike4(parent)) throw unresolvedError(path);
2785
+ if (!isObjectLike3(parent)) throw unresolvedError(path);
1416
2786
  return { parent, segment: path[path.length - 1] };
1417
2787
  };
1418
- var applyPlain = (parent, segment, operation) => {
2788
+ var applyLink = (root, operation, handle) => {
2789
+ const path = operation.path;
2790
+ const ref = operation.ref;
2791
+ if (path.length === 0) throw linkError(path, ref, "does not resolve to a supported operation address");
2792
+ const resolved = nodeOfInternedId(handle, ref, handle.transactionCapture);
2793
+ if (resolved === void 0) throw linkError(path, ref, "does not resolve");
2794
+ const terminal = resolveTerminal(root, path);
2795
+ if (Array.isArray(terminal.parent) && terminal.segment === "length") {
2796
+ throw linkError(path, ref, "cannot address array length");
2797
+ }
2798
+ const key = requirePlainSegment(terminal.parent, terminal.segment, path);
2799
+ const descriptor = Reflect.getOwnPropertyDescriptor(terminal.parent, key);
2800
+ const present = descriptor !== void 0 && descriptor.enumerable && "value" in descriptor;
2801
+ if (descriptor !== void 0 && !present) throw unresolvedError(path);
2802
+ if (!present) {
2803
+ const inheritedDescriptor = getInheritedDescriptor(terminal.parent, key);
2804
+ if (inheritedDescriptor && !("value" in inheritedDescriptor)) {
2805
+ throw new Error(`opshot: ${formatOperationPath(path)} resolves to an inherited accessor`);
2806
+ }
2807
+ }
2808
+ Reflect.set(terminal.parent, key, resolved);
2809
+ };
2810
+ var applyPlain = (parent, segment, operation, identity, handle) => {
1419
2811
  const path = operation.path;
1420
2812
  if (Array.isArray(parent) && segment === "length") {
1421
- if (operation.op !== "replace" || typeof operation.value !== "number" || !Number.isInteger(operation.value) || operation.value < 0 || operation.value > 4294967295) {
2813
+ if (operation.verb !== "assign" || typeof operation.value !== "number" || !Number.isInteger(operation.value) || operation.value < 0 || operation.value > MAX_ARRAY_LENGTH) {
1422
2814
  throw unresolvedError(path);
1423
2815
  }
1424
- setOrThrow(parent, "length", operation.value);
2816
+ Reflect.set(parent, "length", operation.value);
1425
2817
  return;
1426
2818
  }
1427
2819
  const key = requirePlainSegment(parent, segment, path);
1428
2820
  const descriptor = Reflect.getOwnPropertyDescriptor(parent, key);
1429
2821
  const present = descriptor !== void 0 && descriptor.enumerable && "value" in descriptor;
1430
2822
  if (descriptor !== void 0 && !present) throw unresolvedError(path);
1431
- if (operation.op === "add" && present) throw unresolvedError(path);
1432
- if (operation.op !== "add" && !present) throw unresolvedError(path);
1433
- if (operation.op === "add") {
2823
+ if (operation.verb === "delete") {
2824
+ Reflect.deleteProperty(parent, key);
2825
+ return;
2826
+ }
2827
+ if (!present) {
1434
2828
  const inheritedDescriptor = getInheritedDescriptor(parent, key);
1435
2829
  if (inheritedDescriptor && !("value" in inheritedDescriptor)) {
1436
2830
  throw new Error(`opshot: ${formatOperationPath(path)} resolves to an inherited accessor`);
1437
2831
  }
1438
2832
  }
1439
- if (operation.op === "remove") {
1440
- deleteOrThrow(parent, key);
1441
- return;
1442
- }
1443
- if (!("value" in operation)) throw unresolvedError(path);
2833
+ const payload = getValuePayload(operation, identity);
1444
2834
  restoreValue(
1445
- getValuePayload(operation),
1446
- (value) => setOrThrow(parent, key, value),
1447
- () => Reflect.get(parent, key)
2835
+ payload,
2836
+ (value) => Reflect.set(parent, key, value),
2837
+ () => Reflect.get(parent, key),
2838
+ identity
1448
2839
  );
2840
+ const attached = Reflect.get(parent, key);
2841
+ if (!isObjectLike3(attached)) return;
2842
+ if (operation.ids !== void 0) {
2843
+ if (isObjectLike3(payload.recorded)) {
2844
+ bindVendedIds(handle, attached, payload.recorded, operation.ids, handle.transactionCapture, parent, key);
2845
+ }
2846
+ } else {
2847
+ let chains = chainsAtRoot(handle.declarations);
2848
+ for (const segment2 of path) chains = descendChains(chains, segment2).chains;
2849
+ chains = nodeChainsOf(handle, attached) ?? chains;
2850
+ internSubtree(
2851
+ handle,
2852
+ attached,
2853
+ chains,
2854
+ (parent2, parentChains, key2, entry) => isTrackedEdge(entry) ? resolveChildChains(handle, parent2, parentChains, key2, entry.value)?.chains : void 0,
2855
+ handle.transactionCapture
2856
+ );
2857
+ }
2858
+ };
2859
+ var applyMutation = (root, operation, identity, handle) => {
2860
+ if (operation.verb === "link") {
2861
+ applyLink(root, operation, handle);
2862
+ return;
2863
+ }
2864
+ const terminal = resolveTerminal(root, operation.path);
2865
+ applyPlain(terminal.parent, terminal.segment, operation, identity, handle);
1449
2866
  };
1450
- function applyOperations(root, operations) {
2867
+ function applyMutations(root, operations, direction, identity, handle) {
2868
+ if (direction === "do") {
2869
+ for (const operation of operations) applyMutation(root, operation.do, identity, handle);
2870
+ return;
2871
+ }
2872
+ const occupantAt = (path) => {
2873
+ let current = root;
2874
+ for (const segment of path) {
2875
+ if (!isObjectLike3(current)) return void 0;
2876
+ current = Reflect.get(current, segment);
2877
+ }
2878
+ return current;
2879
+ };
2880
+ const admittedRoots = new Array();
1451
2881
  for (const operation of operations) {
1452
- const terminal = resolveTerminal(root, operation.path);
1453
- applyPlain(terminal.parent, terminal.segment, operation);
2882
+ if (operation.do.verb !== "assign" || !isObjectLike3(operation.do.value)) continue;
2883
+ const occupant = occupantAt(operation.undo.path);
2884
+ if (isObjectLike3(occupant)) admittedRoots.push(occupant);
2885
+ }
2886
+ for (let index = operations.length - 1; index >= 0; index--) {
2887
+ const operation = operations[index];
2888
+ if (operation === void 0) continue;
2889
+ applyMutation(root, operation.undo, identity, handle);
2890
+ }
2891
+ const idSet = /* @__PURE__ */ new Set();
2892
+ for (const node of admittedRoots) {
2893
+ for (const id of rewindAdmission(handle, node)) idSet.add(id);
2894
+ }
2895
+ while (idSet.has(handle.nextInternId - 1)) handle.nextInternId -= 1;
2896
+ }
2897
+
2898
+ // src/transact/rollback.ts
2899
+ var rollbackTransaction = (handle) => {
2900
+ const restoreTarget = handle.lastSnapshot;
2901
+ const operations = diffObjects(snapshot(handle.proxy.root), restoreTarget, handle, void 0, createCaptureTables());
2902
+ if (operations.length > 0) {
2903
+ applyMutations(handle.proxy.root, operations, "do", "restore", handle);
2904
+ }
2905
+ handle.lastSnapshot = restoreTarget;
2906
+ handle.hasPendingWrites = false;
2907
+ };
2908
+
2909
+ // src/transact/transact.ts
2910
+ function transact(state, mutate, meta) {
2911
+ runTransaction(state, mutate, meta, void 0);
2912
+ }
2913
+ var attachRollbackCause = (error, rollbackError) => {
2914
+ if (!(error instanceof Error) || error.cause !== void 0) return;
2915
+ Object.defineProperty(error, "cause", {
2916
+ value: rollbackError,
2917
+ writable: true,
2918
+ enumerable: false,
2919
+ configurable: true
2920
+ });
2921
+ };
2922
+ var flattenDeliveryFailures = (error) => {
2923
+ if (error instanceof AggregateError && error.message === "opshot: listeners failed during delivery") {
2924
+ return error.errors;
2925
+ }
2926
+ return [error];
2927
+ };
2928
+ var releaseUncaught = (failures) => {
2929
+ if (failures.length === 0) return;
2930
+ const error = failures.length === 1 ? failures[0] : new AggregateError(failures, "opshot: listeners failed during delivery");
2931
+ queueMicrotask(() => {
2932
+ throw error;
2933
+ });
2934
+ };
2935
+ function runTransaction(state, mutate, meta, channelId) {
2936
+ if (isTransactionOpen()) {
2937
+ throw new Error(
2938
+ "opshot: transact cannot be nested; a transaction cannot contain another. Mutate inside the callback rather than transacting, run transactions in sequence, or call applyOperations at top level."
2939
+ );
2940
+ }
2941
+ const handle = requireHandle(state, "opshot: transact requires a state");
2942
+ handle.flushGeneration += 1;
2943
+ handle.isFlushScheduled = false;
2944
+ const listenerFailures = new Array();
2945
+ const emitCollectingListeners = (emit) => {
2946
+ const baseline = handle.lastSnapshot;
2947
+ try {
2948
+ emit();
2949
+ } catch (error) {
2950
+ if (handle.lastSnapshot === baseline) throw error;
2951
+ listenerFailures.push(...flattenDeliveryFailures(error));
2952
+ }
2953
+ };
2954
+ const deliverQuietly = (ranges) => {
2955
+ try {
2956
+ deliverCapturedRanges(ranges);
2957
+ } catch (error) {
2958
+ listenerFailures.push(...flattenDeliveryFailures(error));
2959
+ }
2960
+ };
2961
+ try {
2962
+ const starting = captureWrites(handle);
2963
+ const previousHeld = handle.isFlushHeld;
2964
+ handle.isFlushHeld = true;
2965
+ handle.transactionCapture = createCaptureTables();
2966
+ openTransaction();
2967
+ let completed = false;
2968
+ let mutateError;
2969
+ try {
2970
+ mutate();
2971
+ completed = true;
2972
+ } catch (error) {
2973
+ mutateError = error;
2974
+ throw error;
2975
+ } finally {
2976
+ closeTransaction();
2977
+ if (!completed) {
2978
+ try {
2979
+ rollbackTransaction(handle);
2980
+ } catch (rollbackError) {
2981
+ attachRollbackCause(mutateError, rollbackError);
2982
+ }
2983
+ handle.transactionCapture = void 0;
2984
+ handle.isFlushHeld = previousHeld;
2985
+ deliverQuietly([starting]);
2986
+ } else {
2987
+ handle.isFlushHeld = previousHeld;
2988
+ }
2989
+ }
2990
+ let transaction;
2991
+ try {
2992
+ transaction = captureTransactionWrites(handle, meta, channelId);
2993
+ } catch (error) {
2994
+ try {
2995
+ rollbackTransaction(handle);
2996
+ } catch (rollbackError) {
2997
+ attachRollbackCause(error, rollbackError);
2998
+ }
2999
+ deliverQuietly([starting]);
3000
+ throw error;
3001
+ } finally {
3002
+ handle.transactionCapture = void 0;
3003
+ }
3004
+ deliverQuietly([starting, transaction]);
3005
+ emitCollectingListeners(() => {
3006
+ emitWrites(handle);
3007
+ });
3008
+ } finally {
3009
+ releaseUncaught(listenerFailures);
3010
+ }
3011
+ }
3012
+
3013
+ // src/ops/applyOperations.ts
3014
+ var originError = () => new Error("opshot: applyOperations applies a state's operations only to that state");
3015
+ var tapeError = () => new Error("opshot: applyOperations applies only the next or previous operations");
3016
+ var isFrozenCopyablePath = (value) => Array.isArray(value) && value.every((segment) => typeof segment === "string" || typeof segment === "number");
3017
+ var isNonNegativeInteger = (value) => typeof value === "number" && Number.isInteger(value) && value >= 0;
3018
+ var isWellFormedLinkHalf = (value) => typeof value === "object" && value !== null && "verb" in value && value.verb === "link" && "path" in value && "ref" in value && isFrozenCopyablePath(value.path) && isNonNegativeInteger(value.ref);
3019
+ var isWellFormedDeleteHalf = (value) => typeof value === "object" && value !== null && "verb" in value && value.verb === "delete" && "path" in value && isFrozenCopyablePath(value.path);
3020
+ var isWellFormedIds = (value) => value === void 0 || Array.isArray(value) && value.every((id) => typeof id === "number" && Number.isInteger(id) && id >= 0);
3021
+ var isWellFormedAssignHalf = (value) => typeof value === "object" && value !== null && "verb" in value && value.verb === "assign" && "value" in value && "path" in value && isFrozenCopyablePath(value.path) && (!("ids" in value) || value.ids === void 0 || isWellFormedIds(value.ids));
3022
+ var isApplicableHalf = (value) => isMutation(value) || isWellFormedLinkHalf(value) || isWellFormedDeleteHalf(value) || isWellFormedAssignHalf(value);
3023
+ var assertApplicable = (operation) => {
3024
+ if (isMutation(operation)) {
3025
+ throw new Error("opshot: applyOperations applies operation pairs; pass the operation, with a direction");
3026
+ }
3027
+ if (typeof operation !== "object" || operation === null || !("do" in operation) || !("undo" in operation) || !isApplicableHalf(operation.do) || !isApplicableHalf(operation.undo)) {
3028
+ throw new Error("opshot: applyOperations applies well-formed { do, undo } pairs");
1454
3029
  }
3030
+ };
3031
+ function applyOperations(state, operations, direction, meta) {
3032
+ runOperations(state, operations, direction, meta, void 0);
1455
3033
  }
1456
- function applyOps(state, operations, meta) {
3034
+ function runOperations(state, operations, direction, meta, channelId) {
1457
3035
  for (const operation of operations) assertApplicable(operation);
1458
- transact(
1459
- state,
1460
- () => {
1461
- applyOperations(resolveEmitterTarget(state), operations);
1462
- },
1463
- meta
1464
- );
3036
+ const appliedDirection = direction;
3037
+ if (appliedDirection !== "do" && appliedDirection !== "undo") {
3038
+ throw new Error('opshot: applyOperations applies a direction of "do" or "undo"');
3039
+ }
3040
+ if (isTransactionOpen()) {
3041
+ throw new Error(
3042
+ "opshot: transact cannot be nested; a transaction cannot contain another. Mutate inside the callback rather than transacting, run transactions in sequence, or call applyOperations at top level."
3043
+ );
3044
+ }
3045
+ const handle = requireHandle(state, "opshot: applyOperations requires a state");
3046
+ emitWrites(handle);
3047
+ let ownedCount = 0;
3048
+ for (const operation of operations) {
3049
+ const stamp = stampOf(operation);
3050
+ if (stamp !== void 0 && stamp !== handle.stamp) throw originError();
3051
+ if (stamp === handle.stamp) ownedCount += 1;
3052
+ }
3053
+ if (ownedCount > 0 && ownedCount < operations.length) throw originError();
3054
+ const owned = operations.length > 0 && ownedCount === operations.length;
3055
+ if (owned) {
3056
+ let index = 0;
3057
+ for (const operation of operations) {
3058
+ const expected = direction === "do" ? handle.version + 1 + index : handle.version - (operations.length - 1 - index);
3059
+ if (versionOf(operation) !== expected) throw tapeError();
3060
+ index += 1;
3061
+ }
3062
+ }
3063
+ handle.replaying = true;
3064
+ try {
3065
+ runTransaction(
3066
+ state,
3067
+ () => {
3068
+ applyMutations(resolveWriteProxy(state), operations, direction, owned ? "restore" : "construct", handle);
3069
+ if (owned) {
3070
+ handle.version = direction === "do" ? handle.version + operations.length : handle.version - operations.length;
3071
+ }
3072
+ },
3073
+ meta,
3074
+ channelId
3075
+ );
3076
+ } finally {
3077
+ handle.replaying = false;
3078
+ }
1465
3079
  }
1466
3080
 
1467
3081
  // src/subscribe.ts
1468
3082
  function subscribe2(target, listener) {
1469
3083
  if (isGroup(target)) {
1470
- return addGroupListener(getGroupListeners(target), listener, void 0, (state, ops, meta) => {
1471
- listener(state, ops, unwrapTransportMeta(meta));
1472
- });
3084
+ return addGroupListener(
3085
+ getGroupListeners(target),
3086
+ listener,
3087
+ void 0,
3088
+ (state, ops, meta) => listener(state, ops, meta)
3089
+ );
1473
3090
  }
1474
- return addStateListener(target, listener, void 0, (ops, meta) => {
1475
- listener(ops, unwrapTransportMeta(meta));
1476
- });
1477
- }
1478
- var channelStampBrand = /* @__PURE__ */ Symbol.for("opshot.channelStamp");
1479
- function stampChannelMeta(channelId, meta) {
1480
- return { [channelStampBrand]: channelId, meta };
1481
- }
1482
- function isChannelStamp(value) {
1483
- return typeof value === "object" && value !== null && channelStampBrand in value;
1484
- }
1485
- function isOwnChannelStamp(value, channelId) {
1486
- return isChannelStamp(value) && value[channelStampBrand] === channelId;
1487
- }
1488
- function unwrapTransportMeta(meta) {
1489
- if (isChannelStamp(meta)) return meta.meta;
1490
- return meta;
3091
+ return addStateListener(target, listener, void 0, (ops, meta) => listener(ops, meta));
1491
3092
  }
1492
- function toChannelContext(channelId, defaults, meta) {
1493
- if (isOwnChannelStamp(meta, channelId)) {
1494
- return { isTransaction: true, meta: { ...defaults, ...meta.meta } };
3093
+ function toChannelContext(channelId, defaults, meta, deliveredChannelId) {
3094
+ if (deliveredChannelId === channelId) {
3095
+ return {
3096
+ isTransaction: true,
3097
+ meta: { ...defaults, ...typeof meta === "object" && meta !== null ? meta : void 0 }
3098
+ };
1495
3099
  }
1496
- return { isTransaction: false, meta: unwrapTransportMeta(meta) };
3100
+ return { isTransaction: false, meta };
1497
3101
  }
1498
3102
 
1499
3103
  // src/createChannel.ts
1500
3104
  function createChannel(defaults) {
1501
3105
  const channelId = Object.freeze({});
1502
3106
  function transact2(state, mutate, meta) {
1503
- transact(state, mutate, stampChannelMeta(channelId, meta));
3107
+ runTransaction(state, mutate, meta, channelId);
1504
3108
  }
1505
3109
  function subscribe3(target, listener) {
1506
3110
  if (isGroup(target)) {
1507
- return addGroupListener(getGroupListeners(target), listener, channelId, (state, ops, meta) => {
1508
- listener(
1509
- state,
1510
- ops,
1511
- toChannelContext(channelId, defaults, meta)
1512
- );
1513
- });
3111
+ return addGroupListener(
3112
+ getGroupListeners(target),
3113
+ listener,
3114
+ channelId,
3115
+ (state, ops, meta, deliveredChannelId) => {
3116
+ listener(
3117
+ state,
3118
+ ops,
3119
+ toChannelContext(channelId, defaults, meta, deliveredChannelId)
3120
+ );
3121
+ }
3122
+ );
1514
3123
  }
1515
- return addStateListener(target, listener, channelId, (ops, meta) => {
3124
+ return addStateListener(target, listener, channelId, (ops, meta, deliveredChannelId) => {
1516
3125
  listener(
1517
3126
  ops,
1518
- toChannelContext(channelId, defaults, meta)
3127
+ toChannelContext(channelId, defaults, meta, deliveredChannelId)
1519
3128
  );
1520
3129
  });
1521
3130
  }
1522
- function applyOps2(state, operations, meta) {
1523
- applyOps(state, operations, stampChannelMeta(channelId, meta));
1524
- }
1525
- return { transact: transact2, subscribe: subscribe3, applyOps: applyOps2 };
1526
- }
1527
-
1528
- // src/react/resolveWrapper.ts
1529
- var { proxyStateMap: proxyStateMap5 } = unstable_getInternalStates();
1530
- var isObjectLike5 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
1531
- function unwrapWrapper(value) {
1532
- if (!isObjectLike5(value) || proxyStateMap5.has(value)) return value;
1533
- let current = value;
1534
- while (isObjectLike5(current)) {
1535
- const registeredTarget = getRegisteredWrapperTarget(current);
1536
- if (registeredTarget === void 0) break;
1537
- current = registeredTarget;
3131
+ function applyOperations2(state, operations, direction, meta) {
3132
+ runOperations(state, operations, direction, meta, channelId);
1538
3133
  }
1539
- return current;
1540
- }
1541
-
1542
- // src/isState.ts
1543
- var { proxyStateMap: proxyStateMap6 } = unstable_getInternalStates();
1544
- function isState(value) {
1545
- const resolved = unwrapWrapper(value);
1546
- if (typeof resolved !== "object" || resolved === null) return false;
1547
- return proxyStateMap6.has(resolved);
3134
+ return { transact: transact2, subscribe: subscribe3, applyOperations: applyOperations2 };
1548
3135
  }
1549
3136
 
1550
- // src/ignore.ts
1551
- var ignore = ref;
1552
-
1553
3137
  // src/tracked/facadeGuard.ts
1554
3138
  var assertMutableFacade = (facade, mutationKey) => {
1555
3139
  const facadeSource = getUntracked(facade);
@@ -1561,11 +3145,17 @@ var assertMutableFacade = (facade, mutationKey) => {
1561
3145
  };
1562
3146
 
1563
3147
  // src/tracked/trackedDate.ts
3148
+ var DateSetYearError = class extends Error {
3149
+ constructor(message) {
3150
+ super(message);
3151
+ this.name = "DateSetYearError";
3152
+ }
3153
+ };
1564
3154
  var setLegacyYear = (date, year) => {
1565
3155
  const setYear = Reflect.get(date, "setYear");
1566
- if (typeof setYear !== "function") throw new Error("opshot: Date.setYear is not available");
3156
+ if (typeof setYear !== "function") throw new DateSetYearError("opshot: Date.setYear is not available");
1567
3157
  const epochMs = Reflect.apply(setYear, date, [year]);
1568
- if (typeof epochMs !== "number") throw new Error("opshot: Date.setYear returned a non-number");
3158
+ if (typeof epochMs !== "number") throw new DateSetYearError("opshot: Date.setYear returned a non-number");
1569
3159
  return epochMs;
1570
3160
  };
1571
3161
  var constructDate = (args) => {
@@ -1588,6 +3178,11 @@ var constructDate = (args) => {
1588
3178
  return new Date(args[0], args[1], args[2], args[3], args[4], args[5], args[6]);
1589
3179
  }
1590
3180
  };
3181
+ var MAX_TIME = 864e13;
3182
+ var clipTime = (epochMs) => {
3183
+ if (!Number.isFinite(epochMs) || Math.abs(epochMs) > MAX_TIME) return Number.NaN;
3184
+ return Math.trunc(epochMs) + 0;
3185
+ };
1591
3186
  var TrackedDate = class {
1592
3187
  constructor(...args) {
1593
3188
  installBoundary();
@@ -1596,6 +3191,9 @@ var TrackedDate = class {
1596
3191
  readDate() {
1597
3192
  return new Date(this.epochMs);
1598
3193
  }
3194
+ readEpochMs() {
3195
+ return clipTime(this.epochMs);
3196
+ }
1599
3197
  write(mutate) {
1600
3198
  assertMutableFacade(this, "epochMs");
1601
3199
  const epochMs = mutate(this.readDate());
@@ -1621,10 +3219,10 @@ var TrackedDate = class {
1621
3219
  return this.readDate().toLocaleTimeString(locales, options);
1622
3220
  }
1623
3221
  valueOf() {
1624
- return this.readDate().valueOf();
3222
+ return this.readEpochMs();
1625
3223
  }
1626
3224
  getTime() {
1627
- return this.readDate().getTime();
3225
+ return this.readEpochMs();
1628
3226
  }
1629
3227
  getFullYear() {
1630
3228
  return this.readDate().getFullYear();
@@ -1738,8 +3336,8 @@ var TrackedDate = class {
1738
3336
  return this.readDate().toISOString();
1739
3337
  }
1740
3338
  [Symbol.toPrimitive](hint) {
1741
- const date = this.readDate();
1742
- return hint === "number" ? date[Symbol.toPrimitive]("number") : date[Symbol.toPrimitive](hint);
3339
+ if (hint === "number") return this.readEpochMs();
3340
+ return this.readDate()[Symbol.toPrimitive](hint);
1743
3341
  }
1744
3342
  };
1745
3343
  Object.defineProperty(TrackedDate.prototype, Symbol.toStringTag, {
@@ -1750,19 +3348,11 @@ Object.defineProperty(TrackedDate.prototype, Symbol.toStringTag, {
1750
3348
  });
1751
3349
 
1752
3350
  // src/tracked/address.ts
1753
- var internTable = /* @__PURE__ */ new WeakMap();
1754
- var nextInternId = 0;
1755
- var internIdentity = (key) => {
1756
- const resolved = resolveIdentity(key);
1757
- if (resolved === null || typeof resolved !== "object" && typeof resolved !== "function" && typeof resolved !== "symbol") {
1758
- throw new Error("opshot: addressOf interned a non-identity value");
3351
+ var UnsupportedKeyTypeError = class extends Error {
3352
+ constructor(key) {
3353
+ super(`opshot: addressOf received unsupported key type ${typeof key}`);
3354
+ this.name = "UnsupportedKeyTypeError";
1759
3355
  }
1760
- const existing = internTable.get(resolved);
1761
- if (existing !== void 0) return existing;
1762
- const id = nextInternId;
1763
- nextInternId += 1;
1764
- internTable.set(resolved, id);
1765
- return id;
1766
3356
  };
1767
3357
  var addressOf = (key) => {
1768
3358
  if (key === null) return "z";
@@ -1785,10 +3375,59 @@ var addressOf = (key) => {
1785
3375
  case "function":
1786
3376
  return `o${internIdentity(key)}`;
1787
3377
  default:
1788
- throw new Error(`opshot: addressOf received unsupported key type ${typeof key}`);
3378
+ throw new UnsupportedKeyTypeError(key);
1789
3379
  }
1790
3380
  };
1791
3381
 
3382
+ // src/tracked/slotStore.ts
3383
+ var swapChain = /* @__PURE__ */ new WeakMap();
3384
+ var compactStore = (store, addressOfEntry) => {
3385
+ const retired = store.slots;
3386
+ const slots = new Array();
3387
+ const index = {};
3388
+ for (const entry of retired) {
3389
+ if (entry === null || entry === void 0) continue;
3390
+ index[addressOfEntry(entry)] = slots.length;
3391
+ slots.push(entry);
3392
+ }
3393
+ store.slots = slots;
3394
+ store.index = index;
3395
+ swapChain.set(retired, store.slots);
3396
+ };
3397
+ var translateCursor = (retired, cursor, current) => {
3398
+ let array = retired;
3399
+ let position = cursor;
3400
+ while (array !== current) {
3401
+ const successor = swapChain.get(array);
3402
+ if (successor === void 0) return 0;
3403
+ let survivors = 0;
3404
+ const bound = Math.min(position, array.length);
3405
+ for (let slot = 0; slot < bound; slot += 1) {
3406
+ const entry = array[slot];
3407
+ if (entry !== null && entry !== void 0) survivors += 1;
3408
+ }
3409
+ position = survivors;
3410
+ array = successor;
3411
+ }
3412
+ return position;
3413
+ };
3414
+ var deleteFromStore = (store, addr, addressOfEntry) => {
3415
+ const slot = store.index[addr];
3416
+ if (slot === void 0) return false;
3417
+ store.slots[slot] = null;
3418
+ Reflect.deleteProperty(store.index, addr);
3419
+ store.count -= 1;
3420
+ if (store.slots.length >= 2 * store.count) {
3421
+ compactStore(store, addressOfEntry);
3422
+ }
3423
+ return true;
3424
+ };
3425
+ var clearStore = (store) => {
3426
+ store.slots = [];
3427
+ store.index = {};
3428
+ store.count = 0;
3429
+ };
3430
+
1792
3431
  // src/tracked/iterateSlots.ts
1793
3432
  function* iterateSlots(getSlots) {
1794
3433
  let slots = getSlots();
@@ -1796,8 +3435,8 @@ function* iterateSlots(getSlots) {
1796
3435
  for (; ; ) {
1797
3436
  const current = getSlots();
1798
3437
  if (current !== slots) {
3438
+ index = translateCursor(slots, index, current);
1799
3439
  slots = current;
1800
- index = 0;
1801
3440
  }
1802
3441
  if (index >= slots.length) return;
1803
3442
  const entry = slots[index];
@@ -1806,22 +3445,18 @@ function* iterateSlots(getSlots) {
1806
3445
  }
1807
3446
  }
1808
3447
 
1809
- // src/tracked/slotStore.ts
1810
- var deleteFromStore = (store, addr) => {
1811
- const slot = store.index[addr];
1812
- if (slot === void 0) return false;
1813
- store.slots[slot] = null;
1814
- Reflect.deleteProperty(store.index, addr);
1815
- store.count -= 1;
1816
- return true;
3448
+ // src/tracked/trackedMap.ts
3449
+ var EmptyMapSlotError = class extends Error {
3450
+ constructor() {
3451
+ super("opshot: TrackedMap resolved an empty slot");
3452
+ this.name = "EmptyMapSlotError";
3453
+ }
1817
3454
  };
1818
- var clearStore = (store) => {
1819
- store.slots = [];
1820
- store.index = {};
1821
- store.count = 0;
3455
+ var isObjectLike5 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
3456
+ var isStoredValue = (stored, incoming) => {
3457
+ if (Object.is(stored, incoming)) return true;
3458
+ return isObjectLike5(stored) && isObjectLike5(incoming) && isSameIdentity(stored, incoming);
1822
3459
  };
1823
-
1824
- // src/tracked/trackedMap.ts
1825
3460
  var TrackedMap = class {
1826
3461
  constructor(entries) {
1827
3462
  installBoundary();
@@ -1844,23 +3479,29 @@ var TrackedMap = class {
1844
3479
  }
1845
3480
  set(key, value) {
1846
3481
  assertMutableFacade(this, "count");
1847
- const addr = addressOf(key);
3482
+ const stored = Object.is(key, -0) ? 0 : key;
3483
+ const addr = addressOf(stored);
1848
3484
  const slot = this.index[addr];
1849
3485
  if (slot === void 0) {
1850
3486
  const newSlot = this.slots.length;
1851
- this.slots.push([key, value]);
3487
+ this.slots.push([stored, value]);
1852
3488
  this.index[addr] = newSlot;
1853
3489
  this.count += 1;
1854
3490
  } else {
1855
3491
  const pair = this.slots[slot];
1856
- if (pair === null || pair === void 0) throw new Error("opshot: TrackedMap resolved an empty slot");
3492
+ if (pair === null || pair === void 0) throw new EmptyMapSlotError();
3493
+ if (isStoredValue(pair[1], value)) return this;
1857
3494
  this.slots[slot] = [pair[0], value];
1858
3495
  }
1859
3496
  return this;
1860
3497
  }
1861
3498
  delete(key) {
1862
3499
  assertMutableFacade(this, "count");
1863
- return deleteFromStore(this, addressOf(key));
3500
+ return deleteFromStore(
3501
+ this,
3502
+ addressOf(key),
3503
+ (pair) => addressOf(pair[0])
3504
+ );
1864
3505
  }
1865
3506
  clear() {
1866
3507
  assertMutableFacade(this, "count");
@@ -1915,17 +3556,22 @@ var TrackedSet = class {
1915
3556
  }
1916
3557
  add(value) {
1917
3558
  assertMutableFacade(this, "count");
1918
- const addr = addressOf(value);
3559
+ const stored = Object.is(value, -0) ? 0 : value;
3560
+ const addr = addressOf(stored);
1919
3561
  if (this.index[addr] !== void 0) return this;
1920
3562
  const slot = this.slots.length;
1921
- this.slots.push([value]);
3563
+ this.slots.push([stored]);
1922
3564
  this.index[addr] = slot;
1923
3565
  this.count += 1;
1924
3566
  return this;
1925
3567
  }
1926
3568
  delete(value) {
1927
3569
  assertMutableFacade(this, "count");
1928
- return deleteFromStore(this, addressOf(value));
3570
+ return deleteFromStore(
3571
+ this,
3572
+ addressOf(value),
3573
+ (member) => addressOf(member[0])
3574
+ );
1929
3575
  }
1930
3576
  clear() {
1931
3577
  assertMutableFacade(this, "count");
@@ -1960,15 +3606,195 @@ Object.defineProperty(TrackedSet.prototype, Symbol.toStringTag, {
1960
3606
  writable: false
1961
3607
  });
1962
3608
 
1963
- // src/react/boundary.ts
1964
- var { refSet: refSet6, proxyStateMap: proxyStateMap7 } = unstable_getInternalStates();
1965
- var KEYS_PROPERTY2 = "k";
1966
- var HAS_KEY_PROPERTY2 = "h";
1967
- var HAS_OWN_KEY_PROPERTY2 = "o";
1968
- var ALL_OWN_KEYS_PROPERTY2 = "w";
3609
+ // src/react/dirtySinceSnapshot.ts
3610
+ var parentLiveOf = (root, path) => {
3611
+ if (path.length === 0) return void 0;
3612
+ let current = root;
3613
+ for (const segment of path.slice(0, -1)) {
3614
+ if (!isObjectLike3(current)) return void 0;
3615
+ current = Reflect.get(current, segment);
3616
+ }
3617
+ return isObjectLike3(current) ? current : void 0;
3618
+ };
3619
+ function dirtySinceSnapshot(handle, from) {
3620
+ const dirty = { edges: /* @__PURE__ */ new WeakMap(), nodes: /* @__PURE__ */ new WeakSet() };
3621
+ for (const operation of diffObjects(from, snapshot(handle.proxy.root))) {
3622
+ const path = operation.do.path;
3623
+ markDirtyPath(dirty, handle, path, parentLiveOf(handle.proxy.root, path));
3624
+ }
3625
+ return dirty;
3626
+ }
3627
+
3628
+ // src/react/propWalk.ts
3629
+ var stateKeysByContainer = /* @__PURE__ */ new WeakMap();
3630
+ var noStateKeys = /* @__PURE__ */ new Set();
3631
+ var isReactOwnNode = (value) => "$$typeof" in value || typeof Node !== "undefined" && value instanceof Node;
3632
+ var childRole = (value, writable, mode) => {
3633
+ if (typeof value !== "object" || value === null) return "skip";
3634
+ if (isReactOwnNode(value)) return "skip";
3635
+ if (mode === "nested" && !writable) return "skip";
3636
+ if (admissionLane(value) === "untracked") return "skip";
3637
+ if (isState(value)) return "state";
3638
+ if (admissionLane(value) === "tracked") return "descend";
3639
+ return "skip";
3640
+ };
3641
+ var readVerdict = (container, pass) => pass.verdicts.get(container) ?? stateKeysByContainer.get(container) ?? noStateKeys;
3642
+ var createDiscoveryPass = () => ({
3643
+ entriesByContainer: /* @__PURE__ */ new Map(),
3644
+ verdicts: /* @__PURE__ */ new Map(),
3645
+ inProgress: /* @__PURE__ */ new Set(),
3646
+ relaxable: /* @__PURE__ */ new Set()
3647
+ });
3648
+ function visitContainer(container, pass, mode) {
3649
+ if (mode === "nested" && stateKeysByContainer.has(container)) return false;
3650
+ if (pass.inProgress.has(container)) return true;
3651
+ if (pass.verdicts.has(container)) return pass.relaxable.has(container);
3652
+ pass.inProgress.add(container);
3653
+ const entries = walkDataEntries(container);
3654
+ const keys = /* @__PURE__ */ new Set();
3655
+ let dependedOnBackEdge = false;
3656
+ pass.entriesByContainer.set(container, entries);
3657
+ for (const entry of entries) {
3658
+ const role = childRole(entry.value, entry.writable, mode);
3659
+ if (role === "state") {
3660
+ keys.add(entry.key);
3661
+ continue;
3662
+ }
3663
+ if (role !== "descend") continue;
3664
+ const child = entry.value;
3665
+ if (typeof child !== "object" || child === null) continue;
3666
+ if (visitContainer(child, pass, "nested")) dependedOnBackEdge = true;
3667
+ if (readVerdict(child, pass).size > 0) keys.add(entry.key);
3668
+ }
3669
+ pass.inProgress.delete(container);
3670
+ pass.verdicts.set(container, keys);
3671
+ if (dependedOnBackEdge) pass.relaxable.add(container);
3672
+ return dependedOnBackEdge;
3673
+ }
3674
+ function relaxVerdicts(pass, entryContainer) {
3675
+ let gained = true;
3676
+ while (gained) {
3677
+ gained = false;
3678
+ for (const container of pass.relaxable) {
3679
+ const keys = pass.verdicts.get(container);
3680
+ const entries = pass.entriesByContainer.get(container);
3681
+ if (keys === void 0 || entries === void 0) continue;
3682
+ for (const entry of entries) {
3683
+ if (keys.has(entry.key)) continue;
3684
+ if (childRole(entry.value, entry.writable, container === entryContainer ? "entry" : "nested") !== "descend")
3685
+ continue;
3686
+ const child = entry.value;
3687
+ if (typeof child !== "object" || child === null) continue;
3688
+ if (readVerdict(child, pass).size === 0) continue;
3689
+ keys.add(entry.key);
3690
+ gained = true;
3691
+ }
3692
+ }
3693
+ }
3694
+ }
3695
+ var cacheNestedVerdicts = (pass, skip) => {
3696
+ for (const [visited, keys] of pass.verdicts) {
3697
+ if (visited === skip) continue;
3698
+ stateKeysByContainer.set(visited, keys);
3699
+ }
3700
+ };
3701
+ function discoverStateKeys(container) {
3702
+ const cached = stateKeysByContainer.get(container);
3703
+ if (cached !== void 0) return cached;
3704
+ if (isReactOwnNode(container)) return noStateKeys;
3705
+ if (admissionLane(container) !== "tracked") return noStateKeys;
3706
+ const pass = createDiscoveryPass();
3707
+ visitContainer(container, pass, "nested");
3708
+ relaxVerdicts(pass);
3709
+ cacheNestedVerdicts(pass);
3710
+ return pass.verdicts.get(container) ?? noStateKeys;
3711
+ }
3712
+ function substituteContainer(container, substitution, wrap, mode) {
3713
+ const rebuilt = substitution.rebuiltByContainer.get(container);
3714
+ if (rebuilt !== void 0) return rebuilt;
3715
+ let stateKeys;
3716
+ if (mode === "nested") {
3717
+ stateKeys = discoverStateKeys(container);
3718
+ } else {
3719
+ const pass = createDiscoveryPass();
3720
+ visitContainer(container, pass, "entry");
3721
+ relaxVerdicts(pass, container);
3722
+ cacheNestedVerdicts(pass, container);
3723
+ stateKeys = pass.verdicts.get(container) ?? noStateKeys;
3724
+ }
3725
+ if (stateKeys.size === 0) {
3726
+ substitution.rebuiltByContainer.set(container, container);
3727
+ return container;
3728
+ }
3729
+ const clone = Array.isArray(container) ? [] : {};
3730
+ Reflect.setPrototypeOf(clone, Reflect.getPrototypeOf(container));
3731
+ substitution.rebuiltByContainer.set(container, clone);
3732
+ const descriptors = Object.getOwnPropertyDescriptors(container);
3733
+ for (const key of stateKeys) {
3734
+ const descriptor = descriptors[key];
3735
+ if (descriptor === void 0 || !("value" in descriptor)) continue;
3736
+ const value = descriptor.value;
3737
+ const role = childRole(value, descriptor.writable === true, mode);
3738
+ if (role === "state") {
3739
+ const source = peelReadProxy(value);
3740
+ if (typeof source !== "object" || source === null) continue;
3741
+ if (!substitution.visitedSources.has(source)) {
3742
+ substitution.visitedSources.add(source);
3743
+ substitution.sources.push(source);
3744
+ }
3745
+ descriptors[key] = { ...descriptor, value: wrap(source) };
3746
+ continue;
3747
+ }
3748
+ if (role !== "descend") continue;
3749
+ if (typeof value !== "object" || value === null) continue;
3750
+ descriptors[key] = { ...descriptor, value: substituteContainer(value, substitution, wrap, "nested") };
3751
+ }
3752
+ Object.defineProperties(clone, descriptors);
3753
+ return clone;
3754
+ }
3755
+ function substituteStates(root, wrap) {
3756
+ const substitution = {
3757
+ rebuiltByContainer: /* @__PURE__ */ new Map(),
3758
+ sources: [],
3759
+ visitedSources: /* @__PURE__ */ new Set()
3760
+ };
3761
+ if (isReactOwnNode(root) || unfrozenAdmissionLane(root) !== "tracked") {
3762
+ return { props: root, sources: substitution.sources };
3763
+ }
3764
+ return { props: substituteContainer(root, substitution, wrap, "entry"), sources: substitution.sources };
3765
+ }
3766
+ var NO_SLOT = /* @__PURE__ */ Symbol("opshot.noDispatcherSlot");
3767
+ var readDispatcher = () => {
3768
+ const internals = React;
3769
+ const modern = internals.__CLIENT_INTERNALS_DO_NOT_USE_OR_WARN_USERS_THEY_CANNOT_UPGRADE;
3770
+ if (modern !== void 0) return modern.H;
3771
+ const legacy = internals.__SECRET_INTERNALS_DO_NOT_USE_OR_YOU_WILL_BE_FIRED?.ReactCurrentDispatcher;
3772
+ if (legacy !== void 0) return legacy.current;
3773
+ return NO_SLOT;
3774
+ };
3775
+ var nonRenderDispatcher;
3776
+ var learnNonRenderDispatcher = () => {
3777
+ const current = readDispatcher();
3778
+ if (current === NO_SLOT || current === null || current === void 0) return;
3779
+ nonRenderDispatcher = current;
3780
+ };
3781
+ var isRendering = () => {
3782
+ if (nonRenderDispatcher === void 0) return false;
3783
+ const current = readDispatcher();
3784
+ if (current === NO_SLOT || current === null || current === void 0) return false;
3785
+ return current !== nonRenderDispatcher;
3786
+ };
3787
+
3788
+ // src/react/readTracker.ts
3789
+ var { proxyStateMap: proxyStateMap16 } = unstable_getInternalStates();
3790
+ var KEYS_PROPERTY = "k";
3791
+ var HAS_KEY_PROPERTY = "h";
3792
+ var HAS_OWN_KEY_PROPERTY = "o";
3793
+ var ALL_OWN_KEYS_PROPERTY = "w";
1969
3794
  var isObjectLike6 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
1970
- var isLiveProxy = (value) => proxyStateMap7.has(value);
1971
- var getProxyTarget = (liveProxy) => proxyStateMap7.get(liveProxy)?.[0] ?? liveProxy;
3795
+ var isLiveProxy = (value) => proxyStateMap16.has(value);
3796
+ var getProxyTarget = (writeProxy) => proxyStateMap16.get(writeProxy)?.[0] ?? writeProxy;
3797
+ var getProxyVersion = (writeProxy) => getVersion(writeProxy) ?? 0;
1972
3798
  var getUsage = (affected, target) => {
1973
3799
  let used = affected.get(target);
1974
3800
  if (used === void 0) {
@@ -1997,260 +3823,173 @@ var getPrototypeMethod = (target, prop) => {
1997
3823
  }
1998
3824
  return void 0;
1999
3825
  };
2000
- var wrapperBoundMethods = /* @__PURE__ */ new WeakMap();
2001
- var bindMethodToWrapper = (wrapper, method) => {
2002
- let methods = wrapperBoundMethods.get(wrapper);
2003
- if (methods === void 0) {
2004
- methods = /* @__PURE__ */ new WeakMap();
2005
- wrapperBoundMethods.set(wrapper, methods);
3826
+ var UnregisteredReadTrackerError = class extends Error {
3827
+ constructor() {
3828
+ super("opshot: readsIntersectDirty received an unregistered tracker");
3829
+ this.name = "UnregisteredReadTrackerError";
2006
3830
  }
2007
- const existing = methods.get(method);
2008
- if (existing !== void 0) return existing;
2009
- const bound = Function.prototype.bind.call(method, wrapper);
2010
- methods.set(method, bound);
2011
- return bound;
2012
3831
  };
2013
- function createBoundary() {
3832
+ var trackerPartitions = /* @__PURE__ */ new WeakMap();
3833
+ var recordedKeysOf = (used) => {
3834
+ const keySets = new Array();
3835
+ if (used[KEYS_PROPERTY] !== void 0) keySets.push(used[KEYS_PROPERTY]);
3836
+ if (used[HAS_KEY_PROPERTY] !== void 0) keySets.push(used[HAS_KEY_PROPERTY]);
3837
+ if (used[HAS_OWN_KEY_PROPERTY] !== void 0) keySets.push(used[HAS_OWN_KEY_PROPERTY]);
3838
+ return keySets;
3839
+ };
3840
+ function readsIntersectDirty(tracker, dirty) {
3841
+ const partitions = trackerPartitions.get(tracker);
3842
+ if (partitions === void 0) throw new UnregisteredReadTrackerError();
3843
+ for (const partition of partitions.values()) {
3844
+ for (const [writeProxy, used] of partition.affected) {
3845
+ const raw = getProxyTarget(writeProxy);
3846
+ const edges = dirty.edges.get(raw);
3847
+ for (const keys of recordedKeysOf(used)) {
3848
+ for (const key of keys) {
3849
+ if (edges?.has(key) === true) return true;
3850
+ }
3851
+ }
3852
+ if (used[ALL_OWN_KEYS_PROPERTY] === true && dirty.nodes.has(raw)) return true;
3853
+ }
3854
+ for (const writeProxy of partition.identityReads) {
3855
+ if (partition.affected.has(writeProxy)) continue;
3856
+ if (dirty.nodes.has(getProxyTarget(writeProxy))) return true;
3857
+ }
3858
+ }
3859
+ return false;
3860
+ }
3861
+ function createReadTracker() {
2014
3862
  const partitions = /* @__PURE__ */ new Map();
2015
- const targets = /* @__PURE__ */ new Map();
2016
3863
  let afterRender = false;
2017
- const getPartition = (sourceProxy) => {
2018
- let partition = partitions.get(sourceProxy);
3864
+ let releasing = false;
3865
+ const getPartition = (writeProxy) => {
3866
+ let partition = partitions.get(writeProxy);
2019
3867
  if (partition === void 0) {
2020
3868
  partition = {
2021
- sourceProxy,
2022
- previousRootSnapshot: void 0,
2023
3869
  affected: /* @__PURE__ */ new Map(),
2024
- baselines: /* @__PURE__ */ new Map(),
3870
+ identityReads: /* @__PURE__ */ new Set(),
2025
3871
  proxyCache: /* @__PURE__ */ new WeakMap()
2026
3872
  };
2027
- partitions.set(sourceProxy, partition);
3873
+ partitions.set(writeProxy, partition);
2028
3874
  }
2029
3875
  return partition;
2030
3876
  };
2031
- const trackUsage = (partition, liveProxy) => afterRender ? {} : getUsage(partition.affected, liveProxy);
2032
- const ensureBaseline = (partition, liveProxy) => {
2033
- if (afterRender) return snapshot(liveProxy);
2034
- const existing = partition.baselines.get(liveProxy);
2035
- if (existing !== void 0) return existing;
2036
- const baseline = snapshot(liveProxy);
2037
- partition.baselines.set(liveProxy, baseline);
2038
- return baseline;
2039
- };
2040
- const ensureRootBaseline = (partition) => {
2041
- if (afterRender) return partition.previousRootSnapshot ?? snapshot(partition.sourceProxy);
2042
- if (partition.previousRootSnapshot === void 0) {
2043
- partition.previousRootSnapshot = snapshot(partition.sourceProxy);
2044
- partition.baselines.set(partition.sourceProxy, partition.previousRootSnapshot);
2045
- }
2046
- return partition.previousRootSnapshot;
2047
- };
2048
- const registerTarget = (liveProxy) => {
2049
- if (targets.has(liveProxy)) return;
2050
- targets.set(liveProxy, {
2051
- lastIdentitySnapshot: snapshot(liveProxy)
2052
- });
3877
+ const shouldRecord = () => !afterRender || isRendering();
3878
+ const trackUsage = (partition, writeProxy) => shouldRecord() ? getUsage(partition.affected, writeProxy) : {};
3879
+ const recordIdentity = (partition, value) => {
3880
+ if (!shouldRecord()) return;
3881
+ if (isObjectLike6(value) && isLiveProxy(value)) partition.identityReads.add(value);
2053
3882
  };
2054
- const wrapLive = (liveProxy, partition) => {
2055
- ensureBaseline(partition, liveProxy);
2056
- registerTarget(liveProxy);
2057
- const cached = partition.proxyCache.get(liveProxy);
2058
- if (cached !== void 0) return cached;
2059
- const storageTarget = getProxyTarget(liveProxy);
2060
- const wrapperBox = {};
3883
+ const toReadProxy = (writeProxy, partition) => {
3884
+ const currentVersion = getProxyVersion(writeProxy);
3885
+ const cached = partition.proxyCache.get(writeProxy);
3886
+ if (cached?.version === currentVersion) return cached.readProxy;
3887
+ const target = getProxyTarget(writeProxy);
3888
+ const readProxyBox = {};
3889
+ const boundMethods = /* @__PURE__ */ new WeakMap();
3890
+ const bindMethodToReadProxy = (readProxy2, method) => {
3891
+ const existing = boundMethods.get(method);
3892
+ if (existing !== void 0) return existing;
3893
+ const bound = Function.prototype.bind.call(method, readProxy2);
3894
+ boundMethods.set(method, bound);
3895
+ return bound;
3896
+ };
2061
3897
  const handler = {
2062
3898
  get(_target, prop) {
2063
- ensureRootBaseline(partition);
2064
- const value = Reflect.get(liveProxy, prop, liveProxy);
2065
- const wrapper2 = wrapperBox.current;
2066
- const used = trackUsage(partition, liveProxy);
2067
- recordKey(used, KEYS_PROPERTY2, prop);
2068
- ensureBaseline(partition, liveProxy);
3899
+ const readProxy2 = readProxyBox.current;
3900
+ const value = Reflect.get(writeProxy, prop, readProxy2 ?? writeProxy);
3901
+ const used = trackUsage(partition, writeProxy);
3902
+ recordKey(used, KEYS_PROPERTY, prop);
3903
+ recordIdentity(partition, value);
2069
3904
  if (typeof value === "function") {
2070
- const method = getPrototypeMethod(storageTarget, prop);
2071
- if (method !== void 0 && value === method && wrapper2 !== void 0) {
2072
- return bindMethodToWrapper(wrapper2, method);
3905
+ const method = getPrototypeMethod(target, prop);
3906
+ if (method !== void 0 && value === method && readProxy2 !== void 0) {
3907
+ return bindMethodToReadProxy(readProxy2, method);
2073
3908
  }
2074
3909
  }
2075
3910
  if (!isObjectLike6(value)) return value;
2076
3911
  if (typeof value === "function") return value;
2077
- if (refSet6.has(value)) return value;
2078
3912
  if (!isLiveProxy(value)) return value;
2079
- return wrapLive(value, partition);
3913
+ return toReadProxy(value, partition);
2080
3914
  },
2081
3915
  has(_target, prop) {
2082
- const used = trackUsage(partition, liveProxy);
2083
- recordKey(used, HAS_KEY_PROPERTY2, prop);
2084
- ensureBaseline(partition, liveProxy);
2085
- return Reflect.has(liveProxy, prop);
3916
+ const used = trackUsage(partition, writeProxy);
3917
+ recordKey(used, HAS_KEY_PROPERTY, prop);
3918
+ return Reflect.has(writeProxy, prop);
2086
3919
  },
2087
3920
  getOwnPropertyDescriptor(_target, prop) {
2088
- const used = trackUsage(partition, liveProxy);
2089
- recordKey(used, HAS_OWN_KEY_PROPERTY2, prop);
2090
- ensureBaseline(partition, liveProxy);
2091
- return Reflect.getOwnPropertyDescriptor(liveProxy, prop);
3921
+ const used = trackUsage(partition, writeProxy);
3922
+ recordKey(used, HAS_OWN_KEY_PROPERTY, prop);
3923
+ return Reflect.getOwnPropertyDescriptor(writeProxy, prop);
2092
3924
  },
2093
3925
  ownKeys() {
2094
- const used = trackUsage(partition, liveProxy);
2095
- used[ALL_OWN_KEYS_PROPERTY2] = true;
2096
- ensureBaseline(partition, liveProxy);
2097
- return Reflect.ownKeys(liveProxy);
3926
+ const used = trackUsage(partition, writeProxy);
3927
+ used[ALL_OWN_KEYS_PROPERTY] = true;
3928
+ return Reflect.ownKeys(writeProxy);
2098
3929
  },
2099
3930
  set(_target, prop, value) {
2100
- ensureRootBaseline(partition);
2101
- return Reflect.set(liveProxy, prop, value, liveProxy);
3931
+ return Reflect.set(writeProxy, prop, value, writeProxy);
2102
3932
  },
2103
3933
  deleteProperty(_target, prop) {
2104
- ensureRootBaseline(partition);
2105
- return Reflect.deleteProperty(liveProxy, prop);
3934
+ return Reflect.deleteProperty(writeProxy, prop);
2106
3935
  }
2107
3936
  };
2108
- const wrapper = new Proxy(/* @__PURE__ */ Object.create(null), handler);
2109
- wrapperBox.current = wrapper;
2110
- registerWrapperTarget(wrapper, liveProxy);
2111
- partition.proxyCache.set(liveProxy, wrapper);
2112
- return wrapper;
3937
+ const readProxy = new Proxy(writeProxy, handler);
3938
+ readProxyBox.current = readProxy;
3939
+ registerReadProxyTarget(readProxy, writeProxy);
3940
+ partition.proxyCache.set(writeProxy, { readProxy, version: currentVersion });
3941
+ return readProxy;
2113
3942
  };
2114
- return {
2115
- wrap(sourceProxy) {
2116
- if (!isLiveProxy(sourceProxy)) {
2117
- throw new Error("opshot: Boundary.wrap requires a live Valtio proxy");
2118
- }
2119
- const partition = getPartition(sourceProxy);
2120
- ensureRootBaseline(partition);
2121
- return wrapLive(sourceProxy, partition);
2122
- },
2123
- readsChanged(sourceProxy) {
2124
- const partition = partitions.get(sourceProxy);
2125
- if (partition?.previousRootSnapshot === void 0) return false;
2126
- if (partition.affected.size === 0) return false;
2127
- const translated = /* @__PURE__ */ new WeakMap();
2128
- for (const [live, usage] of partition.affected) {
2129
- const baseline = partition.baselines.get(live);
2130
- if (baseline === void 0) {
2131
- throw new Error("opshot: missing baseline snapshot for affected live proxy");
2132
- }
2133
- translated.set(baseline, usage);
3943
+ const tracker = {
3944
+ wrap(writeProxy) {
3945
+ if (!isLiveProxy(writeProxy)) {
3946
+ throw new Error("opshot: ReadTracker.wrap requires a write proxy");
2134
3947
  }
2135
- const nextRoot = snapshot(sourceProxy);
2136
- return isChanged(partition.previousRootSnapshot, nextRoot, translated, /* @__PURE__ */ new WeakMap());
3948
+ const partition = getPartition(writeProxy);
3949
+ return toReadProxy(writeProxy, partition);
2137
3950
  },
2138
3951
  captureReads() {
3952
+ learnNonRenderDispatcher();
2139
3953
  afterRender = true;
2140
3954
  },
2141
- evictChangedTargets() {
2142
- for (const [liveProxy, entry] of targets) {
2143
- const current = snapshot(liveProxy);
2144
- if (current !== entry.lastIdentitySnapshot) {
2145
- for (const partition of partitions.values()) {
2146
- partition.proxyCache.delete(liveProxy);
2147
- }
2148
- }
2149
- entry.lastIdentitySnapshot = current;
2150
- }
2151
- },
2152
3955
  resetReads() {
2153
3956
  afterRender = false;
2154
3957
  for (const partition of partitions.values()) {
2155
- partition.previousRootSnapshot = void 0;
2156
3958
  partition.affected.clear();
2157
- partition.baselines.clear();
3959
+ partition.identityReads.clear();
2158
3960
  }
2159
3961
  },
2160
- advanceBaselines() {
2161
- for (const partition of partitions.values()) {
2162
- for (const liveProxy of [...partition.baselines.keys()]) {
2163
- partition.baselines.set(liveProxy, snapshot(liveProxy));
2164
- }
2165
- partition.previousRootSnapshot = snapshot(partition.sourceProxy);
2166
- partition.baselines.set(partition.sourceProxy, partition.previousRootSnapshot);
2167
- }
3962
+ retain() {
3963
+ releasing = false;
3964
+ },
3965
+ dispose() {
3966
+ releasing = true;
3967
+ void Promise.resolve().then(() => {
3968
+ if (!releasing) return;
3969
+ releasing = false;
3970
+ partitions.clear();
3971
+ });
2168
3972
  }
2169
3973
  };
3974
+ trackerPartitions.set(tracker, partitions);
3975
+ return tracker;
2170
3976
  }
3977
+ var useCommitEffect = typeof document === "undefined" ? useEffect : useLayoutEffect;
2171
3978
 
2172
3979
  // src/react/scope.tsx
2173
- var isPlainPrototype = (value) => {
2174
- const prototype = Reflect.getPrototypeOf(value);
2175
- return prototype === Object.prototype || prototype === null;
2176
- };
2177
- var assertSubstitutableContainer = (container) => {
2178
- if (isPlainPrototype(container)) return;
2179
- const kind = classifyValue(container);
2180
- if (kind === "plain" || kind === "plainArray" || kind === "cleanClass") return;
2181
- const className = constructorName(container.constructor);
2182
- if (kind === "arraySubclass") {
2183
- throw new Error(
2184
- `opshot: scope found a state inside ${className}, an array subclass whose prototype can't survive substitution. Move the state to a plain array, or ignore() the ${className}.`
2185
- );
2186
- }
2187
- const hidden = kind === "privateClass" ? "private fields" : "internal slots";
2188
- throw new Error(
2189
- `opshot: scope found a state inside ${className}, whose ${hidden} can't survive substitution. Move the state to a plain container, or ignore() the ${className}.`
2190
- );
2191
- };
2192
- function findStatePaths(value, maxDepth, path = [], paths = [], ancestors = /* @__PURE__ */ new Set()) {
2193
- if (isState(value)) {
2194
- paths.push(path);
2195
- return paths;
2196
- }
2197
- if (value === null || typeof value !== "object") return paths;
2198
- if ("$$typeof" in value) return paths;
2199
- if (ancestors.has(value)) return paths;
2200
- if (path.length >= maxDepth) return paths;
2201
- ancestors.add(value);
2202
- if (Array.isArray(value)) {
2203
- const foundCount = paths.length;
2204
- value.forEach((item, index) => {
2205
- findStatePaths(item, maxDepth, [...path, index], paths, ancestors);
2206
- });
2207
- if (paths.length > foundCount) assertSubstitutableContainer(value);
2208
- } else {
2209
- const foundCount = paths.length;
2210
- for (const [key, propertyValue] of Object.entries(value)) {
2211
- if (key.startsWith("__react")) continue;
2212
- findStatePaths(propertyValue, maxDepth, [...path, key], paths, ancestors);
3980
+ var sourcesKey = (sources) => `${sources.length}:${sources.map((source) => addressOf(source)).join(",")}`;
3981
+ var uniqueHandlesOf = (nodes) => {
3982
+ const unique = new Array();
3983
+ const seen = /* @__PURE__ */ new Set();
3984
+ for (const node of nodes) {
3985
+ for (const handle of handlesOf(node)) {
3986
+ if (seen.has(handle)) continue;
3987
+ seen.add(handle);
3988
+ unique.push(handle);
2213
3989
  }
2214
- if (paths.length > foundCount) assertSubstitutableContainer(value);
2215
- }
2216
- ancestors.delete(value);
2217
- return paths;
2218
- }
2219
- function getAtPath(object, path) {
2220
- let current = object;
2221
- for (const segment of path) {
2222
- if (current === null || current === void 0) return void 0;
2223
- current = current[segment];
2224
- }
2225
- return current;
2226
- }
2227
- function setAtPath(object, path, value) {
2228
- if (path.length === 0) return value;
2229
- const head = path[0];
2230
- if (head === void 0) throw new Error("setAtPath: non-empty path yielded no head segment");
2231
- const tail = path.slice(1);
2232
- const current = object[head];
2233
- const updated = setAtPath(current, tail, value);
2234
- if (Array.isArray(object)) {
2235
- const clone2 = [...object];
2236
- clone2[head] = updated;
2237
- return clone2;
2238
- }
2239
- const prototype = Reflect.getPrototypeOf(object);
2240
- if (prototype === Object.prototype || prototype === null) return { ...object, [head]: updated };
2241
- const descriptor = Object.getOwnPropertyDescriptor(object, head);
2242
- if (descriptor?.get !== void 0 || descriptor?.set !== void 0) {
2243
- const className = constructorName(object.constructor);
2244
- throw new Error(
2245
- `opshot: scope found a state behind the accessor "${String(head)}" on ${className}, which can't survive substitution. Move the state to a plain container, or ignore() the ${className}.`
2246
- );
2247
3990
  }
2248
- const clone = Object.create(prototype);
2249
- Object.defineProperties(clone, Object.getOwnPropertyDescriptors(object));
2250
- clone[head] = updated;
2251
- return clone;
2252
- }
2253
- var sourcesKey = (sources) => `${sources.length}:${sources.map((source) => addressOf(source)).join(",")}`;
3991
+ return unique;
3992
+ };
2254
3993
  var arePropsEqual = (previous, next) => {
2255
3994
  const previousRecord = previous;
2256
3995
  const nextRecord = next;
@@ -2267,99 +4006,112 @@ var arePropsEqual = (previous, next) => {
2267
4006
  }
2268
4007
  return true;
2269
4008
  };
2270
- function scope(Component, options) {
2271
- const maxDepth = options?.maxDepth ?? 10;
4009
+ function scope(Component) {
2272
4010
  const Scoped = (props) => {
2273
- const boundaryRef = useRef(void 0);
2274
- boundaryRef.current ?? (boundaryRef.current = createBoundary());
2275
- const boundary = boundaryRef.current;
4011
+ const readTrackerRef = useRef(void 0);
4012
+ const currentHandlesRef = useRef([]);
4013
+ const [gapSnapshots] = useState(() => /* @__PURE__ */ new WeakMap());
4014
+ readTrackerRef.current ??= createReadTracker();
4015
+ const readTracker = readTrackerRef.current;
2276
4016
  const [, bump] = useReducer((value) => value + 1, 0);
2277
- boundary.resetReads();
2278
- const paths = findStatePaths(props, maxDepth);
2279
- const sources = [];
2280
- let nextProps = props;
2281
- let changed = false;
2282
- for (const path of paths) {
2283
- const value = getAtPath(props, path);
2284
- if (!isState(value)) continue;
2285
- const source = unwrapWrapper(value);
2286
- if (typeof source !== "object" || source === null) continue;
2287
- const wrapped = boundary.wrap(source);
2288
- if (!sources.includes(source)) sources.push(source);
2289
- if (wrapped !== value) {
2290
- nextProps = setAtPath(nextProps, path, wrapped);
2291
- changed = true;
2292
- }
4017
+ readTracker.resetReads();
4018
+ const { props: renderedProps, sources } = substituteStates(props, (source) => readTracker.wrap(source));
4019
+ const uniqueHandles = uniqueHandlesOf(sources);
4020
+ for (const handle of uniqueHandles) {
4021
+ gapSnapshots.set(handle, snapshot(handle.proxy.root));
2293
4022
  }
2294
- const renderedProps = changed ? nextProps : props;
2295
- const versionsAtRender = sources.map((source) => getVersion(source));
2296
- useEffect(() => {
2297
- boundary.captureReads();
4023
+ useCommitEffect(() => {
4024
+ currentHandlesRef.current = uniqueHandles;
4025
+ readTracker.captureReads();
2298
4026
  });
2299
4027
  useEffect(() => {
2300
- const unsubscribes = sources.map(
2301
- (source) => subscribe(
2302
- source,
2303
- () => {
2304
- boundary.evictChangedTargets();
2305
- if (boundary.readsChanged(source)) bump();
2306
- else boundary.advanceBaselines();
2307
- },
2308
- true
2309
- )
4028
+ readTracker.retain();
4029
+ return () => readTracker.dispose();
4030
+ }, [readTracker]);
4031
+ useEffect(() => {
4032
+ let cancelled = false;
4033
+ const subscribedHandles = uniqueHandlesOf(sources);
4034
+ for (const handle of subscribedHandles) {
4035
+ const from = gapSnapshots.get(handle);
4036
+ if (from !== void 0 && readsIntersectDirty(readTracker, dirtySinceSnapshot(handle, from))) bump();
4037
+ }
4038
+ const unsubscribes = subscribedHandles.map(
4039
+ (handle) => subscribe2(handle.proxy.root, () => {
4040
+ if (cancelled) return;
4041
+ const dirty = handle.lastDirty;
4042
+ if (dirty !== void 0 && readsIntersectDirty(readTracker, dirty)) bump();
4043
+ })
2310
4044
  );
2311
4045
  return () => {
4046
+ cancelled = true;
4047
+ const currentHandles = new Set(currentHandlesRef.current);
4048
+ for (const handle of subscribedHandles) {
4049
+ if (currentHandles.has(handle)) continue;
4050
+ gapSnapshots.set(handle, snapshot(handle.proxy.root));
4051
+ }
2312
4052
  for (const unsubscribe of unsubscribes) unsubscribe();
2313
4053
  };
2314
- }, [sourcesKey(sources), boundary]);
2315
- useEffect(() => {
2316
- let shouldBump = false;
2317
- for (let index = 0; index < sources.length; index += 1) {
2318
- const source = sources[index];
2319
- const captured = versionsAtRender[index];
2320
- if (source === void 0 || captured === void 0) continue;
2321
- if (getVersion(source) !== captured) {
2322
- boundary.evictChangedTargets();
2323
- if (boundary.readsChanged(source)) shouldBump = true;
2324
- }
2325
- }
2326
- if (shouldBump) bump();
2327
- });
4054
+ }, [sourcesKey(sources), readTracker]);
2328
4055
  return createElement(Component, renderedProps);
2329
4056
  };
2330
4057
  const baseName = Component.displayName ?? Component.name;
2331
4058
  Scoped.displayName = `scope(${typeof baseName === "string" && baseName !== "" ? baseName : "Component"})`;
2332
4059
  return memo(Scoped, arePropsEqual);
2333
4060
  }
2334
- function useGroup() {
2335
- return useState(() => createGroup())[0];
4061
+ function useGroup(parent) {
4062
+ return useState(() => createGroup(parent))[0];
2336
4063
  }
2337
- function useMutableState(properties, group) {
2338
- const [{ proxy: proxy2, boundary }] = useState(() => ({
2339
- proxy: createMutableState(properties, group),
2340
- boundary: createBoundary()
2341
- }));
4064
+ var isObjectLike7 = (value) => value !== null && (typeof value === "object" || typeof value === "function");
4065
+ function useMutableState(properties, options) {
4066
+ const [{ writeProxy, readTracker }] = useState(() => {
4067
+ const initial = typeof properties === "function" ? properties() : properties;
4068
+ return {
4069
+ writeProxy: createMutableState(initial, options),
4070
+ readTracker: createReadTracker()
4071
+ };
4072
+ });
2342
4073
  const [, bump] = useReducer((value) => value + 1, 0);
2343
- const versionAtRender = getVersion(proxy2);
2344
- boundary.resetReads();
2345
- const wrapper = boundary.wrap(proxy2);
2346
- useEffect(() => {
2347
- boundary.captureReads();
4074
+ const currentHandlesRef = useRef([]);
4075
+ const [gapSnapshots] = useState(() => /* @__PURE__ */ new WeakMap());
4076
+ const uniqueHandles = isObjectLike7(writeProxy) ? handlesOf(writeProxy) : [];
4077
+ readTracker.resetReads();
4078
+ const readProxy = isObjectLike7(writeProxy) ? readTracker.wrap(writeProxy) : writeProxy;
4079
+ for (const handle of uniqueHandles) {
4080
+ gapSnapshots.set(handle, snapshot(handle.proxy.root));
4081
+ }
4082
+ useCommitEffect(() => {
4083
+ currentHandlesRef.current = uniqueHandles;
4084
+ readTracker.captureReads();
2348
4085
  });
2349
4086
  useEffect(() => {
2350
- const onSignal = () => {
2351
- boundary.evictChangedTargets();
2352
- if (boundary.readsChanged(proxy2)) bump();
2353
- else boundary.advanceBaselines();
2354
- };
2355
- return subscribe(proxy2, onSignal, true);
2356
- }, [proxy2, boundary]);
4087
+ readTracker.retain();
4088
+ return () => readTracker.dispose();
4089
+ }, [readTracker]);
2357
4090
  useEffect(() => {
2358
- if (getVersion(proxy2) === versionAtRender) return;
2359
- boundary.evictChangedTargets();
2360
- if (boundary.readsChanged(proxy2)) bump();
2361
- });
2362
- return wrapper;
4091
+ let cancelled = false;
4092
+ const subscribedHandles = isObjectLike7(writeProxy) ? handlesOf(writeProxy) : [];
4093
+ for (const handle of subscribedHandles) {
4094
+ const from = gapSnapshots.get(handle);
4095
+ if (from !== void 0 && readsIntersectDirty(readTracker, dirtySinceSnapshot(handle, from))) bump();
4096
+ }
4097
+ const unsubscribes = subscribedHandles.map(
4098
+ (handle) => subscribe2(handle.proxy.root, () => {
4099
+ if (cancelled) return;
4100
+ const dirty = handle.lastDirty;
4101
+ if (dirty !== void 0 && readsIntersectDirty(readTracker, dirty)) bump();
4102
+ })
4103
+ );
4104
+ return () => {
4105
+ cancelled = true;
4106
+ const currentHandles = new Set(currentHandlesRef.current);
4107
+ for (const handle of subscribedHandles) {
4108
+ if (currentHandles.has(handle)) continue;
4109
+ gapSnapshots.set(handle, snapshot(handle.proxy.root));
4110
+ }
4111
+ for (const unsubscribe of unsubscribes) unsubscribe();
4112
+ };
4113
+ }, [writeProxy, readTracker]);
4114
+ return readProxy;
2363
4115
  }
2364
4116
 
2365
- export { TrackedDate, TrackedMap, TrackedSet, applyOps, createChannel, createGroup, createMutableState, diffSnapshots, identify, ignore, isSameIdentity, isState, scope, subscribe2 as subscribe, transact, unsafeTrack, useGroup, useMutableState };
4117
+ export { TrackedDate, TrackedMap, TrackedSet, applyOperations, createChannel, createGroup, createMutableState, diffObjects, identify, ignore, isSameIdentity, isState, scope, subscribe2 as subscribe, transact, unsafeTrack, useGroup, useMutableState };