footprintjs 9.23.0 → 9.23.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,9 +10,71 @@
10
10
  * found on element proxies, then the same root on nested and terminal ones).
11
11
  * So every read trap resolves through the CURRENT value and falls back to the
12
12
  * captured object only when the path is gone or no longer holds an object.
13
+ *
14
+ * The READ side of every object proxy lives here — {@link liveObject},
15
+ * {@link liveGetTrap}, {@link liveInspectionTraps}, and the ONE per-member
16
+ * proxy cache {@link cachedMember} (9.23.2); the WRITE side is
17
+ * `writeTraps.ts`. A factory only wires them (9.23.1).
13
18
  */
14
19
  Object.defineProperty(exports, "__esModule", { value: true });
15
- exports.liveInspectionTraps = exports.liveObject = void 0;
20
+ exports.liveInspectionTraps = exports.liveGetTrap = exports.liveObject = exports.cachedMember = exports.MemberCache = void 0;
21
+ const jsonProjection_js_1 = require("./jsonProjection.js");
22
+ /**
23
+ * A proxy per member NAME under one parent proxy, validated by the raw
24
+ * member's identity. The map is allocated on the FIRST insert: an element
25
+ * proxy over `{ id, n }` reads only primitives and must not pay for one
26
+ * (10,000 of them in the naive re-read loop — measured, `bench/nested-reads.ts`).
27
+ */
28
+ class MemberCache {
29
+ entries;
30
+ /** The proxy cached under `prop`, if it was built over exactly this raw `value`. */
31
+ hit(prop, value) {
32
+ const cached = this.entries?.get(prop);
33
+ return cached !== undefined && cached.ref === value ? cached.proxy : undefined;
34
+ }
35
+ remember(prop, value, proxy) {
36
+ (this.entries ??= new Map()).set(prop, { ref: value, proxy });
37
+ }
38
+ /** Forget `prop` — a write replaced its value, so the next read must build over the new one. */
39
+ delete(prop) {
40
+ this.entries?.delete(prop);
41
+ }
42
+ }
43
+ exports.MemberCache = MemberCache;
44
+ /**
45
+ * WHY the cache: `o.arr === o.arr` must hold within a stage, and
46
+ * `for (i < N) s.k.arr[i]` must build ONE array proxy — whose element cache
47
+ * then serves every index — not N (the 9.22.0 perf review, finding 4: the
48
+ * nested get trap built a fresh array proxy, with a fresh empty element
49
+ * cache, on every `.arr`). The top-level scope has cached its child proxies
50
+ * this way since before 9.22.0; this is that leaf, shared by all four.
51
+ *
52
+ * Validated by IDENTITY, invalidated by replacement: every write through a
53
+ * proxy rebuilds the containers on its path (`structuralWrite.setInPath`),
54
+ * so after `s.k.arr[0].n = 1` the raw `arr` is a new array, the ref check
55
+ * misses, and the next read builds a proxy over the NEW value. A hit can
56
+ * never be stale — every proxy reads live (`liveGetTrap`), so the cached one
57
+ * and a fresh one answer the same.
58
+ *
59
+ * Keyed by NAME under THIS parent, never by the raw value alone: a diamond
60
+ * (one array under `k.a` and `k.b`) needs two proxies, each bound to its own
61
+ * path and sink. Only what `build` actually WRAPPED is kept — a member handed
62
+ * back raw (a `Date`, a frozen object, a cycle edge) is not worth an entry.
63
+ * `build` is the caller's stable child step, not a closure made per read: a
64
+ * hit allocates nothing, and a primitive member skips the cache entirely.
65
+ */
66
+ function cachedMember(cache, prop, value, build, segments) {
67
+ if (value === null || typeof value !== 'object')
68
+ return build(value, [...segments, prop]);
69
+ const hit = cache.hit(prop, value);
70
+ if (hit !== undefined)
71
+ return hit;
72
+ const proxy = build(value, [...segments, prop]);
73
+ if (proxy !== value)
74
+ cache.remember(prop, value, proxy);
75
+ return proxy;
76
+ }
77
+ exports.cachedMember = cachedMember;
16
78
  /** The object at `segments` under the current root, or `raw` when it is gone. */
17
79
  function liveObject(raw, current) {
18
80
  return current !== null && typeof current === 'object' && !Array.isArray(current)
@@ -20,6 +82,29 @@ function liveObject(raw, current) {
20
82
  : raw;
21
83
  }
22
84
  exports.liveObject = liveObject;
85
+ /**
86
+ * WHY one get trap: the names a proxy answers ITSELF (promise/matcher guards,
87
+ * `constructor`, and the JSON law — serializing a proxied value equals
88
+ * serializing the raw one, `jsonProjection.ts`) must be the same three lines
89
+ * on every object proxy; any other member is handed to `child` with its full
90
+ * path — through the parent's {@link cachedMember} — and only THAT step
91
+ * differs per factory (the cycle policy).
92
+ */
93
+ function liveGetTrap(live, segments, child, members) {
94
+ return (_target, prop) => {
95
+ const raw = live();
96
+ if (typeof prop === 'symbol')
97
+ return raw[prop];
98
+ if (prop === 'then' || prop === 'asymmetricMatch')
99
+ return undefined;
100
+ if (prop === 'constructor')
101
+ return Object;
102
+ if (prop === 'toJSON')
103
+ return () => (0, jsonProjection_js_1.toJSONView)(raw);
104
+ return cachedMember(members, prop, raw[prop], child, segments);
105
+ };
106
+ }
107
+ exports.liveGetTrap = liveGetTrap;
23
108
  /**
24
109
  * The three inspection traps (`in`, `Object.keys`, descriptors) answered from
25
110
  * the live object. The one Proxy invariant that could bite — a non-extensible
@@ -45,4 +130,4 @@ function liveInspectionTraps(live) {
45
130
  };
46
131
  }
47
132
  exports.liveInspectionTraps = liveInspectionTraps;
48
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGl2ZVZpZXcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3JlYWN0aXZlL2xpdmVWaWV3LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7R0FXRzs7O0FBRUgsaUZBQWlGO0FBQ2pGLFNBQWdCLFVBQVUsQ0FBQyxHQUE0QixFQUFFLE9BQWdCO0lBQ3ZFLE9BQU8sT0FBTyxLQUFLLElBQUksSUFBSSxPQUFPLE9BQU8sS0FBSyxRQUFRLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQztRQUMvRSxDQUFDLENBQUUsT0FBbUM7UUFDdEMsQ0FBQyxDQUFDLEdBQUcsQ0FBQztBQUNWLENBQUM7QUFKRCxnQ0FJQztBQUVEOzs7Ozs7O0dBT0c7QUFDSCxTQUFnQixtQkFBbUIsQ0FDakMsSUFBa0I7SUFFbEIsT0FBTztRQUNMLEdBQUcsQ0FBQyxNQUFNLEVBQUUsSUFBSTtZQUNkLE9BQU8sT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQzFFLENBQUM7UUFDRCxPQUFPLENBQUMsTUFBTTtZQUNaLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDeEUsQ0FBQztRQUNELHdCQUF3QixDQUFDLE1BQU0sRUFBRSxJQUFJO1lBQ25DLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQztnQkFBRSxPQUFPLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDdkYsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLHdCQUF3QixDQUFDLElBQUksRUFBRSxFQUFFLElBQUksQ0FBQyxDQUFDO1lBQ2pFLE9BQU8sVUFBVSxJQUFJLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxDQUFDLENBQUMsRUFBRSxHQUFHLFVBQVUsRUFBRSxZQUFZLEVBQUUsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQztRQUNyRyxDQUFDO0tBQ0YsQ0FBQztBQUNKLENBQUM7QUFoQkQsa0RBZ0JDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiByZWFjdGl2ZS9saXZlVmlldyDigJQgd2hhdCBhIHByb3h5IHN0YW5kcyBmb3IsIEFTIElUIFNUQU5EUyBOT1cuXG4gKlxuICogRXZlcnkgd3JpdGUgdGhyb3VnaCB0aGUgdHlwZWQgc2NvcGUgcmVidWlsZHMgdGhlIHJvb3QgaW1tdXRhYmx5XG4gKiAoYHN0cnVjdHVyYWxXcml0ZS5zZXRJblBhdGhgLCBhIGZyZXNoIG1lcmdlKSwgc28gdGhlIG9iamVjdCBhIHByb3h5IHdhc1xuICogY3JlYXRlZCBvdmVyIGlzIHRoZSBQUkUtd3JpdGUgdmFsdWUgZm9yIGV2ZXIgYWZ0ZXIuIEEgaGVsZCBwcm94eSB0aGF0IHJlYWRcbiAqIGZyb20gaXQgc2F3IGl0cyBvd24gd3JpdGVzIHZhbmlzaDogYG8ueCArPSAxYCB0d2ljZSBnYXZlIDIsIGBvLmIgPSBvLmEgKiAxMGBcbiAqIHVzZWQgdGhlIG9sZCBgYWAsIGAneCcgaW4gb2Agd2FzIGZhbHNlIHJpZ2h0IGFmdGVyIGBvLnggPSAxYCAoOS4yMi4wIOKAlCBmaXJzdFxuICogZm91bmQgb24gZWxlbWVudCBwcm94aWVzLCB0aGVuIHRoZSBzYW1lIHJvb3Qgb24gbmVzdGVkIGFuZCB0ZXJtaW5hbCBvbmVzKS5cbiAqIFNvIGV2ZXJ5IHJlYWQgdHJhcCByZXNvbHZlcyB0aHJvdWdoIHRoZSBDVVJSRU5UIHZhbHVlIGFuZCBmYWxscyBiYWNrIHRvIHRoZVxuICogY2FwdHVyZWQgb2JqZWN0IG9ubHkgd2hlbiB0aGUgcGF0aCBpcyBnb25lIG9yIG5vIGxvbmdlciBob2xkcyBhbiBvYmplY3QuXG4gKi9cblxuLyoqIFRoZSBvYmplY3QgYXQgYHNlZ21lbnRzYCB1bmRlciB0aGUgY3VycmVudCByb290LCBvciBgcmF3YCB3aGVuIGl0IGlzIGdvbmUuICovXG5leHBvcnQgZnVuY3Rpb24gbGl2ZU9iamVjdChyYXc6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBjdXJyZW50OiB1bmtub3duKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gY3VycmVudCAhPT0gbnVsbCAmJiB0eXBlb2YgY3VycmVudCA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoY3VycmVudClcbiAgICA/IChjdXJyZW50IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVxuICAgIDogcmF3O1xufVxuXG4vKipcbiAqIFRoZSB0aHJlZSBpbnNwZWN0aW9uIHRyYXBzIChgaW5gLCBgT2JqZWN0LmtleXNgLCBkZXNjcmlwdG9ycykgYW5zd2VyZWQgZnJvbVxuICogdGhlIGxpdmUgb2JqZWN0LiBUaGUgb25lIFByb3h5IGludmFyaWFudCB0aGF0IGNvdWxkIGJpdGUg4oCUIGEgbm9uLWV4dGVuc2libGVcbiAqIHRhcmdldCBtdXN0IHJlcG9ydCBleGFjdGx5IGl0cyBvd24ga2V5cywgYW5kIGEgcHJvcGVydHkgdGhlIHRhcmdldCBsYWNrc1xuICogbXVzdCBiZSByZXBvcnRlZCBjb25maWd1cmFibGUg4oCUIGlzIGhvbm91cmVkOiB0aGUgYWxsb3dsaXN0IGFscmVhZHkgcmVmdXNlc1xuICogZnJvemVuIGFuZCBzZWFsZWQgdmFsdWVzLCBzbyB0aGUgYHByZXZlbnRFeHRlbnNpb25zYC1vbmx5IGNvcm5lciBhbnN3ZXJzXG4gKiBmcm9tIHRoZSB0YXJnZXQsIGFuZCBhIGxpdmUgZGVzY3JpcHRvciBpcyBhbHdheXMgcmVwb3J0ZWQgY29uZmlndXJhYmxlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbGl2ZUluc3BlY3Rpb25UcmFwcyhcbiAgbGl2ZTogKCkgPT4gb2JqZWN0LFxuKTogUGljazxQcm94eUhhbmRsZXI8b2JqZWN0PiwgJ2hhcycgfCAnb3duS2V5cycgfCAnZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yJz4ge1xuICByZXR1cm4ge1xuICAgIGhhcyh0YXJnZXQsIHByb3ApIHtcbiAgICAgIHJldHVybiBSZWZsZWN0LmhhcyhPYmplY3QuaXNFeHRlbnNpYmxlKHRhcmdldCkgPyBsaXZlKCkgOiB0YXJnZXQsIHByb3ApO1xuICAgIH0sXG4gICAgb3duS2V5cyh0YXJnZXQpIHtcbiAgICAgIHJldHVybiBSZWZsZWN0Lm93bktleXMoT2JqZWN0LmlzRXh0ZW5zaWJsZSh0YXJnZXQpID8gbGl2ZSgpIDogdGFyZ2V0KTtcbiAgICB9LFxuICAgIGdldE93blByb3BlcnR5RGVzY3JpcHRvcih0YXJnZXQsIHByb3ApIHtcbiAgICAgIGlmICghT2JqZWN0LmlzRXh0ZW5zaWJsZSh0YXJnZXQpKSByZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcih0YXJnZXQsIHByb3ApO1xuICAgICAgY29uc3QgZGVzY3JpcHRvciA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IobGl2ZSgpLCBwcm9wKTtcbiAgICAgIHJldHVybiBkZXNjcmlwdG9yICYmICFkZXNjcmlwdG9yLmNvbmZpZ3VyYWJsZSA/IHsgLi4uZGVzY3JpcHRvciwgY29uZmlndXJhYmxlOiB0cnVlIH0gOiBkZXNjcmlwdG9yO1xuICAgIH0sXG4gIH07XG59XG4iXX0=
133
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGl2ZVZpZXcuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvbGliL3JlYWN0aXZlL2xpdmVWaWV3LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7Ozs7Ozs7Ozs7Ozs7OztHQWdCRzs7O0FBRUgsMkRBQWlEO0FBRWpEOzs7OztHQUtHO0FBQ0gsTUFBYSxXQUFXO0lBQ2QsT0FBTyxDQUFnRDtJQUUvRCxvRkFBb0Y7SUFDcEYsR0FBRyxDQUFDLElBQVksRUFBRSxLQUFhO1FBQzdCLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3ZDLE9BQU8sTUFBTSxLQUFLLFNBQVMsSUFBSSxNQUFNLENBQUMsR0FBRyxLQUFLLEtBQUssQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2pGLENBQUM7SUFFRCxRQUFRLENBQUMsSUFBWSxFQUFFLEtBQWEsRUFBRSxLQUFjO1FBQ2xELENBQUMsSUFBSSxDQUFDLE9BQU8sS0FBSyxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxFQUFFLEdBQUcsRUFBRSxLQUFLLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztJQUNoRSxDQUFDO0lBRUQsZ0dBQWdHO0lBQ2hHLE1BQU0sQ0FBQyxJQUFZO1FBQ2pCLElBQUksQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQzdCLENBQUM7Q0FDRjtBQWpCRCxrQ0FpQkM7QUFFRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBcUJHO0FBQ0gsU0FBZ0IsWUFBWSxDQUMxQixLQUFrQixFQUNsQixJQUFZLEVBQ1osS0FBYyxFQUNkLEtBQWtELEVBQ2xELFFBQTJCO0lBRTNCLElBQUksS0FBSyxLQUFLLElBQUksSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRO1FBQUUsT0FBTyxLQUFLLENB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LEVBQUUsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDO1FBQ3JHLENBQUM7S0FDRixDQUFDO0FBQ0osQ0FBQztBQWhCRCxrREFnQkMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIHJlYWN0aXZlL2xpdmVWaWV3IOKAlCB3aGF0IGEgcHJveHkgc3RhbmRzIGZvciwgQVMgSVQgU1RBTkRTIE5PVy5cbiAqXG4gKiBFdmVyeSB3cml0ZSB0aHJvdWdoIHRoZSB0eXBlZCBzY29wZSByZWJ1aWxkcyB0aGUgcm9vdCBpbW11dGFibHlcbiAqIChgc3RydWN0dXJhbFdyaXRlLnNldEluUGF0aGAsIGEgZnJlc2ggbWVyZ2UpLCBzbyB0aGUgb2JqZWN0IGEgcHJveHkgd2FzXG4gKiBjcmVhdGVkIG92ZXIgaXMgdGhlIFBSRS13cml0ZSB2YWx1ZSBmb3IgZXZlciBhZnRlci4gQSBoZWxkIHByb3h5IHRoYXQgcmVhZFxuICogZnJvbSBpdCBzYXcgaXRzIG93biB3cml0ZXMgdmFuaXNoOiBgby54ICs9IDFgIHR3aWNlIGdhdmUgMiwgYG8uYiA9IG8uYSAqIDEwYFxuICogdXNlZCB0aGUgb2xkIGBhYCwgYCd4JyBpbiBvYCB3YXMgZmFsc2UgcmlnaHQgYWZ0ZXIgYG8ueCA9IDFgICg5LjIyLjAg4oCUIGZpcnN0XG4gKiBmb3VuZCBvbiBlbGVtZW50IHByb3hpZXMsIHRoZW4gdGhlIHNhbWUgcm9vdCBvbiBuZXN0ZWQgYW5kIHRlcm1pbmFsIG9uZXMpLlxuICogU28gZXZlcnkgcmVhZCB0cmFwIHJlc29sdmVzIHRocm91Z2ggdGhlIENVUlJFTlQgdmFsdWUgYW5kIGZhbGxzIGJhY2sgdG8gdGhlXG4gKiBjYXB0dXJlZCBvYmplY3Qgb25seSB3aGVuIHRoZSBwYXRoIGlzIGdvbmUgb3Igbm8gbG9uZ2VyIGhvbGRzIGFuIG9iamVjdC5cbiAqXG4gKiBUaGUgUkVBRCBzaWRlIG9mIGV2ZXJ5IG9iamVjdCBwcm94eSBsaXZlcyBoZXJlIOKAlCB7QGxpbmsgbGl2ZU9iamVjdH0sXG4gKiB7QGxpbmsgbGl2ZUdldFRyYXB9LCB7QGxpbmsgbGl2ZUluc3BlY3Rpb25UcmFwc30sIGFuZCB0aGUgT05FIHBlci1tZW1iZXJcbiAqIHByb3h5IGNhY2hlIHtAbGluayBjYWNoZWRNZW1iZXJ9ICg5LjIzLjIpOyB0aGUgV1JJVEUgc2lkZSBpc1xuICogYHdyaXRlVHJhcHMudHNgLiBBIGZhY3Rvcnkgb25seSB3aXJlcyB0aGVtICg5LjIzLjEpLlxuICovXG5cbmltcG9ydCB7IHRvSlNPTlZpZXcgfSBmcm9tICcuL2pzb25Qcm9qZWN0aW9uLmpzJztcblxuLyoqXG4gKiBBIHByb3h5IHBlciBtZW1iZXIgTkFNRSB1bmRlciBvbmUgcGFyZW50IHByb3h5LCB2YWxpZGF0ZWQgYnkgdGhlIHJhd1xuICogbWVtYmVyJ3MgaWRlbnRpdHkuIFRoZSBtYXAgaXMgYWxsb2NhdGVkIG9uIHRoZSBGSVJTVCBpbnNlcnQ6IGFuIGVsZW1lbnRcbiAqIHByb3h5IG92ZXIgYHsgaWQsIG4gfWAgcmVhZHMgb25seSBwcmltaXRpdmVzIGFuZCBtdXN0IG5vdCBwYXkgZm9yIG9uZVxuICogKDEwLDAwMCBvZiB0aGVtIGluIHRoZSBuYWl2ZSByZS1yZWFkIGxvb3Ag4oCUIG1lYXN1cmVkLCBgYmVuY2gvbmVzdGVkLXJlYWRzLnRzYCkuXG4gKi9cbmV4cG9ydCBjbGFzcyBNZW1iZXJDYWNoZSB7XG4gIHByaXZhdGUgZW50cmllcz86IE1hcDxzdHJpbmcsIHsgcmVmOiBvYmplY3Q7IHByb3h5OiB1bmtub3duIH0+O1xuXG4gIC8qKiBUaGUgcHJveHkgY2FjaGVkIHVuZGVyIGBwcm9wYCwgaWYgaXQgd2FzIGJ1aWx0IG92ZXIgZXhhY3RseSB0aGlzIHJhdyBgdmFsdWVgLiAqL1xuICBoaXQocHJvcDogc3RyaW5nLCB2YWx1ZTogb2JqZWN0KTogdW5rbm93biB7XG4gICAgY29uc3QgY2FjaGVkID0gdGhpcy5lbnRyaWVzPy5nZXQocHJvcCk7XG4gICAgcmV0dXJuIGNhY2hlZCAhPT0gdW5kZWZpbmVkICYmIGNhY2hlZC5yZWYgPT09IHZhbHVlID8gY2FjaGVkLnByb3h5IDogdW5kZWZpbmVkO1xuICB9XG5cbiAgcmVtZW1iZXIocHJvcDogc3RyaW5nLCB2YWx1ZTogb2JqZWN0LCBwcm94eTogdW5rbm93bik6IHZvaWQge1xuICAgICh0aGlzLmVudHJpZXMgPz89IG5ldyBNYXAoKSkuc2V0KHByb3AsIHsgcmVmOiB2YWx1ZSwgcHJveHkgfSk7XG4gIH1cblxuICAvKiogRm9yZ2V0IGBwcm9wYCDigJQgYSB3cml0ZSByZXBsYWNlZCBpdHMgdmFsdWUsIHNvIHRoZSBuZXh0IHJlYWQgbXVzdCBidWlsZCBvdmVyIHRoZSBuZXcgb25lLiAqL1xuICBkZWxldGUocHJvcDogc3RyaW5nKTogdm9pZCB7XG4gICAgdGhpcy5lbnRyaWVzPy5kZWxldGUocHJvcCk7XG4gIH1cbn1cblxuLyoqXG4gKiBXSFkgdGhlIGNhY2hlOiBgby5hcnIgPT09IG8uYXJyYCBtdXN0IGhvbGQgd2l0aGluIGEgc3RhZ2UsIGFuZFxuICogYGZvciAoaSA8IE4pIHMuay5hcnJbaV1gIG11c3QgYnVpbGQgT05FIGFycmF5IHByb3h5IOKAlCB3aG9zZSBlbGVtZW50IGNhY2hlXG4gKiB0aGVuIHNlcnZlcyBldmVyeSBpbmRleCDigJQgbm90IE4gKHRoZSA5LjIyLjAgcGVyZiByZXZpZXcsIGZpbmRpbmcgNDogdGhlXG4gKiBuZXN0ZWQgZ2V0IHRyYXAgYnVpbHQgYSBmcmVzaCBhcnJheSBwcm94eSwgd2l0aCBhIGZyZXNoIGVtcHR5IGVsZW1lbnRcbiAqIGNhY2hlLCBvbiBldmVyeSBgLmFycmApLiBUaGUgdG9wLWxldmVsIHNjb3BlIGhhcyBjYWNoZWQgaXRzIGNoaWxkIHByb3hpZXNcbiAqIHRoaXMgd2F5IHNpbmNlIGJlZm9yZSA5LjIyLjA7IHRoaXMgaXMgdGhhdCBsZWFmLCBzaGFyZWQgYnkgYWxsIGZvdXIuXG4gKlxuICogVmFsaWRhdGVkIGJ5IElERU5USVRZLCBpbnZhbGlkYXRlZCBieSByZXBsYWNlbWVudDogZXZlcnkgd3JpdGUgdGhyb3VnaCBhXG4gKiBwcm94eSByZWJ1aWxkcyB0aGUgY29udGFpbmVycyBvbiBpdHMgcGF0aCAoYHN0cnVjdHVyYWxXcml0ZS5zZXRJblBhdGhgKSxcbiAqIHNvIGFmdGVyIGBzLmsuYXJyWzBdLm4gPSAxYCB0aGUgcmF3IGBhcnJgIGlzIGEgbmV3IGFycmF5LCB0aGUgcmVmIGNoZWNrXG4gKiBtaXNzZXMsIGFuZCB0aGUgbmV4dCByZWFkIGJ1aWxkcyBhIHByb3h5IG92ZXIgdGhlIE5FVyB2YWx1ZS4gQSBoaXQgY2FuXG4gKiBuZXZlciBiZSBzdGFsZSDigJQgZXZlcnkgcHJveHkgcmVhZHMgbGl2ZSAoYGxpdmVHZXRUcmFwYCksIHNvIHRoZSBjYWNoZWQgb25lXG4gKiBhbmQgYSBmcmVzaCBvbmUgYW5zd2VyIHRoZSBzYW1lLlxuICpcbiAqIEtleWVkIGJ5IE5BTUUgdW5kZXIgVEhJUyBwYXJlbnQsIG5ldmVyIGJ5IHRoZSByYXcgdmFsdWUgYWxvbmU6IGEgZGlhbW9uZFxuICogKG9uZSBhcnJheSB1bmRlciBgay5hYCBhbmQgYGsuYmApIG5lZWRzIHR3byBwcm94aWVzLCBlYWNoIGJvdW5kIHRvIGl0cyBvd25cbiAqIHBhdGggYW5kIHNpbmsuIE9ubHkgd2hhdCBgYnVpbGRgIGFjdHVhbGx5IFdSQVBQRUQgaXMga2VwdCDigJQgYSBtZW1iZXIgaGFuZGVkXG4gKiBiYWNrIHJhdyAoYSBgRGF0ZWAsIGEgZnJvemVuIG9iamVjdCwgYSBjeWNsZSBlZGdlKSBpcyBub3Qgd29ydGggYW4gZW50cnkuXG4gKiBgYnVpbGRgIGlzIHRoZSBjYWxsZXIncyBzdGFibGUgY2hpbGQgc3RlcCwgbm90IGEgY2xvc3VyZSBtYWRlIHBlciByZWFkOiBhXG4gKiBoaXQgYWxsb2NhdGVzIG5vdGhpbmcsIGFuZCBhIHByaW1pdGl2ZSBtZW1iZXIgc2tpcHMgdGhlIGNhY2hlIGVudGlyZWx5LlxuICovXG5leHBvcnQgZnVuY3Rpb24gY2FjaGVkTWVtYmVyKFxuICBjYWNoZTogTWVtYmVyQ2FjaGUsXG4gIHByb3A6IHN0cmluZyxcbiAgdmFsdWU6IHVua25vd24sXG4gIGJ1aWxkOiAodmFsdWU6IHVua25vd24sIHBhdGg6IHN0cmluZ1tdKSA9PiB1bmtub3duLFxuICBzZWdtZW50czogcmVhZG9ubHkgc3RyaW5nW10sXG4pOiB1bmtub3duIHtcbiAgaWYgKHZhbHVlID09PSBudWxsIHx8IHR5cGVvZiB2YWx1ZSAhPT0gJ29iamVjdCcpIHJldHVybiBidWlsZCh2YWx1ZSwgWy4uLnNlZ21lbnRzLCBwcm9wXSk7XG4gIGNvbnN0IGhpdCA9IGNhY2hlLmhpdChwcm9wLCB2YWx1ZSk7XG4gIGlmIChoaXQgIT09IHVuZGVmaW5lZCkgcmV0dXJuIGhpdDtcbiAgY29uc3QgcHJveHkgPSBidWlsZCh2YWx1ZSwgWy4uLnNlZ21lbnRzLCBwcm9wXSk7XG4gIGlmIChwcm94eSAhPT0gdmFsdWUpIGNhY2hlLnJlbWVtYmVyKHByb3AsIHZhbHVlLCBwcm94eSk7XG4gIHJldHVybiBwcm94eTtcbn1cblxuLyoqIFRoZSBvYmplY3QgYXQgYHNlZ21lbnRzYCB1bmRlciB0aGUgY3VycmVudCByb290LCBvciBgcmF3YCB3aGVuIGl0IGlzIGdvbmUuICovXG5leHBvcnQgZnVuY3Rpb24gbGl2ZU9iamVjdChyYXc6IFJlY29yZDxzdHJpbmcsIHVua25vd24+LCBjdXJyZW50OiB1bmtub3duKTogUmVjb3JkPHN0cmluZywgdW5rbm93bj4ge1xuICByZXR1cm4gY3VycmVudCAhPT0gbnVsbCAmJiB0eXBlb2YgY3VycmVudCA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoY3VycmVudClcbiAgICA/IChjdXJyZW50IGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KVxuICAgIDogcmF3O1xufVxuXG4vKipcbiAqIFdIWSBvbmUgZ2V0IHRyYXA6IHRoZSBuYW1lcyBhIHByb3h5IGFuc3dlcnMgSVRTRUxGIChwcm9taXNlL21hdGNoZXIgZ3VhcmRzLFxuICogYGNvbnN0cnVjdG9yYCwgYW5kIHRoZSBKU09OIGxhdyDigJQgc2VyaWFsaXppbmcgYSBwcm94aWVkIHZhbHVlIGVxdWFsc1xuICogc2VyaWFsaXppbmcgdGhlIHJhdyBvbmUsIGBqc29uUHJvamVjdGlvbi50c2ApIG11c3QgYmUgdGhlIHNhbWUgdGhyZWUgbGluZXNcbiAqIG9uIGV2ZXJ5IG9iamVjdCBwcm94eTsgYW55IG90aGVyIG1lbWJlciBpcyBoYW5kZWQgdG8gYGNoaWxkYCB3aXRoIGl0cyBmdWxsXG4gKiBwYXRoIOKAlCB0aHJvdWdoIHRoZSBwYXJlbnQncyB7QGxpbmsgY2FjaGVkTWVtYmVyfSDigJQgYW5kIG9ubHkgVEhBVCBzdGVwXG4gKiBkaWZmZXJzIHBlciBmYWN0b3J5ICh0aGUgY3ljbGUgcG9saWN5KS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpdmVHZXRUcmFwKFxuICBsaXZlOiAoKSA9PiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgc2VnbWVudHM6IHJlYWRvbmx5IHN0cmluZ1tdLFxuICBjaGlsZDogKHZhbHVlOiB1bmtub3duLCBwYXRoOiBzdHJpbmdbXSkgPT4gdW5rbm93bixcbiAgbWVtYmVyczogTWVtYmVyQ2FjaGUsXG4pOiBQcm94eUhhbmRsZXI8b2JqZWN0PlsnZ2V0J10ge1xuICByZXR1cm4gKF90YXJnZXQsIHByb3ApID0+IHtcbiAgICBjb25zdCByYXcgPSBsaXZlKCk7XG4gICAgaWYgKHR5cGVvZiBwcm9wID09PSAnc3ltYm9sJykgcmV0dXJuIChyYXcgYXMgYW55KVtwcm9wXTtcbiAgICBpZiAocHJvcCA9PT0gJ3RoZW4nIHx8IHByb3AgPT09ICdhc3ltbWV0cmljTWF0Y2gnKSByZXR1cm4gdW5kZWZpbmVkO1xuICAgIGlmIChwcm9wID09PSAnY29uc3RydWN0b3InKSByZXR1cm4gT2JqZWN0O1xuICAgIGlmIChwcm9wID09PSAndG9KU09OJykgcmV0dXJuICgpID0+IHRvSlNPTlZpZXcocmF3KTtcbiAgICByZXR1cm4gY2FjaGVkTWVtYmVyKG1lbWJlcnMsIHByb3AsIHJhd1twcm9wXSwgY2hpbGQsIHNlZ21lbnRzKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBUaGUgdGhyZWUgaW5zcGVjdGlvbiB0cmFwcyAoYGluYCwgYE9iamVjdC5rZXlzYCwgZGVzY3JpcHRvcnMpIGFuc3dlcmVkIGZyb21cbiAqIHRoZSBsaXZlIG9iamVjdC4gVGhlIG9uZSBQcm94eSBpbnZhcmlhbnQgdGhhdCBjb3VsZCBiaXRlIOKAlCBhIG5vbi1leHRlbnNpYmxlXG4gKiB0YXJnZXQgbXVzdCByZXBvcnQgZXhhY3RseSBpdHMgb3duIGtleXMsIGFuZCBhIHByb3BlcnR5IHRoZSB0YXJnZXQgbGFja3NcbiAqIG11c3QgYmUgcmVwb3J0ZWQgY29uZmlndXJhYmxlIOKAlCBpcyBob25vdXJlZDogdGhlIGFsbG93bGlzdCBhbHJlYWR5IHJlZnVzZXNcbiAqIGZyb3plbiBhbmQgc2VhbGVkIHZhbHVlcywgc28gdGhlIGBwcmV2ZW50RXh0ZW5zaW9uc2Atb25seSBjb3JuZXIgYW5zd2Vyc1xuICogZnJvbSB0aGUgdGFyZ2V0LCBhbmQgYSBsaXZlIGRlc2NyaXB0b3IgaXMgYWx3YXlzIHJlcG9ydGVkIGNvbmZpZ3VyYWJsZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGxpdmVJbnNwZWN0aW9uVHJhcHMoXG4gIGxpdmU6ICgpID0+IG9iamVjdCxcbik6IFBpY2s8UHJveHlIYW5kbGVyPG9iamVjdD4sICdoYXMnIHwgJ293bktleXMnIHwgJ2dldE93blByb3BlcnR5RGVzY3JpcHRvcic+IHtcbiAgcmV0dXJuIHtcbiAgICBoYXModGFyZ2V0LCBwcm9wKSB7XG4gICAgICByZXR1cm4gUmVmbGVjdC5oYXMoT2JqZWN0LmlzRXh0ZW5zaWJsZSh0YXJnZXQpID8gbGl2ZSgpIDogdGFyZ2V0LCBwcm9wKTtcbiAgICB9LFxuICAgIG93bktleXModGFyZ2V0KSB7XG4gICAgICByZXR1cm4gUmVmbGVjdC5vd25LZXlzKE9iamVjdC5pc0V4dGVuc2libGUodGFyZ2V0KSA/IGxpdmUoKSA6IHRhcmdldCk7XG4gICAgfSxcbiAgICBnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBwcm9wKSB7XG4gICAgICBpZiAoIU9iamVjdC5pc0V4dGVuc2libGUodGFyZ2V0KSkgcmV0dXJuIE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodGFyZ2V0LCBwcm9wKTtcbiAgICAgIGNvbnN0IGRlc2NyaXB0b3IgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKGxpdmUoKSwgcHJvcCk7XG4gICAgICByZXR1cm4gZGVzY3JpcHRvciAmJiAhZGVzY3JpcHRvci5jb25maWd1cmFibGUgPyB7IC4uLmRlc2NyaXB0b3IsIGNvbmZpZ3VyYWJsZTogdHJ1ZSB9IDogZGVzY3JpcHRvcjtcbiAgICB9LFxuICB9O1xufVxuIl19
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+ /**
3
+ * reactive/writeTraps — where a proxy's writes LAND, and the two traps that
4
+ * send them there.
5
+ *
6
+ * Every object proxy in this folder (nested, terminal, element) intercepts
7
+ * the same three things — a property set, a property delete, and an array
8
+ * mutation somewhere below it — and differs only in where the write goes:
9
+ * a nested/terminal proxy commits under a TOP-LEVEL KEY (an object write as
10
+ * `merge` of a patch, an array write or a delete as `set` of the rebuilt
11
+ * root); an element proxy commits the WHOLE OWNING ARRAY back through the
12
+ * array proxy's own callback. That difference is a {@link WriteSink}; the
13
+ * traps are written once over it (9.23.1 — the 9.22.0 stale-read bug was
14
+ * fixed in one copy of these traps and then found again in the other two).
15
+ */
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.sinkDeleteTrap = exports.sinkSetTrap = exports.elementSink = exports.rootKeySink = void 0;
18
+ const pathOps_js_1 = require("../memory/pathOps.js");
19
+ const pathBuilder_js_1 = require("./pathBuilder.js");
20
+ const structuralWrite_js_1 = require("./structuralWrite.js");
21
+ /**
22
+ * WHY: a write below a top-level key has TWO verbs (reactive/README.md, law
23
+ * 3) — an object leaf is a `merge` of a nested patch, an array leaf or a
24
+ * delete rebuilds the root immutably and commits a `set` of the key. Only the
25
+ * sink knows that; the traps do not. Every write drops the key's cached child
26
+ * proxy (`cache`), so the next read is built over the new value.
27
+ */
28
+ function rootKeySink(target, readSilent, rootKey, cache) {
29
+ return new RootKeySink(target, readSilent, rootKey, cache);
30
+ }
31
+ exports.rootKeySink = rootKeySink;
32
+ /** One allocation per top-level read miss (the methods live on the prototype). */
33
+ class RootKeySink {
34
+ target;
35
+ readSilent;
36
+ rootKey;
37
+ cache;
38
+ constructor(target, readSilent, rootKey, cache) {
39
+ this.target = target;
40
+ this.readSilent = readSilent;
41
+ this.rootKey = rootKey;
42
+ this.cache = cache;
43
+ }
44
+ /** An empty path is the key's own value — `nativeGet(v, [])` would return it unchanged, so the walk is skipped. */
45
+ readAt(path) {
46
+ const root = this.readSilent(this.rootKey);
47
+ return path.length === 0 ? root : (0, pathOps_js_1.nativeGet)(root, path);
48
+ }
49
+ put(path, value) {
50
+ if (!Array.isArray(value))
51
+ this.target.updateValue(this.rootKey, (0, pathBuilder_js_1.buildNestedPatch)(path, value));
52
+ else
53
+ this.target.setValue(this.rootKey, path.length === 0 ? value : (0, structuralWrite_js_1.setInPath)(this.readAt([]), path, value));
54
+ this.cache.delete(this.rootKey);
55
+ }
56
+ remove(path) {
57
+ this.target.setValue(this.rootKey, (0, structuralWrite_js_1.deleteInPath)(this.readAt([]), path));
58
+ this.cache.delete(this.rootKey);
59
+ }
60
+ }
61
+ /**
62
+ * WHY: a write inside an array element is an array write — it rebuilds the
63
+ * owning array immutably and hands the WHOLE new array to the array proxy's
64
+ * commit, the funnel `push` already uses. `path` is measured from the
65
+ * element; `[]` is the element slot itself.
66
+ */
67
+ function elementSink(getCurrent, commit, index) {
68
+ return new ElementSink(getCurrent, commit, index);
69
+ }
70
+ exports.elementSink = elementSink;
71
+ /** One allocation per element proxy (the methods live on the prototype) — a 10k-element loop builds 10k of these. */
72
+ class ElementSink {
73
+ getCurrent;
74
+ commit;
75
+ index;
76
+ constructor(getCurrent, commit, index) {
77
+ this.getCurrent = getCurrent;
78
+ this.commit = commit;
79
+ this.index = index;
80
+ }
81
+ readAt(path) {
82
+ return readInElement(this.getCurrent, this.index, path);
83
+ }
84
+ put(path, value) {
85
+ replaceInElement(this.getCurrent, this.commit, this.index, path, value);
86
+ }
87
+ remove(path) {
88
+ removeInElement(this.getCurrent, this.commit, this.index, path);
89
+ }
90
+ }
91
+ /** The value at `path` inside element `index`, as it stands NOW (read-your-writes). */
92
+ function readInElement(getCurrent, index, path) {
93
+ const element = getCurrent()[index];
94
+ return path.length === 0 ? element : (0, pathOps_js_1.nativeGet)(element, path);
95
+ }
96
+ /** A copy of the array with `value` at `path` inside element `index`; a gone element has nothing to write into. */
97
+ function replaceInElement(getCurrent, commit, index, path, value) {
98
+ const next = [...getCurrent()];
99
+ if (index >= next.length)
100
+ return;
101
+ next[index] = path.length === 0 ? value : (0, structuralWrite_js_1.setInPath)(next[index], path, value);
102
+ commit(next);
103
+ }
104
+ /** A copy of the array with the key at `path` inside element `index` removed. */
105
+ function removeInElement(getCurrent, commit, index, path) {
106
+ const next = [...getCurrent()];
107
+ if (index >= next.length)
108
+ return;
109
+ next[index] = (0, structuralWrite_js_1.deleteInPath)(next[index], path);
110
+ commit(next);
111
+ }
112
+ /**
113
+ * WHY one set trap: the assigned value is unwrapped HERE (landmine 1 — the
114
+ * JSON round-trip applies to what the caller handed in, never to the
115
+ * surrounding state) and handed to the sink at the proxy's path plus the key.
116
+ */
117
+ function sinkSetTrap(sink, segments) {
118
+ return (_target, prop, value) => {
119
+ if (typeof prop !== 'string')
120
+ return true;
121
+ sink.put([...segments, prop], (0, structuralWrite_js_1.unwrapProxy)(value));
122
+ return true;
123
+ };
124
+ }
125
+ exports.sinkSetTrap = sinkSetTrap;
126
+ /**
127
+ * WHY one delete trap: `merge` cannot express a removal (a patch of
128
+ * `undefined` reads as absent), so a delete always rebuilds through the sink.
129
+ */
130
+ function sinkDeleteTrap(sink, segments) {
131
+ return (_target, prop) => {
132
+ if (typeof prop !== 'string')
133
+ return true;
134
+ sink.remove([...segments, prop]);
135
+ return true;
136
+ };
137
+ }
138
+ exports.sinkDeleteTrap = sinkDeleteTrap;
139
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoid3JpdGVUcmFwcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvcmVhY3RpdmUvd3JpdGVUcmFwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7Ozs7Ozs7Ozs7R0FhRzs7O0FBRUgscURBQWlEO0FBRWpELHFEQUFvRDtBQUNwRCw2REFBNEU7QUFzQjVFOzs7Ozs7R0FNRztBQUNILFNBQWdCLFdBQVcsQ0FDekIsTUFBcUIsRUFDckIsVUFBb0MsRUFDcEMsT0FBZSxFQUNmLEtBQWtDO0lBRWxDLE9BQU8sSUFBSSxXQUFXLENBQUMsTUFBTSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLENBQUM7QUFDN0QsQ0FBQztBQVBELGtDQU9DO0FBRUQsa0ZBQWtGO0FBQ2xGLE1BQU0sV0FBVztJQUVJO0lBQ0E7SUFDQTtJQUNBO0lBSm5CLFlBQ21CLE1BQXFCLEVBQ3JCLFVBQW9DLEVBQ3BDLE9BQWUsRUFDZixLQUFrQztRQUhsQyxXQUFNLEdBQU4sTUFBTSxDQUFlO1FBQ3JCLGVBQVUsR0FBVixVQUFVLENBQTBCO1FBQ3BDLFlBQU8sR0FBUCxPQUFPLENBQVE7UUFDZixVQUFLLEdBQUwsS0FBSyxDQUE2QjtJQUNsRCxDQUFDO0lBRUosbUhBQW1IO0lBQ25ILE1BQU0sQ0FBQyxJQUF1QjtRQUM1QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMzQyxPQUFPLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUEsc0JBQVMsRUFBQyxJQUFJLEVBQUUsSUFBZ0IsQ0FBQyxDQUFDO0lBQ3RFLENBQUM7SUFFRCxHQUFHLENBQUMsSUFBdUIsRUFBRSxLQUFjO1FBQ3pDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQztZQUFFLElBQUksQ0FBQyxNQUFN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QyxDQUFDO1FBQ2pDLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQyxDQUFDO0FBQ0osQ0FBQztBQU5ELHdDQU1DIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiByZWFjdGl2ZS93cml0ZVRyYXBzIOKAlCB3aGVyZSBhIHByb3h5J3Mgd3JpdGVzIExBTkQsIGFuZCB0aGUgdHdvIHRyYXBzIHRoYXRcbiAqIHNlbmQgdGhlbSB0aGVyZS5cbiAqXG4gKiBFdmVyeSBvYmplY3QgcHJveHkgaW4gdGhpcyBmb2xkZXIgKG5lc3RlZCwgdGVybWluYWwsIGVsZW1lbnQpIGludGVyY2VwdHNcbiAqIHRoZSBzYW1lIHRocmVlIHRoaW5ncyDigJQgYSBwcm9wZXJ0eSBzZXQsIGEgcHJvcGVydHkgZGVsZXRlLCBhbmQgYW4gYXJyYXlcbiAqIG11dGF0aW9uIHNvbWV3aGVyZSBiZWxvdyBpdCDigJQgYW5kIGRpZmZlcnMgb25seSBpbiB3aGVyZSB0aGUgd3JpdGUgZ29lczpcbiAqIGEgbmVzdGVkL3Rlcm1pbmFsIHByb3h5IGNvbW1pdHMgdW5kZXIgYSBUT1AtTEVWRUwgS0VZIChhbiBvYmplY3Qgd3JpdGUgYXNcbiAqIGBtZXJnZWAgb2YgYSBwYXRjaCwgYW4gYXJyYXkgd3JpdGUgb3IgYSBkZWxldGUgYXMgYHNldGAgb2YgdGhlIHJlYnVpbHRcbiAqIHJvb3QpOyBhbiBlbGVtZW50IHByb3h5IGNvbW1pdHMgdGhlIFdIT0xFIE9XTklORyBBUlJBWSBiYWNrIHRocm91Z2ggdGhlXG4gKiBhcnJheSBwcm94eSdzIG93biBjYWxsYmFjay4gVGhhdCBkaWZmZXJlbmNlIGlzIGEge0BsaW5rIFdyaXRlU2lua307IHRoZVxuICogdHJhcHMgYXJlIHdyaXR0ZW4gb25jZSBvdmVyIGl0ICg5LjIzLjEg4oCUIHRoZSA5LjIyLjAgc3RhbGUtcmVhZCBidWcgd2FzXG4gKiBmaXhlZCBpbiBvbmUgY29weSBvZiB0aGVzZSB0cmFwcyBhbmQgdGhlbiBmb3VuZCBhZ2FpbiBpbiB0aGUgb3RoZXIgdHdvKS5cbiAqL1xuXG5pbXBvcnQgeyBuYXRpdmVHZXQgfSBmcm9tICcuLi9tZW1vcnkvcGF0aE9wcy5qcyc7XG5pbXBvcnQgdHlwZSB7IE1lbWJlckNhY2hlIH0gZnJvbSAnLi9saXZlVmlldy5qcyc7XG5pbXBvcnQgeyBidWlsZE5lc3RlZFBhdGNoIH0gZnJvbSAnLi9wYXRoQnVpbGRlci5qcyc7XG5pbXBvcnQgeyBkZWxldGVJblBhdGgsIHNldEluUGF0aCwgdW53cmFwUHJveHkgfSBmcm9tICcuL3N0cnVjdHVyYWxXcml0ZS5qcyc7XG5cbi8qKlxuICogVGhlIHNlYW0gYmV0d2VlbiBhIHByb3h5IGFuZCBzdGF0ZS4gYHBhdGhgIGlzIG1lYXN1cmVkIGZyb20gdGhlIHNpbmsnc1xuICogcm9vdCDigJQgdGhlIGtleSdzIHZhbHVlIGZvciB7QGxpbmsgcm9vdEtleVNpbmt9LCB0aGUgZWxlbWVudCBmb3JcbiAqIHtAbGluayBlbGVtZW50U2lua307IGBbXWAgaXMgdGhlIHJvb3QgaXRzZWxmLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFdyaXRlU2luayB7XG4gIC8qKiBUaGUgdmFsdWUgYXQgYHBhdGhgLCBhcyBpdCBzdGFuZHMgTk9XIChyZWFkLXlvdXItd3JpdGVzOyBuZXZlciBhIHRyYWNrZWQgcmVhZCkuICovXG4gIHJlYWRBdChwYXRoOiByZWFkb25seSBzdHJpbmdbXSk6IHVua25vd247XG4gIC8qKiBQdXQgYW4gYWxyZWFkeS11bndyYXBwZWQgYHZhbHVlYCBhdCBgcGF0aGAuIFRoZSBzaW5rIGNob29zZXMgdGhlIHZlcmIuICovXG4gIHB1dChwYXRoOiByZWFkb25seSBzdHJpbmdbXSwgdmFsdWU6IHVua25vd24pOiB2b2lkO1xuICAvKiogUmVtb3ZlIHRoZSBrZXkgYXQgYHBhdGhgLiAqL1xuICByZW1vdmUocGF0aDogcmVhZG9ubHkgc3RyaW5nW10pOiB2b2lkO1xufVxuXG4vKiogVGhlIHR3byB3YXlzIGEgdmFsdWUgcmVhY2hlcyBhIHN0YXRlIGtleTogd2hhdCB0aGUgc2luayB3cml0ZXMgdGhyb3VnaC4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUm9vdEtleVRhcmdldCB7XG4gIHNldFZhbHVlKGtleTogc3RyaW5nLCB2YWx1ZTogdW5rbm93bik6IHZvaWQ7XG4gIHVwZGF0ZVZhbHVlKGtleTogc3RyaW5nLCB2YWx1ZTogdW5rbm93bik6IHZvaWQ7XG59XG5cbi8qKlxuICogV0hZOiBhIHdyaXRlIGJlbG93IGEgdG9wLWxldmVsIGtleSBoYXMgVFdPIHZlcmJzIChyZWFjdGl2ZS9SRUFETUUubWQsIGxhd1xuICogMykg4oCUIGFuIG9iamVjdCBsZWFmIGlzIGEgYG1lcmdlYCBvZiBhIG5lc3RlZCBwYXRjaCwgYW4gYXJyYXkgbGVhZiBvciBhXG4gKiBkZWxldGUgcmVidWlsZHMgdGhlIHJvb3QgaW1tdXRhYmx5IGFuZCBjb21taXRzIGEgYHNldGAgb2YgdGhlIGtleS4gT25seSB0aGVcbiAqIHNpbmsga25vd3MgdGhhdDsgdGhlIHRyYXBzIGRvIG5vdC4gRXZlcnkgd3JpdGUgZHJvcHMgdGhlIGtleSdzIGNhY2hlZCBjaGlsZFxuICogcHJveHkgKGBjYWNoZWApLCBzbyB0aGUgbmV4dCByZWFkIGlzIGJ1aWx0IG92ZXIgdGhlIG5ldyB2YWx1ZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJvb3RLZXlTaW5rKFxuICB0YXJnZXQ6IFJvb3RLZXlUYXJnZXQsXG4gIHJlYWRTaWxlbnQ6IChrZXk6IHN0cmluZykgPT4gdW5rbm93bixcbiAgcm9vdEtleTogc3RyaW5nLFxuICBjYWNoZTogUGljazxNZW1iZXJDYWNoZSwgJ2RlbGV0ZSc+LFxuKTogV3JpdGVTaW5rIHtcbiAgcmV0dXJuIG5ldyBSb290S2V5U2luayh0YXJnZXQsIHJlYWRTaWxlbnQsIHJvb3RLZXksIGNhY2hlKTtcbn1cblxuLyoqIE9uZSBhbGxvY2F0aW9uIHBlciB0b3AtbGV2ZWwgcmVhZCBtaXNzICh0aGUgbWV0aG9kcyBsaXZlIG9uIHRoZSBwcm90b3R5cGUpLiAqL1xuY2xhc3MgUm9vdEtleVNpbmsgaW1wbGVtZW50cyBXcml0ZVNpbmsge1xuICBjb25zdHJ1Y3RvcihcbiAgICBwcml2YXRlIHJlYWRvbmx5IHRhcmdldDogUm9vdEtleVRhcmdldCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJlYWRTaWxlbnQ6IChrZXk6IHN0cmluZykgPT4gdW5rbm93bixcbiAgICBwcml2YXRlIHJlYWRvbmx5IHJvb3RLZXk6IHN0cmluZyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNhY2hlOiBQaWNrPE1lbWJlckNhY2hlLCAnZGVsZXRlJz4sXG4gICkge31cblxuICAvKiogQW4gZW1wdHkgcGF0aCBpcyB0aGUga2V5J3Mgb3duIHZhbHVlIOKAlCBgbmF0aXZlR2V0KHYsIFtdKWAgd291bGQgcmV0dXJuIGl0IHVuY2hhbmdlZCwgc28gdGhlIHdhbGsgaXMgc2tpcHBlZC4gKi9cbiAgcmVhZEF0KHBhdGg6IHJlYWRvbmx5IHN0cmluZ1tdKTogdW5rbm93biB7XG4gICAgY29uc3Qgcm9vdCA9IHRoaXMucmVhZFNpbGVudCh0aGlzLnJvb3RLZXkpO1xuICAgIHJldHVybiBwYXRoLmxlbmd0aCA9PT0gMCA/IHJvb3QgOiBuYXRpdmVHZXQocm9vdCwgcGF0aCBhcyBzdHJpbmdbXSk7XG4gIH1cblxuICBwdXQocGF0aDogcmVhZG9ubHkgc3RyaW5nW10sIHZhbHVlOiB1bmtub3duKTogdm9pZCB7XG4gICAgaWYgKCFBcnJheS5pc0FycmF5KHZhbHVlKSkgdGhpcy50YXJnZXQudXBkYXRlVmFsdWUodGhpcy5yb290S2V5LCBidWlsZE5lc3RlZFBhdGNoKHBhdGggYXMgc3RyaW5nW10sIHZhbHVlKSk7XG4gICAgZWxzZSB0aGlzLnRhcmdldC5zZXRWYWx1ZSh0aGlzLnJvb3RLZXksIHBhdGgubGVuZ3RoID09PSAwID8gdmFsdWUgOiBzZXRJblBhdGgodGhpcy5yZWFkQXQoW10pLCBwYXRoLCB2YWx1ZSkpO1xuICAgIHRoaXMuY2FjaGUuZGVsZXRlKHRoaXMucm9vdEtleSk7XG4gIH1cblxuICByZW1vdmUocGF0aDogcmVhZG9ubHkgc3RyaW5nW10pOiB2b2lkIHtcbiAgICB0aGlzLnRhcmdldC5zZXRWYWx1ZSh0aGlzLnJvb3RLZXksIGRlbGV0ZUluUGF0aCh0aGlzLnJlYWRBdChbXSksIHBhdGgpKTtcbiAgICB0aGlzLmNhY2hlLmRlbGV0ZSh0aGlzLnJvb3RLZXkpO1xuICB9XG59XG5cbi8qKlxuICogV0hZOiBhIHdyaXRlIGluc2lkZSBhbiBhcnJheSBlbGVtZW50IGlzIGFuIGFycmF5IHdyaXRlIOKAlCBpdCByZWJ1aWxkcyB0aGVcbiAqIG93bmluZyBhcnJheSBpbW11dGFibHkgYW5kIGhhbmRzIHRoZSBXSE9MRSBuZXcgYXJyYXkgdG8gdGhlIGFycmF5IHByb3h5J3NcbiAqIGNvbW1pdCwgdGhlIGZ1bm5lbCBgcHVzaGAgYWxyZWFkeSB1c2VzLiBgcGF0aGAgaXMgbWVhc3VyZWQgZnJvbSB0aGVcbiAqIGVsZW1lbnQ7IGBbXWAgaXMgdGhlIGVsZW1lbnQgc2xvdCBpdHNlbGYuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBlbGVtZW50U2luayhnZXRDdXJyZW50OiAoKSA9PiB1bmtub3duW10sIGNvbW1pdDogKG5leHQ6IHVua25vd25bXSkgPT4gdm9pZCwgaW5kZXg6IG51bWJlcik6IFdyaXRlU2luayB7XG4gIHJldHVybiBuZXcgRWxlbWVudFNpbmsoZ2V0Q3VycmVudCwgY29tbWl0LCBpbmRleCk7XG59XG5cbi8qKiBPbmUgYWxsb2NhdGlvbiBwZXIgZWxlbWVudCBwcm94eSAodGhlIG1ldGhvZHMgbGl2ZSBvbiB0aGUgcHJvdG90eXBlKSDigJQgYSAxMGstZWxlbWVudCBsb29wIGJ1aWxkcyAxMGsgb2YgdGhlc2UuICovXG5jbGFzcyBFbGVtZW50U2luayBpbXBsZW1lbnRzIFdyaXRlU2luayB7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgZ2V0Q3VycmVudDogKCkgPT4gdW5rbm93bltdLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgY29tbWl0OiAobmV4dDogdW5rbm93bltdKSA9PiB2b2lkLFxuICAgIHByaXZhdGUgcmVhZG9ubHkgaW5kZXg6IG51bWJlcixcbiAgKSB7fVxuXG4gIHJlYWRBdChwYXRoOiByZWFkb25seSBzdHJpbmdbXSk6IHVua25vd24ge1xuICAgIHJldHVybiByZWFkSW5FbGVtZW50KHRoaXMuZ2V0Q3VycmVudCwgdGhpcy5pbmRleCwgcGF0aCk7XG4gIH1cblxuICBwdXQocGF0aDogcmVhZG9ubHkgc3RyaW5nW10sIHZhbHVlOiB1bmtub3duKTogdm9pZCB7XG4gICAgcmVwbGFjZUluRWxlbWVudCh0aGlzLmdldEN1cnJlbnQsIHRoaXMuY29tbWl0LCB0aGlzLmluZGV4LCBwYXRoLCB2YWx1ZSk7XG4gIH1cblxuICByZW1vdmUocGF0aDogcmVhZG9ubHkgc3RyaW5nW10pOiB2b2lkIHtcbiAgICByZW1vdmVJbkVsZW1lbnQodGhpcy5nZXRDdXJyZW50LCB0aGlzLmNvbW1pdCwgdGhpcy5pbmRleCwgcGF0aCk7XG4gIH1cbn1cblxuLyoqIFRoZSB2YWx1ZSBhdCBgcGF0aGAgaW5zaWRlIGVsZW1lbnQgYGluZGV4YCwgYXMgaXQgc3RhbmRzIE5PVyAocmVhZC15b3VyLXdyaXRlcykuICovXG5mdW5jdGlvbiByZWFkSW5FbGVtZW50KGdldEN1cnJlbnQ6ICgpID0+IHVua25vd25bXSwgaW5kZXg6IG51bWJlciwgcGF0aDogcmVhZG9ubHkgc3RyaW5nW10pOiB1bmtub3duIHtcbiAgY29uc3QgZWxlbWVudCA9IGdldEN1cnJlbnQoKVtpbmRleF07XG4gIHJldHVybiBwYXRoLmxlbmd0aCA9PT0gMCA/IGVsZW1lbnQgOiBuYXRpdmVHZXQoZWxlbWVudCwgcGF0aCBhcyBzdHJpbmdbXSk7XG59XG5cbi8qKiBBIGNvcHkgb2YgdGhlIGFycmF5IHdpdGggYHZhbHVlYCBhdCBgcGF0aGAgaW5zaWRlIGVsZW1lbnQgYGluZGV4YDsgYSBnb25lIGVsZW1lbnQgaGFzIG5vdGhpbmcgdG8gd3JpdGUgaW50by4gKi9cbmZ1bmN0aW9uIHJlcGxhY2VJbkVsZW1lbnQoXG4gIGdldEN1cnJlbnQ6ICgpID0+IHVua25vd25bXSxcbiAgY29tbWl0OiAobmV4dDogdW5rbm93bltdKSA9PiB2b2lkLFxuICBpbmRleDogbnVtYmVyLFxuICBwYXRoOiByZWFkb25seSBzdHJpbmdbXSxcbiAgdmFsdWU6IHVua25vd24sXG4pOiB2b2lkIHtcbiAgY29uc3QgbmV4dCA9IFsuLi5nZXRDdXJyZW50KCldO1xuICBpZiAoaW5kZXggPj0gbmV4dC5sZW5ndGgpIHJldHVybjtcbiAgbmV4dFtpbmRleF0gPSBwYXRoLmxlbmd0aCA9PT0gMCA/IHZhbHVlIDogc2V0SW5QYXRoKG5leHRbaW5kZXhdLCBwYXRoLCB2YWx1ZSk7XG4gIGNvbW1pdChuZXh0KTtcbn1cblxuLyoqIEEgY29weSBvZiB0aGUgYXJyYXkgd2l0aCB0aGUga2V5IGF0IGBwYXRoYCBpbnNpZGUgZWxlbWVudCBgaW5kZXhgIHJlbW92ZWQuICovXG5mdW5jdGlvbiByZW1vdmVJbkVsZW1lbnQoXG4gIGdldEN1cnJlbnQ6ICgpID0+IHVua25vd25bXSxcbiAgY29tbWl0OiAobmV4dDogdW5rbm93bltdKSA9PiB2b2lkLFxuICBpbmRleDogbnVtYmVyLFxuICBwYXRoOiByZWFkb25seSBzdHJpbmdbXSxcbik6IHZvaWQge1xuICBjb25zdCBuZXh0ID0gWy4uLmdldEN1cnJlbnQoKV07XG4gIGlmIChpbmRleCA+PSBuZXh0Lmxlbmd0aCkgcmV0dXJuO1xuICBuZXh0W2luZGV4XSA9IGRlbGV0ZUluUGF0aChuZXh0W2luZGV4XSwgcGF0aCk7XG4gIGNvbW1pdChuZXh0KTtcbn1cblxuLyoqXG4gKiBXSFkgb25lIHNldCB0cmFwOiB0aGUgYXNzaWduZWQgdmFsdWUgaXMgdW53cmFwcGVkIEhFUkUgKGxhbmRtaW5lIDEg4oCUIHRoZVxuICogSlNPTiByb3VuZC10cmlwIGFwcGxpZXMgdG8gd2hhdCB0aGUgY2FsbGVyIGhhbmRlZCBpbiwgbmV2ZXIgdG8gdGhlXG4gKiBzdXJyb3VuZGluZyBzdGF0ZSkgYW5kIGhhbmRlZCB0byB0aGUgc2luayBhdCB0aGUgcHJveHkncyBwYXRoIHBsdXMgdGhlIGtleS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNpbmtTZXRUcmFwKHNpbms6IFdyaXRlU2luaywgc2VnbWVudHM6IHJlYWRvbmx5IHN0cmluZ1tdKTogUHJveHlIYW5kbGVyPG9iamVjdD5bJ3NldCddIHtcbiAgcmV0dXJuIChfdGFyZ2V0LCBwcm9wLCB2YWx1ZSkgPT4ge1xuICAgIGlmICh0eXBlb2YgcHJvcCAhPT0gJ3N0cmluZycpIHJldHVybiB0cnVlO1xuICAgIHNpbmsucHV0KFsuLi5zZWdtZW50cywgcHJvcF0sIHVud3JhcFByb3h5KHZhbHVlKSk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG59XG5cbi8qKlxuICogV0hZIG9uZSBkZWxldGUgdHJhcDogYG1lcmdlYCBjYW5ub3QgZXhwcmVzcyBhIHJlbW92YWwgKGEgcGF0Y2ggb2ZcbiAqIGB1bmRlZmluZWRgIHJlYWRzIGFzIGFic2VudCksIHNvIGEgZGVsZXRlIGFsd2F5cyByZWJ1aWxkcyB0aHJvdWdoIHRoZSBzaW5rLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2lua0RlbGV0ZVRyYXAoc2luazogV3JpdGVTaW5rLCBzZWdtZW50czogcmVhZG9ubHkgc3RyaW5nW10pOiBQcm94eUhhbmRsZXI8b2JqZWN0PlsnZGVsZXRlUHJvcGVydHknXSB7XG4gIHJldHVybiAoX3RhcmdldCwgcHJvcCkgPT4ge1xuICAgIGlmICh0eXBlb2YgcHJvcCAhPT0gJ3N0cmluZycpIHJldHVybiB0cnVlO1xuICAgIHNpbmsucmVtb3ZlKFsuLi5zZWdtZW50cywgcHJvcF0pO1xuICAgIHJldHVybiB0cnVlO1xuICB9O1xufVxuIl19
@@ -274,6 +274,24 @@ export declare class TransactionBuffer {
274
274
  * today's full-value `set`.
275
275
  */
276
276
  private toDeltaPayload;
277
+ /**
278
+ * Did the stage change the value at `segments`? Base and final value are
279
+ * fixed at commit, so this is the ONE net-change verdict both payload
280
+ * encodings apply (a no-op write and a write-then-revert both fail it).
281
+ */
282
+ private changedSinceBase;
283
+ /**
284
+ * Path → its op-verb sequence, ordered by LAST touch (delete + re-insert
285
+ * moves a re-touched path to the end of the Map's insertion order —
286
+ * preserving last-writer-wins for nested/overlapping paths). Per-write
287
+ * provenance (#P1): the LAST op's readKeys is kept — read prefixes only grow
288
+ * within a stage, so last == union across the path.
289
+ */
290
+ private opsByPath;
291
+ /** The net-change filter — identical to 'full' ({@link changedSinceBase}). Survivors keep last-touch order. */
292
+ private netChangeSurvivors;
293
+ /** Replay each overlapping family ONCE, lazily — most commits have none, and pay nothing. */
294
+ private memoisedFamilyValue;
277
295
  /**
278
296
  * Bucket the staged ops of every OVERLAPPING family by family root, in op
279
297
  * order — the input {@link replayFamilyVerbs} folds. Ops on paths the
@@ -38,9 +38,9 @@
38
38
  *
39
39
  * Now an indexed read of a wrappable element returns an ELEMENT PROXY that
40
40
  * accumulates the path inside the element and, on write, rebuilds the array
41
- * immutably ({@link setInPath}) and hands the whole new array to `commit` —
42
- * the same funnel `push` already used. One write path for the whole array,
43
- * whatever depth it is addressed at.
41
+ * immutably (`structuralWrite.setInPath`, behind `writeTraps.elementSink`)
42
+ * and hands the whole new array to `commit` — the same funnel `push` already
43
+ * used. One write path for the whole array, whatever depth it is addressed at.
44
44
  *
45
45
  * ── What is still NOT seen (by design) ───────────────────────────────────
46
46
  * Elements reached WITHOUT an index — `find()`, `filter()`, `for…of`,
@@ -50,10 +50,30 @@
50
50
  * not lost in silence either: `StageContext` compares what a stage READ with
51
51
  * what the value holds at commit and, in dev mode, warns with the exact path.
52
52
  * See src/lib/reactive/README.md.
53
+ *
54
+ * ── Shape (9.23.1) ───────────────────────────────────────────────────────
55
+ * `createArrayProxy` and `createElementProxy` are ORCHESTRATORS: they wire
56
+ * traps and hold the caches. Every trap body is a named leaf below — one
57
+ * concern each — and the element proxy's set/delete/get traps are the SAME
58
+ * leaves the nested and terminal object proxies use (`writeTraps.ts`,
59
+ * `liveView.ts`), over an {@link elementSink}. A fix lands in a leaf once.
60
+ */
61
+ import { type WriteSink } from './writeTraps.js';
62
+ /**
63
+ * WHY: an array anywhere below a sink's root is ONE write path — it reads
64
+ * through the sink and commits the WHOLE new array back through it, so
65
+ * `push` three levels down and `arr[i].x = v` at the top share a funnel.
53
66
  */
67
+ export declare function arrayProxyAt(sink: WriteSink, path: readonly string[]): unknown[];
54
68
  /**
55
69
  * Creates a Proxy over an array that intercepts mutating operations.
56
70
  *
71
+ * The actual current array is the Proxy target: Node.js console.log inspects
72
+ * the target directly (bypasses Proxy traps), so the real array shows correct
73
+ * values. The target reference is fixed at creation time — after mutations,
74
+ * the proxy returns a new proxy (via cache invalidation) with the fresh array
75
+ * as target.
76
+ *
57
77
  * @param getCurrent - Returns the current array snapshot from state
58
78
  * @param commit - Called with the new array after a mutation (triggers setValue)
59
79
  * @returns Proxied array with copy-on-write semantics
@@ -9,9 +9,60 @@
9
9
  * found on element proxies, then the same root on nested and terminal ones).
10
10
  * So every read trap resolves through the CURRENT value and falls back to the
11
11
  * captured object only when the path is gone or no longer holds an object.
12
+ *
13
+ * The READ side of every object proxy lives here — {@link liveObject},
14
+ * {@link liveGetTrap}, {@link liveInspectionTraps}, and the ONE per-member
15
+ * proxy cache {@link cachedMember} (9.23.2); the WRITE side is
16
+ * `writeTraps.ts`. A factory only wires them (9.23.1).
17
+ */
18
+ /**
19
+ * A proxy per member NAME under one parent proxy, validated by the raw
20
+ * member's identity. The map is allocated on the FIRST insert: an element
21
+ * proxy over `{ id, n }` reads only primitives and must not pay for one
22
+ * (10,000 of them in the naive re-read loop — measured, `bench/nested-reads.ts`).
12
23
  */
24
+ export declare class MemberCache {
25
+ private entries?;
26
+ /** The proxy cached under `prop`, if it was built over exactly this raw `value`. */
27
+ hit(prop: string, value: object): unknown;
28
+ remember(prop: string, value: object, proxy: unknown): void;
29
+ /** Forget `prop` — a write replaced its value, so the next read must build over the new one. */
30
+ delete(prop: string): void;
31
+ }
32
+ /**
33
+ * WHY the cache: `o.arr === o.arr` must hold within a stage, and
34
+ * `for (i < N) s.k.arr[i]` must build ONE array proxy — whose element cache
35
+ * then serves every index — not N (the 9.22.0 perf review, finding 4: the
36
+ * nested get trap built a fresh array proxy, with a fresh empty element
37
+ * cache, on every `.arr`). The top-level scope has cached its child proxies
38
+ * this way since before 9.22.0; this is that leaf, shared by all four.
39
+ *
40
+ * Validated by IDENTITY, invalidated by replacement: every write through a
41
+ * proxy rebuilds the containers on its path (`structuralWrite.setInPath`),
42
+ * so after `s.k.arr[0].n = 1` the raw `arr` is a new array, the ref check
43
+ * misses, and the next read builds a proxy over the NEW value. A hit can
44
+ * never be stale — every proxy reads live (`liveGetTrap`), so the cached one
45
+ * and a fresh one answer the same.
46
+ *
47
+ * Keyed by NAME under THIS parent, never by the raw value alone: a diamond
48
+ * (one array under `k.a` and `k.b`) needs two proxies, each bound to its own
49
+ * path and sink. Only what `build` actually WRAPPED is kept — a member handed
50
+ * back raw (a `Date`, a frozen object, a cycle edge) is not worth an entry.
51
+ * `build` is the caller's stable child step, not a closure made per read: a
52
+ * hit allocates nothing, and a primitive member skips the cache entirely.
53
+ */
54
+ export declare function cachedMember(cache: MemberCache, prop: string, value: unknown, build: (value: unknown, path: string[]) => unknown, segments: readonly string[]): unknown;
13
55
  /** The object at `segments` under the current root, or `raw` when it is gone. */
14
56
  export declare function liveObject(raw: Record<string, unknown>, current: unknown): Record<string, unknown>;
57
+ /**
58
+ * WHY one get trap: the names a proxy answers ITSELF (promise/matcher guards,
59
+ * `constructor`, and the JSON law — serializing a proxied value equals
60
+ * serializing the raw one, `jsonProjection.ts`) must be the same three lines
61
+ * on every object proxy; any other member is handed to `child` with its full
62
+ * path — through the parent's {@link cachedMember} — and only THAT step
63
+ * differs per factory (the cycle policy).
64
+ */
65
+ export declare function liveGetTrap(live: () => Record<string, unknown>, segments: readonly string[], child: (value: unknown, path: string[]) => unknown, members: MemberCache): ProxyHandler<object>['get'];
15
66
  /**
16
67
  * The three inspection traps (`in`, `Object.keys`, descriptors) answered from
17
68
  * the live object. The one Proxy invariant that could bite — a non-extensible
@@ -0,0 +1,59 @@
1
+ /**
2
+ * reactive/writeTraps — where a proxy's writes LAND, and the two traps that
3
+ * send them there.
4
+ *
5
+ * Every object proxy in this folder (nested, terminal, element) intercepts
6
+ * the same three things — a property set, a property delete, and an array
7
+ * mutation somewhere below it — and differs only in where the write goes:
8
+ * a nested/terminal proxy commits under a TOP-LEVEL KEY (an object write as
9
+ * `merge` of a patch, an array write or a delete as `set` of the rebuilt
10
+ * root); an element proxy commits the WHOLE OWNING ARRAY back through the
11
+ * array proxy's own callback. That difference is a {@link WriteSink}; the
12
+ * traps are written once over it (9.23.1 — the 9.22.0 stale-read bug was
13
+ * fixed in one copy of these traps and then found again in the other two).
14
+ */
15
+ import type { MemberCache } from './liveView.js';
16
+ /**
17
+ * The seam between a proxy and state. `path` is measured from the sink's
18
+ * root — the key's value for {@link rootKeySink}, the element for
19
+ * {@link elementSink}; `[]` is the root itself.
20
+ */
21
+ export interface WriteSink {
22
+ /** The value at `path`, as it stands NOW (read-your-writes; never a tracked read). */
23
+ readAt(path: readonly string[]): unknown;
24
+ /** Put an already-unwrapped `value` at `path`. The sink chooses the verb. */
25
+ put(path: readonly string[], value: unknown): void;
26
+ /** Remove the key at `path`. */
27
+ remove(path: readonly string[]): void;
28
+ }
29
+ /** The two ways a value reaches a state key: what the sink writes through. */
30
+ export interface RootKeyTarget {
31
+ setValue(key: string, value: unknown): void;
32
+ updateValue(key: string, value: unknown): void;
33
+ }
34
+ /**
35
+ * WHY: a write below a top-level key has TWO verbs (reactive/README.md, law
36
+ * 3) — an object leaf is a `merge` of a nested patch, an array leaf or a
37
+ * delete rebuilds the root immutably and commits a `set` of the key. Only the
38
+ * sink knows that; the traps do not. Every write drops the key's cached child
39
+ * proxy (`cache`), so the next read is built over the new value.
40
+ */
41
+ export declare function rootKeySink(target: RootKeyTarget, readSilent: (key: string) => unknown, rootKey: string, cache: Pick<MemberCache, 'delete'>): WriteSink;
42
+ /**
43
+ * WHY: a write inside an array element is an array write — it rebuilds the
44
+ * owning array immutably and hands the WHOLE new array to the array proxy's
45
+ * commit, the funnel `push` already uses. `path` is measured from the
46
+ * element; `[]` is the element slot itself.
47
+ */
48
+ export declare function elementSink(getCurrent: () => unknown[], commit: (next: unknown[]) => void, index: number): WriteSink;
49
+ /**
50
+ * WHY one set trap: the assigned value is unwrapped HERE (landmine 1 — the
51
+ * JSON round-trip applies to what the caller handed in, never to the
52
+ * surrounding state) and handed to the sink at the proxy's path plus the key.
53
+ */
54
+ export declare function sinkSetTrap(sink: WriteSink, segments: readonly string[]): ProxyHandler<object>['set'];
55
+ /**
56
+ * WHY one delete trap: `merge` cannot express a removal (a patch of
57
+ * `undefined` reads as absent), so a delete always rebuilds through the sink.
58
+ */
59
+ export declare function sinkDeleteTrap(sink: WriteSink, segments: readonly string[]): ProxyHandler<object>['deleteProperty'];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "footprintjs",
3
- "version": "9.23.0",
3
+ "version": "9.23.2",
4
4
  "description": "Explainable backend flows — automatic causal traces, decision evidence, and MCP tool generation for AI agents",
5
5
  "license": "MIT",
6
6
  "author": "Sanjay Krishna Anbalagan",