sia-reactor 0.0.39 → 0.0.40

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.
@@ -1,5 +1,5 @@
1
- import { R as Reactive } from './index-BsH8KkqG.js';
2
- import { T as TimeTravelModule } from './index-D4DGBS2N.js';
1
+ import { R as Reactive } from './index-BtHNGnRR.js';
2
+ import { T as TimeTravelModule } from './index-CKHoDs6x.js';
3
3
 
4
4
  /** Reactive options for the TimeTravel overlay instance. */
5
5
  interface TimeTravelConsoleConfig {
@@ -1,5 +1,5 @@
1
- import { R as Reactive } from './index-BsH8KkqG.cjs';
2
- import { T as TimeTravelModule } from './index-DBx4TIVW.cjs';
1
+ import { R as Reactive } from './index-BtHNGnRR.cjs';
2
+ import { T as TimeTravelModule } from './index-C_djeddc.cjs';
3
3
 
4
4
  /** Reactive options for the TimeTravel overlay instance. */
5
5
  interface TimeTravelConsoleConfig {
@@ -1260,7 +1260,7 @@ var TimeTravelConsole = class _TimeTravelConsole {
1260
1260
  this.config = reactive({ title: `Time Travel Console ${this.index = ++_TimeTravelConsole.count}`, ...build });
1261
1261
  this.state.open = !!this.config.startOpen;
1262
1262
  let wlLive = false, blLive = false;
1263
- const s = this.time.state, host = this.host = createEl("div", { className: "sia-tt-console-host" }), toggle = createEl("button", { className: "sia-tt-console-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "sia-tt-console", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: () => this.time.undo(this.state.stride) }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: () => this.time.redo(this.state.stride) }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), trackUntrack = createEl("button", { onclick: () => this.time[s.tracking ? "untrack" : "track"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.trackUntrack, false) }), range = createEl("input", { type: "range", min: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "sia-tt-io", readOnly: true, placeholder: "current payload json", title: "Current History Entry" }), io = createEl("textarea", { className: "sia-tt-io", placeholder: "timeline payload json", title: "Time History", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "sia-tt-footnote", innerHTML: "<span>Want this in your app? </span>" }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "sia-tt-status-box" }), status = createEl("div", { className: "sia-tt-status-row" }), filters = createEl("div", { className: "sia-tt-status-row" }), filterBox = createEl("div", { className: "sia-tt-status-box" }), whitelistLabel = createEl("span", { className: "muted", textContent: "Whitelist:" }), blacklistLabel = createEl("span", { className: "muted", textContent: "Blacklist:" }), whitelist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Whitelist paths", onfocus: () => wlLive = true, onblur: () => (wlLive = false, whitelist.value = formatPaths(this.time.config.whitelist, "*")), oninput: (_, parsed = parsePaths(whitelist.value)) => parsed !== null && (this.time.config.whitelist = parsed) }), blacklist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Blacklist paths", onfocus: () => blLive = true, onblur: () => (blLive = false, blacklist.value = formatPaths(this.time.config.blacklist, "")), oninput: (_, parsed = parsePaths(blacklist.value, true)) => parsed !== null && (this.time.config.blacklist = parsed) }), speed = createEl("select", { className: "sia-tt-speed", title: "Playback Speed", onchange: () => this.time.config.playbackRate = Number(speed.value) }), stride = createEl("input", { className: "sia-tt-stride sia-tt-button sia-tt-mini-input", type: "number", min: "1", title: "Skip Stride i.e. how many steps count as one unit", oninput: () => this.state.stride = Math.max(1, Number(stride.value) || 1) }), stats = createEl("span", { className: "sia-tt-stats" }), limit = createEl("input", { className: "sia-tt-limit sia-tt-mini-input sia-tt-button", type: "number", min: "1", title: "Maximum number of history entries kept in memory before older entries are discarded.", oninput: () => this.time.config.limit = Math.max(1, Number(limit.value) || 1) }), delay = createEl("input", { className: "sia-tt-delay sia-tt-mini-input sia-tt-button", type: "number", min: "0", step: "50", title: "Maximum playback delay between timeline frames in milliseconds.", oninput: () => this.time.config.maxPlaybackDelay = Math.max(0, Number(delay.value) || 0) }), read = createEl("label", { className: "sia-tt-check", title: "When recording intent mutations, read previous values from the matching state path instead of the intent path. Useful for accurate undo reconstruction of intent-driven flows." }), readBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorReads, onchange: () => this.time.config.mirrorReads = readBox.checked }), write = createEl("label", { className: "sia-tt-check", title: "During playback and teleportation, mirror state writes into matching intent paths to re-enact the recorded history. Useful for accurate reconstruction of the whole session." }), writeBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorWrites, onchange: () => this.time.config.mirrorWrites = writeBox.checked }), filterRow1 = createEl("div", { className: "sia-tt-filter-row" }), filterRow2 = createEl("div", { className: "sia-tt-filter-row" }), row1 = createEl("div", { className: "sia-tt-row" }), row2 = createEl("div", { className: "sia-tt-row" }), row3 = createEl("div", { className: "sia-tt-row" }), row4 = createEl("div", { className: "sia-tt-row" }), row5 = createEl("div", { className: "sia-tt-row sia-tt-config-row" });
1263
+ const s = this.time.state, host = this.host = createEl("div", { className: "sia-tt-console-host" }), toggle = createEl("button", { className: "sia-tt-console-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "sia-tt-console", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: () => this.time.undo(this.state.stride) }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: () => this.time.redo(this.state.stride) }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), trackUntrack = createEl("button", { onclick: () => this.time[s.tracking ? "untrack" : "track"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.trackUntrack, false) }), range = createEl("input", { type: "range", min: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "sia-tt-io", readOnly: true, placeholder: "current payload json", title: "Current History Entry" }), io = createEl("textarea", { className: "sia-tt-io", placeholder: "timeline payload json", title: "Time History", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "sia-tt-footnote", innerHTML: "<span>Try this in your app? </span>" }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "sia-tt-status-box" }), status = createEl("div", { className: "sia-tt-status-row" }), filters = createEl("div", { className: "sia-tt-status-row" }), filterBox = createEl("div", { className: "sia-tt-status-box" }), whitelistLabel = createEl("span", { className: "muted", textContent: "Whitelist:" }), blacklistLabel = createEl("span", { className: "muted", textContent: "Blacklist:" }), whitelist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Whitelist paths", onfocus: () => wlLive = true, onblur: () => (wlLive = false, whitelist.value = formatPaths(this.time.config.whitelist, "*")), oninput: (_, parsed = parsePaths(whitelist.value)) => parsed !== null && (this.time.config.whitelist = parsed) }), blacklist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Blacklist paths", onfocus: () => blLive = true, onblur: () => (blLive = false, blacklist.value = formatPaths(this.time.config.blacklist, "")), oninput: (_, parsed = parsePaths(blacklist.value, true)) => parsed !== null && (this.time.config.blacklist = parsed) }), speed = createEl("select", { className: "sia-tt-speed", title: "Playback Speed", onchange: () => this.time.config.playbackRate = Number(speed.value) }), stride = createEl("input", { className: "sia-tt-stride sia-tt-button sia-tt-mini-input", type: "number", min: "1", title: "Skip Stride i.e. how many steps count as one unit", oninput: () => this.state.stride = Math.max(1, Number(stride.value) || 1) }), stats = createEl("span", { className: "sia-tt-stats" }), limit = createEl("input", { className: "sia-tt-limit sia-tt-mini-input sia-tt-button", type: "number", min: "1", title: "Maximum number of history entries kept in memory before older entries are discarded.", oninput: () => this.time.config.limit = Math.max(1, Number(limit.value) || 1) }), delay = createEl("input", { className: "sia-tt-delay sia-tt-mini-input sia-tt-button", type: "number", min: "0", step: "50", title: "Maximum playback delay between timeline frames in milliseconds.", oninput: () => this.time.config.maxPlaybackDelay = Math.max(0, Number(delay.value) || 0) }), read = createEl("label", { className: "sia-tt-check", title: "When recording intent mutations, read previous values from the matching state path instead of the intent path. Useful for accurate undo reconstruction of intent-driven flows." }), readBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorReads, onchange: () => this.time.config.mirrorReads = readBox.checked }), write = createEl("label", { className: "sia-tt-check", title: "During playback and teleportation, mirror state writes into matching intent paths to re-enact the recorded history. Useful for accurate reconstruction of the whole session." }), writeBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorWrites, onchange: () => this.time.config.mirrorWrites = writeBox.checked }), filterRow1 = createEl("div", { className: "sia-tt-filter-row" }), filterRow2 = createEl("div", { className: "sia-tt-filter-row" }), row1 = createEl("div", { className: "sia-tt-row" }), row2 = createEl("div", { className: "sia-tt-row" }), row3 = createEl("div", { className: "sia-tt-row" }), row4 = createEl("div", { className: "sia-tt-row" }), row5 = createEl("div", { className: "sia-tt-row sia-tt-config-row" });
1264
1264
  speed.append(...[0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4, 8, 16, 32].map((v) => createEl("option", { value: String(v), textContent: `${v}x` })));
1265
1265
  status.append((box.append(frame), box), clrHistory);
1266
1266
  filters.append((filterBox.append((filterRow1.append(whitelistLabel, whitelist), filterRow1), (filterRow2.append(blacklistLabel, blacklist), filterRow2)), filterBox));
@@ -1,7 +1,7 @@
1
- import { E as EffectOptions, d as Reactor, R as Reactive, J as ReactorBuild, K as DeepReadonly, W as WildPaths, a as PathValue } from '../index-BsH8KkqG.cjs';
1
+ import { E as EffectOptions, d as Reactor, R as Reactive, J as ReactorBuild, K as DeepReadonly, W as WildPaths, a as PathValue } from '../index-BtHNGnRR.cjs';
2
2
  import { useLayoutEffect } from 'react';
3
- import { T as TimeTravelModule } from '../index-DBx4TIVW.cjs';
4
- import { a as TimeTravelConsoleConfig } from '../TimeTravelConsole-nYAqg57U.cjs';
3
+ import { T as TimeTravelModule } from '../index-C_djeddc.cjs';
4
+ import { a as TimeTravelConsoleConfig } from '../TimeTravelConsole-Dt8txKnt.cjs';
5
5
 
6
6
  /**
7
7
  * Subscribes a component to desired Reactor state and returns it.
@@ -1,7 +1,7 @@
1
- import { E as EffectOptions, d as Reactor, R as Reactive, J as ReactorBuild, K as DeepReadonly, W as WildPaths, a as PathValue } from '../index-BsH8KkqG.js';
1
+ import { E as EffectOptions, d as Reactor, R as Reactive, J as ReactorBuild, K as DeepReadonly, W as WildPaths, a as PathValue } from '../index-BtHNGnRR.js';
2
2
  import { useLayoutEffect } from 'react';
3
- import { T as TimeTravelModule } from '../index-D4DGBS2N.js';
4
- import { a as TimeTravelConsoleConfig } from '../TimeTravelConsole-DSifvt2z.js';
3
+ import { T as TimeTravelModule } from '../index-CKHoDs6x.js';
4
+ import { a as TimeTravelConsoleConfig } from '../TimeTravelConsole-BjDL0JjZ.js';
5
5
 
6
6
  /**
7
7
  * Subscribes a component to desired Reactor state and returns it.
@@ -2,8 +2,8 @@ import {
2
2
  Autotracker,
3
3
  TimeTravelConsole,
4
4
  withTracker
5
- } from "../chunk-56H5BKHJ.js";
6
- import "../chunk-FOD32N6J.js";
5
+ } from "../chunk-ENEEV334.js";
6
+ import "../chunk-KPJ5SPXP.js";
7
7
  import "../chunk-ORK3EGB6.js";
8
8
  import {
9
9
  CTX,
@@ -11,7 +11,7 @@ import {
11
11
  NOOP,
12
12
  getPath,
13
13
  getReactor
14
- } from "../chunk-DCUPDG7B.js";
14
+ } from "../chunk-LZJYX2LE.js";
15
15
 
16
16
  // src/ts/adapters/react/hooks/useReactor.ts
17
17
  import { useRef, useCallback, useSyncExternalStore, useMemo } from "react";
@@ -1167,7 +1167,7 @@ var TimeTravelConsole = class _TimeTravelConsole {
1167
1167
  this.config = reactive({ title: `Time Travel Console ${this.index = ++_TimeTravelConsole.count}`, ...build });
1168
1168
  this.state.open = !!this.config.startOpen;
1169
1169
  let wlLive = false, blLive = false;
1170
- const s = this.time.state, host = this.host = createEl("div", { className: "sia-tt-console-host" }), toggle = createEl("button", { className: "sia-tt-console-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "sia-tt-console", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: () => this.time.undo(this.state.stride) }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: () => this.time.redo(this.state.stride) }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), trackUntrack = createEl("button", { onclick: () => this.time[s.tracking ? "untrack" : "track"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.trackUntrack, false) }), range = createEl("input", { type: "range", min: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "sia-tt-io", readOnly: true, placeholder: "current payload json", title: "Current History Entry" }), io = createEl("textarea", { className: "sia-tt-io", placeholder: "timeline payload json", title: "Time History", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "sia-tt-footnote", innerHTML: "<span>Want this in your app? </span>" }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "sia-tt-status-box" }), status = createEl("div", { className: "sia-tt-status-row" }), filters = createEl("div", { className: "sia-tt-status-row" }), filterBox = createEl("div", { className: "sia-tt-status-box" }), whitelistLabel = createEl("span", { className: "muted", textContent: "Whitelist:" }), blacklistLabel = createEl("span", { className: "muted", textContent: "Blacklist:" }), whitelist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Whitelist paths", onfocus: () => wlLive = true, onblur: () => (wlLive = false, whitelist.value = formatPaths(this.time.config.whitelist, "*")), oninput: (_, parsed = parsePaths(whitelist.value)) => parsed !== null && (this.time.config.whitelist = parsed) }), blacklist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Blacklist paths", onfocus: () => blLive = true, onblur: () => (blLive = false, blacklist.value = formatPaths(this.time.config.blacklist, "")), oninput: (_, parsed = parsePaths(blacklist.value, true)) => parsed !== null && (this.time.config.blacklist = parsed) }), speed = createEl("select", { className: "sia-tt-speed", title: "Playback Speed", onchange: () => this.time.config.playbackRate = Number(speed.value) }), stride = createEl("input", { className: "sia-tt-stride sia-tt-button sia-tt-mini-input", type: "number", min: "1", title: "Skip Stride i.e. how many steps count as one unit", oninput: () => this.state.stride = Math.max(1, Number(stride.value) || 1) }), stats = createEl("span", { className: "sia-tt-stats" }), limit = createEl("input", { className: "sia-tt-limit sia-tt-mini-input sia-tt-button", type: "number", min: "1", title: "Maximum number of history entries kept in memory before older entries are discarded.", oninput: () => this.time.config.limit = Math.max(1, Number(limit.value) || 1) }), delay = createEl("input", { className: "sia-tt-delay sia-tt-mini-input sia-tt-button", type: "number", min: "0", step: "50", title: "Maximum playback delay between timeline frames in milliseconds.", oninput: () => this.time.config.maxPlaybackDelay = Math.max(0, Number(delay.value) || 0) }), read = createEl("label", { className: "sia-tt-check", title: "When recording intent mutations, read previous values from the matching state path instead of the intent path. Useful for accurate undo reconstruction of intent-driven flows." }), readBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorReads, onchange: () => this.time.config.mirrorReads = readBox.checked }), write = createEl("label", { className: "sia-tt-check", title: "During playback and teleportation, mirror state writes into matching intent paths to re-enact the recorded history. Useful for accurate reconstruction of the whole session." }), writeBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorWrites, onchange: () => this.time.config.mirrorWrites = writeBox.checked }), filterRow1 = createEl("div", { className: "sia-tt-filter-row" }), filterRow2 = createEl("div", { className: "sia-tt-filter-row" }), row1 = createEl("div", { className: "sia-tt-row" }), row2 = createEl("div", { className: "sia-tt-row" }), row3 = createEl("div", { className: "sia-tt-row" }), row4 = createEl("div", { className: "sia-tt-row" }), row5 = createEl("div", { className: "sia-tt-row sia-tt-config-row" });
1170
+ const s = this.time.state, host = this.host = createEl("div", { className: "sia-tt-console-host" }), toggle = createEl("button", { className: "sia-tt-console-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "sia-tt-console", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: () => this.time.undo(this.state.stride) }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: () => this.time.redo(this.state.stride) }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), trackUntrack = createEl("button", { onclick: () => this.time[s.tracking ? "untrack" : "track"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.trackUntrack, false) }), range = createEl("input", { type: "range", min: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "sia-tt-io", readOnly: true, placeholder: "current payload json", title: "Current History Entry" }), io = createEl("textarea", { className: "sia-tt-io", placeholder: "timeline payload json", title: "Time History", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "sia-tt-footnote", innerHTML: "<span>Try this in your app? </span>" }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "sia-tt-status-box" }), status = createEl("div", { className: "sia-tt-status-row" }), filters = createEl("div", { className: "sia-tt-status-row" }), filterBox = createEl("div", { className: "sia-tt-status-box" }), whitelistLabel = createEl("span", { className: "muted", textContent: "Whitelist:" }), blacklistLabel = createEl("span", { className: "muted", textContent: "Blacklist:" }), whitelist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Whitelist paths", onfocus: () => wlLive = true, onblur: () => (wlLive = false, whitelist.value = formatPaths(this.time.config.whitelist, "*")), oninput: (_, parsed = parsePaths(whitelist.value)) => parsed !== null && (this.time.config.whitelist = parsed) }), blacklist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Blacklist paths", onfocus: () => blLive = true, onblur: () => (blLive = false, blacklist.value = formatPaths(this.time.config.blacklist, "")), oninput: (_, parsed = parsePaths(blacklist.value, true)) => parsed !== null && (this.time.config.blacklist = parsed) }), speed = createEl("select", { className: "sia-tt-speed", title: "Playback Speed", onchange: () => this.time.config.playbackRate = Number(speed.value) }), stride = createEl("input", { className: "sia-tt-stride sia-tt-button sia-tt-mini-input", type: "number", min: "1", title: "Skip Stride i.e. how many steps count as one unit", oninput: () => this.state.stride = Math.max(1, Number(stride.value) || 1) }), stats = createEl("span", { className: "sia-tt-stats" }), limit = createEl("input", { className: "sia-tt-limit sia-tt-mini-input sia-tt-button", type: "number", min: "1", title: "Maximum number of history entries kept in memory before older entries are discarded.", oninput: () => this.time.config.limit = Math.max(1, Number(limit.value) || 1) }), delay = createEl("input", { className: "sia-tt-delay sia-tt-mini-input sia-tt-button", type: "number", min: "0", step: "50", title: "Maximum playback delay between timeline frames in milliseconds.", oninput: () => this.time.config.maxPlaybackDelay = Math.max(0, Number(delay.value) || 0) }), read = createEl("label", { className: "sia-tt-check", title: "When recording intent mutations, read previous values from the matching state path instead of the intent path. Useful for accurate undo reconstruction of intent-driven flows." }), readBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorReads, onchange: () => this.time.config.mirrorReads = readBox.checked }), write = createEl("label", { className: "sia-tt-check", title: "During playback and teleportation, mirror state writes into matching intent paths to re-enact the recorded history. Useful for accurate reconstruction of the whole session." }), writeBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorWrites, onchange: () => this.time.config.mirrorWrites = writeBox.checked }), filterRow1 = createEl("div", { className: "sia-tt-filter-row" }), filterRow2 = createEl("div", { className: "sia-tt-filter-row" }), row1 = createEl("div", { className: "sia-tt-row" }), row2 = createEl("div", { className: "sia-tt-row" }), row3 = createEl("div", { className: "sia-tt-row" }), row4 = createEl("div", { className: "sia-tt-row" }), row5 = createEl("div", { className: "sia-tt-row sia-tt-config-row" });
1171
1171
  speed.append(...[0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4, 8, 16, 32].map((v) => createEl("option", { value: String(v), textContent: `${v}x` })));
1172
1172
  status.append((box.append(frame), box), clrHistory);
1173
1173
  filters.append((filterBox.append((filterRow1.append(whitelistLabel, whitelist), filterRow1), (filterRow2.append(blacklistLabel, blacklist), filterRow2)), filterBox));
@@ -1,7 +1,7 @@
1
- import { E as EffectOptions } from '../index-BsH8KkqG.cjs';
2
- export { A as Autotracker, w as withTracker } from '../index-BsH8KkqG.cjs';
3
- export { T as TimeTravelConsole, a as TimeTravelConsoleConfig } from '../TimeTravelConsole-nYAqg57U.cjs';
4
- import '../index-DBx4TIVW.cjs';
1
+ import { E as EffectOptions } from '../index-BtHNGnRR.cjs';
2
+ export { A as Autotracker, w as withTracker } from '../index-BtHNGnRR.cjs';
3
+ export { T as TimeTravelConsole, a as TimeTravelConsoleConfig } from '../TimeTravelConsole-Dt8txKnt.cjs';
4
+ import '../index-C_djeddc.cjs';
5
5
 
6
6
  /**
7
7
  * Runs a reactive side effect in vanilla JavaScript.
@@ -1,7 +1,7 @@
1
- import { E as EffectOptions } from '../index-BsH8KkqG.js';
2
- export { A as Autotracker, w as withTracker } from '../index-BsH8KkqG.js';
3
- export { T as TimeTravelConsole, a as TimeTravelConsoleConfig } from '../TimeTravelConsole-DSifvt2z.js';
4
- import '../index-D4DGBS2N.js';
1
+ import { E as EffectOptions } from '../index-BtHNGnRR.js';
2
+ export { A as Autotracker, w as withTracker } from '../index-BtHNGnRR.js';
3
+ export { T as TimeTravelConsole, a as TimeTravelConsoleConfig } from '../TimeTravelConsole-BjDL0JjZ.js';
4
+ import '../index-CKHoDs6x.js';
5
5
 
6
6
  /**
7
7
  * Runs a reactive side effect in vanilla JavaScript.
@@ -3,10 +3,10 @@ import {
3
3
  TimeTravelConsole,
4
4
  effect,
5
5
  withTracker
6
- } from "../chunk-56H5BKHJ.js";
7
- import "../chunk-FOD32N6J.js";
6
+ } from "../chunk-ENEEV334.js";
7
+ import "../chunk-KPJ5SPXP.js";
8
8
  import "../chunk-ORK3EGB6.js";
9
- import "../chunk-DCUPDG7B.js";
9
+ import "../chunk-LZJYX2LE.js";
10
10
  export {
11
11
  Autotracker,
12
12
  TimeTravelConsole,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  wpArr
3
- } from "./chunk-FOD32N6J.js";
3
+ } from "./chunk-KPJ5SPXP.js";
4
4
  import {
5
5
  KEYS_BLOCKS,
6
6
  createEl,
@@ -15,7 +15,7 @@ import {
15
15
  canHandle,
16
16
  nuke,
17
17
  reactive
18
- } from "./chunk-DCUPDG7B.js";
18
+ } from "./chunk-LZJYX2LE.js";
19
19
 
20
20
  // src/ts/adapters/autotracker.ts
21
21
  var Autotracker = class {
@@ -200,7 +200,7 @@ var TimeTravelConsole = class _TimeTravelConsole {
200
200
  this.config = reactive({ title: `Time Travel Console ${this.index = ++_TimeTravelConsole.count}`, ...build });
201
201
  this.state.open = !!this.config.startOpen;
202
202
  let wlLive = false, blLive = false;
203
- const s = this.time.state, host = this.host = createEl("div", { className: "sia-tt-console-host" }), toggle = createEl("button", { className: "sia-tt-console-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "sia-tt-console", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: () => this.time.undo(this.state.stride) }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: () => this.time.redo(this.state.stride) }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), trackUntrack = createEl("button", { onclick: () => this.time[s.tracking ? "untrack" : "track"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.trackUntrack, false) }), range = createEl("input", { type: "range", min: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "sia-tt-io", readOnly: true, placeholder: "current payload json", title: "Current History Entry" }), io = createEl("textarea", { className: "sia-tt-io", placeholder: "timeline payload json", title: "Time History", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "sia-tt-footnote", innerHTML: "<span>Want this in your app? </span>" }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "sia-tt-status-box" }), status = createEl("div", { className: "sia-tt-status-row" }), filters = createEl("div", { className: "sia-tt-status-row" }), filterBox = createEl("div", { className: "sia-tt-status-box" }), whitelistLabel = createEl("span", { className: "muted", textContent: "Whitelist:" }), blacklistLabel = createEl("span", { className: "muted", textContent: "Blacklist:" }), whitelist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Whitelist paths", onfocus: () => wlLive = true, onblur: () => (wlLive = false, whitelist.value = formatPaths(this.time.config.whitelist, "*")), oninput: (_, parsed = parsePaths(whitelist.value)) => parsed !== null && (this.time.config.whitelist = parsed) }), blacklist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Blacklist paths", onfocus: () => blLive = true, onblur: () => (blLive = false, blacklist.value = formatPaths(this.time.config.blacklist, "")), oninput: (_, parsed = parsePaths(blacklist.value, true)) => parsed !== null && (this.time.config.blacklist = parsed) }), speed = createEl("select", { className: "sia-tt-speed", title: "Playback Speed", onchange: () => this.time.config.playbackRate = Number(speed.value) }), stride = createEl("input", { className: "sia-tt-stride sia-tt-button sia-tt-mini-input", type: "number", min: "1", title: "Skip Stride i.e. how many steps count as one unit", oninput: () => this.state.stride = Math.max(1, Number(stride.value) || 1) }), stats = createEl("span", { className: "sia-tt-stats" }), limit = createEl("input", { className: "sia-tt-limit sia-tt-mini-input sia-tt-button", type: "number", min: "1", title: "Maximum number of history entries kept in memory before older entries are discarded.", oninput: () => this.time.config.limit = Math.max(1, Number(limit.value) || 1) }), delay = createEl("input", { className: "sia-tt-delay sia-tt-mini-input sia-tt-button", type: "number", min: "0", step: "50", title: "Maximum playback delay between timeline frames in milliseconds.", oninput: () => this.time.config.maxPlaybackDelay = Math.max(0, Number(delay.value) || 0) }), read = createEl("label", { className: "sia-tt-check", title: "When recording intent mutations, read previous values from the matching state path instead of the intent path. Useful for accurate undo reconstruction of intent-driven flows." }), readBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorReads, onchange: () => this.time.config.mirrorReads = readBox.checked }), write = createEl("label", { className: "sia-tt-check", title: "During playback and teleportation, mirror state writes into matching intent paths to re-enact the recorded history. Useful for accurate reconstruction of the whole session." }), writeBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorWrites, onchange: () => this.time.config.mirrorWrites = writeBox.checked }), filterRow1 = createEl("div", { className: "sia-tt-filter-row" }), filterRow2 = createEl("div", { className: "sia-tt-filter-row" }), row1 = createEl("div", { className: "sia-tt-row" }), row2 = createEl("div", { className: "sia-tt-row" }), row3 = createEl("div", { className: "sia-tt-row" }), row4 = createEl("div", { className: "sia-tt-row" }), row5 = createEl("div", { className: "sia-tt-row sia-tt-config-row" });
203
+ const s = this.time.state, host = this.host = createEl("div", { className: "sia-tt-console-host" }), toggle = createEl("button", { className: "sia-tt-console-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "sia-tt-console", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: () => this.time.undo(this.state.stride) }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: () => this.time.redo(this.state.stride) }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), trackUntrack = createEl("button", { onclick: () => this.time[s.tracking ? "untrack" : "track"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.trackUntrack, false) }), range = createEl("input", { type: "range", min: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "sia-tt-io", readOnly: true, placeholder: "current payload json", title: "Current History Entry" }), io = createEl("textarea", { className: "sia-tt-io", placeholder: "timeline payload json", title: "Time History", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "sia-tt-footnote", innerHTML: "<span>Try this in your app? </span>" }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "sia-tt-status-box" }), status = createEl("div", { className: "sia-tt-status-row" }), filters = createEl("div", { className: "sia-tt-status-row" }), filterBox = createEl("div", { className: "sia-tt-status-box" }), whitelistLabel = createEl("span", { className: "muted", textContent: "Whitelist:" }), blacklistLabel = createEl("span", { className: "muted", textContent: "Blacklist:" }), whitelist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Whitelist paths", onfocus: () => wlLive = true, onblur: () => (wlLive = false, whitelist.value = formatPaths(this.time.config.whitelist, "*")), oninput: (_, parsed = parsePaths(whitelist.value)) => parsed !== null && (this.time.config.whitelist = parsed) }), blacklist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Blacklist paths", onfocus: () => blLive = true, onblur: () => (blLive = false, blacklist.value = formatPaths(this.time.config.blacklist, "")), oninput: (_, parsed = parsePaths(blacklist.value, true)) => parsed !== null && (this.time.config.blacklist = parsed) }), speed = createEl("select", { className: "sia-tt-speed", title: "Playback Speed", onchange: () => this.time.config.playbackRate = Number(speed.value) }), stride = createEl("input", { className: "sia-tt-stride sia-tt-button sia-tt-mini-input", type: "number", min: "1", title: "Skip Stride i.e. how many steps count as one unit", oninput: () => this.state.stride = Math.max(1, Number(stride.value) || 1) }), stats = createEl("span", { className: "sia-tt-stats" }), limit = createEl("input", { className: "sia-tt-limit sia-tt-mini-input sia-tt-button", type: "number", min: "1", title: "Maximum number of history entries kept in memory before older entries are discarded.", oninput: () => this.time.config.limit = Math.max(1, Number(limit.value) || 1) }), delay = createEl("input", { className: "sia-tt-delay sia-tt-mini-input sia-tt-button", type: "number", min: "0", step: "50", title: "Maximum playback delay between timeline frames in milliseconds.", oninput: () => this.time.config.maxPlaybackDelay = Math.max(0, Number(delay.value) || 0) }), read = createEl("label", { className: "sia-tt-check", title: "When recording intent mutations, read previous values from the matching state path instead of the intent path. Useful for accurate undo reconstruction of intent-driven flows." }), readBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorReads, onchange: () => this.time.config.mirrorReads = readBox.checked }), write = createEl("label", { className: "sia-tt-check", title: "During playback and teleportation, mirror state writes into matching intent paths to re-enact the recorded history. Useful for accurate reconstruction of the whole session." }), writeBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorWrites, onchange: () => this.time.config.mirrorWrites = writeBox.checked }), filterRow1 = createEl("div", { className: "sia-tt-filter-row" }), filterRow2 = createEl("div", { className: "sia-tt-filter-row" }), row1 = createEl("div", { className: "sia-tt-row" }), row2 = createEl("div", { className: "sia-tt-row" }), row3 = createEl("div", { className: "sia-tt-row" }), row4 = createEl("div", { className: "sia-tt-row" }), row5 = createEl("div", { className: "sia-tt-row sia-tt-config-row" });
204
204
  speed.append(...[0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4, 8, 16, 32].map((v) => createEl("option", { value: String(v), textContent: `${v}x` })));
205
205
  status.append((box.append(frame), box), clrHistory);
206
206
  filters.append((filterBox.append((filterRow1.append(whitelistLabel, whitelist), filterRow1), (filterRow2.append(blacklistLabel, blacklist), filterRow2)), filterBox));
@@ -10,7 +10,7 @@ import {
10
10
  nuke,
11
11
  reactive,
12
12
  setPath
13
- } from "./chunk-DCUPDG7B.js";
13
+ } from "./chunk-LZJYX2LE.js";
14
14
 
15
15
  // src/ts/modules/base/index.ts
16
16
  var BaseReactorModule = class {
@@ -176,24 +176,25 @@ function parseEvtOpts(options, opts, boolOpt = opts[0], result = {}) {
176
176
  function fanout(a, b, c, d) {
177
177
  const isEvPd = !!a?.target, isPath = !isEvPd && "string" === typeof b, [state2, path, olds, news, opts, type] = isEvPd ? [a.root, a.currentTarget.path, a.currentTarget.oldValue, a.currentTarget.value, b || NIL, a.type] : isPath ? [a, b, getPath(a, b), c, d || NIL, void 0] : [void 0, void 0, a, b, c || NIL, void 0], target = isEvPd ? getPath(a.root, a.currentTarget.path) : isPath ? getPath(state2, path) : olds;
178
178
  if (isEvPd && type !== "set" && type !== "delete" || !target || !canHandle(news, opts)) return;
179
+ const { merge = false, depth, atomic = true, skipUndef = false, cloneSets = false, txLabel } = opts;
179
180
  const func = () => {
180
- const walk = (target2, obj, depth = isEvPd ? 1 : Infinity, keys = Object.keys(obj)) => {
181
+ const walk = (target2, obj, depth2 = isEvPd ? 1 : Infinity, keys = Object.keys(obj)) => {
181
182
  for (let i = 0, len = keys.length; i < len; i++) {
182
183
  const key = keys[i], val = obj[key];
183
184
  try {
184
- if ((opts.atomic ?? true) && Array.isArray(val)) target2[key] = val, target2[key].length = target2[key].length;
185
- else depth > 1 && canHandle(val, opts) ? walk(target2[key] ||= {}, val, depth - 1) : (!opts.skipUndefined || val !== void 0) && (target2[key] = val);
185
+ if (atomic && Array.isArray(val)) target2[key] = cloneSets ? deepClone(val) : val, target2[key].length = target2[key].length;
186
+ else depth2 > 1 && canHandle(val, opts) ? walk(target2[key] ||= {}, val, depth2 - 1) : (!skipUndef || val !== void 0) && (target2[key] = cloneSets ? deepClone(val) : val);
186
187
  } catch (e) {
187
188
  if (e instanceof RangeError) throw e;
188
189
  }
189
190
  }
190
191
  };
191
- if ((opts.atomic ?? true) && Array.isArray(news) && isPath) setPath(state2, path, news), getPath(state2, path).length = news.length;
192
- else walk(target, opts.merge ? mergeObjs(olds, news, opts) : news, opts.depth === true ? Infinity : opts.depth);
192
+ if (atomic && Array.isArray(news) && isPath) setPath(state2, path, cloneSets ? deepClone(news) : news), getPath(state2, path).length = news.length;
193
+ else walk(target, merge ? mergeObjs(olds, news, opts) : news, depth === true ? Infinity : depth);
193
194
  };
194
- force(() => transaction(func, opts.txLabel ?? `${path ? `Fanout -> '${path}'` : `Fanout`} (Tx ${txId + 1})`), CTX.usingForce || isEvPd);
195
+ force(() => transaction(func, txLabel ?? `${path ? `Fanout -> '${path}'` : `Fanout`} (Tx ${txId + 1})`), CTX.usingForce || isEvPd);
195
196
  }
196
- var fanoutOptsArr = ["merge", "depth", "atomic", "skipUndefined"];
197
+ var fanoutOptsArr = ["merge", "depth", "atomic", "skipUndef"];
197
198
  function force(task, bool = true) {
198
199
  const prev = CTX.usingForce;
199
200
  CTX.usingForce = bool;
@@ -206,8 +207,8 @@ function force(task, bool = true) {
206
207
  function mergeObjs(o1, o2, config = NIL, pojocheck = true) {
207
208
  if (pojocheck && (!isPOJO(o1 || NIL, config) || !isPOJO(o2 || NIL, config))) return o2;
208
209
  o1 ||= {}, o2 ||= {};
209
- const merged = config.skipUndefined ? { ...o1 } : { ...o1, ...o2 };
210
- if (config.skipUndefined) {
210
+ const merged = config.skipUndef ? { ...o1 } : { ...o1, ...o2 };
211
+ if (config.skipUndef) {
211
212
  const keys2 = Object.keys(o1);
212
213
  for (let i = 0, len = keys2.length; i < len; i++) {
213
214
  const key = keys2[i], val = o2[key];
@@ -300,20 +301,18 @@ function isLeafPath(obj, path, config = CTX.defaults, value = getPath(obj, path,
300
301
  return path !== "*" && !canHandle(value, config);
301
302
  }
302
303
  function createReactorSync(rA, rB, prefixA, prefixB = "", signal) {
303
- const reactorA = getReactor(rA, true), reactorB = getReactor(rB, true);
304
+ const rtrA = getReactor(rA, true), rtrB = getReactor(rB, true);
304
305
  let origin = null;
305
- const sync = (srcOrigin, destCore, pSrc, pDest) => (val, payload) => {
306
- if (origin === (srcOrigin ^ 1)) return;
307
- const { path, object, key } = payload.target;
308
- if (pSrc && path !== pSrc && !path.startsWith(pSrc + ".")) return;
309
- origin = srcOrigin;
310
- const syncPath = Array.isArray(object) ? path.slice(0, -(key.length + 1)) : path, stripped = syncPath === pSrc ? "" : pSrc ? syncPath.slice(pSrc.length + 1) : syncPath;
311
- setPath(destCore, pDest ? stripped ? `${pDest}.${stripped}` : pDest : stripped || "*", Array.isArray(object) ? object : val);
312
- origin = null;
306
+ const sync = (src, dest, srcP, destP) => (val, payload) => {
307
+ if (origin === (src ^ 1)) return;
308
+ const { path, object: obj, key } = payload.target;
309
+ if (srcP && path !== srcP && !path.startsWith(srcP + ".")) return;
310
+ const isArr = Array.isArray(obj), origP = isArr ? path.slice(0, -(key.length + 1)) : path, syncP = origP === srcP ? "" : srcP ? origP.slice(srcP.length + 1) : origP;
311
+ origin = src, setPath(dest, destP ? syncP ? `${destP}.${syncP}` : destP : syncP || "*", isArr ? deepClone(obj) : val), origin = null;
313
312
  };
314
- const initialA = prefixA ? getPath(reactorA.core, prefixA) : reactorA.core;
315
- if (initialA !== void 0) fanout(reactorB.core, prefixB || "*", deepClone(initialA), { depth: 1 });
316
- const clupA = reactorA.watch("*", sync(0, reactorB.core, prefixA, prefixB), { signal }), clupB = reactorB.watch("*", sync(1, reactorA.core, prefixB, prefixA), { signal });
313
+ const initA = prefixA ? getPath(rtrA.core, prefixA) : rtrA.core;
314
+ if (initA !== void 0) fanout(rtrB.core, prefixB || "*", initA, { depth: 1, cloneSets: true, txLabel: `ReactorSync: ${prefixA}^ <-> ${prefixB}` });
315
+ const clupA = rtrA.watch("*", sync(0, rtrB.core, prefixA, prefixB), { signal }), clupB = rtrB.watch("*", sync(1, rtrA.core, prefixB, prefixA), { signal });
317
316
  return () => (clupA(), clupB());
318
317
  }
319
318
 
@@ -509,10 +509,12 @@ interface FanoutOptionsTuple extends Partial<Record<(typeof fanoutOptsArr)[numbe
509
509
  depth?: number | boolean;
510
510
  /** Whether to assign arrays as a whole and only touch `.length` for common cases. Only works with the `path` parameter overload or in nested levels.
511
511
  * Arrays can lead to unnecessary work as more often than not, you won't be watching index paths but waiting on the parent bubble instead.
512
- * If you happen to be watching, it might be more optimal to re-set it yourself if it's only a few indexes or just turn set this to `false`. */
512
+ * If you happen to be watching, it might be more optimal to re-set it yourself if it's only a few indexes or just set this to `false`. @default `true` */
513
513
  atomic?: boolean;
514
514
  /** Whether to skip `undefined` values during fanout. @default `false`. */
515
- skipUndefined?: boolean;
515
+ skipUndef?: boolean;
516
+ /** Whether to clone before setting any final values, prevents unintended reference sharing across the state tree. @default `false`. */
517
+ cloneSets?: boolean;
516
518
  /** A label for the transaction that will be started, useful for debugging and tracking. @default `Fanout -> "${path}"` : `Fanout`} (Tx ${CTX.txId})`. */
517
519
  txLabel?: string;
518
520
  }
@@ -536,7 +538,7 @@ declare function fanout<T extends object>(target: T, value: Partial<T> | Partial
536
538
  declare function fanout<T extends object, P extends WildPaths<T> = WildPaths<T>>(state: T, path: P, value: Partial<PathValue<T, P>>, options?: {
537
539
  crossRealms?: boolean;
538
540
  } & FanoutOptionsTuple): void;
539
- declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndefined"];
541
+ declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndef"];
540
542
  /**
541
543
  * Executes a task while forcing all reactive writes to bypass equality checks.
542
544
  * @param task The mutation logic to execute.
@@ -545,13 +547,13 @@ declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndefine
545
547
  */
546
548
  declare function force<T>(task: () => T, bool?: boolean): T;
547
549
  /**
548
- * Deep-merges object-like values, does necessary checks so use without doubts. Only `o2` keys are checked when `skipUndefined` is true.
550
+ * Deep-merges object-like values, does necessary checks so use without doubts. Only `o2` keys are checked when `skipUndef` is true.
549
551
  * @example
550
552
  * const next = mergeObjs({ user: { name: "Kosi" } }, { user: { role: "admin" } }); // { ...o1, ...o2 } // o2 over o1 and deep!
551
553
  */
552
554
  declare function mergeObjs<T1 extends object, T2 extends object>(o1?: T1 | null, o2?: T2 | null, config?: {
553
555
  crossRealms?: boolean;
554
- skipUndefined?: boolean;
556
+ skipUndef?: boolean;
555
557
  }, pojocheck?: boolean): DeepMerge<T1, T2>;
556
558
  /** Returns [path, parent, value] records from root to the target path. */
557
559
  declare function getTrailRecords<T extends object>(obj: T, path: WildPaths<T>, reverse?: boolean): [WildPaths<T>, PathBranchValue<T, WildPaths<T>>, PathValue<T, WildPaths<T>>][];
@@ -592,7 +594,7 @@ declare function isLeafPath<T extends object, const S extends string = ".", P ex
592
594
  separator?: S;
593
595
  } & typeof CTX.defaults, value?: PathValue<T, P, S>): boolean;
594
596
  /**
595
- * Creates a two-way, array-safe, echo-proof sync bridge between two S.I.A Reactors. Uses a synchronous origin lock to prevent infinite echo loops.
597
+ * Creates a two-way, array-atomic, echo-proof sync bridge between two S.I.A Reactors. Uses a synchronous origin lock to prevent infinite echo loops.
596
598
  * On setup, `rA` hydrates `rB` at `prefixB` with a deep clone of its current state at `prefixA` (primary drives initial truth).
597
599
  * @param rA Primary reactor — source of truth. Its `prefixA` slice seeds `rB.prefixB` on setup.
598
600
  * @param rB Secondary reactor — the wider store (e.g. `ctlr.config`). Holds the primary at a named path.
@@ -509,10 +509,12 @@ interface FanoutOptionsTuple extends Partial<Record<(typeof fanoutOptsArr)[numbe
509
509
  depth?: number | boolean;
510
510
  /** Whether to assign arrays as a whole and only touch `.length` for common cases. Only works with the `path` parameter overload or in nested levels.
511
511
  * Arrays can lead to unnecessary work as more often than not, you won't be watching index paths but waiting on the parent bubble instead.
512
- * If you happen to be watching, it might be more optimal to re-set it yourself if it's only a few indexes or just turn set this to `false`. */
512
+ * If you happen to be watching, it might be more optimal to re-set it yourself if it's only a few indexes or just set this to `false`. @default `true` */
513
513
  atomic?: boolean;
514
514
  /** Whether to skip `undefined` values during fanout. @default `false`. */
515
- skipUndefined?: boolean;
515
+ skipUndef?: boolean;
516
+ /** Whether to clone before setting any final values, prevents unintended reference sharing across the state tree. @default `false`. */
517
+ cloneSets?: boolean;
516
518
  /** A label for the transaction that will be started, useful for debugging and tracking. @default `Fanout -> "${path}"` : `Fanout`} (Tx ${CTX.txId})`. */
517
519
  txLabel?: string;
518
520
  }
@@ -536,7 +538,7 @@ declare function fanout<T extends object>(target: T, value: Partial<T> | Partial
536
538
  declare function fanout<T extends object, P extends WildPaths<T> = WildPaths<T>>(state: T, path: P, value: Partial<PathValue<T, P>>, options?: {
537
539
  crossRealms?: boolean;
538
540
  } & FanoutOptionsTuple): void;
539
- declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndefined"];
541
+ declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndef"];
540
542
  /**
541
543
  * Executes a task while forcing all reactive writes to bypass equality checks.
542
544
  * @param task The mutation logic to execute.
@@ -545,13 +547,13 @@ declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndefine
545
547
  */
546
548
  declare function force<T>(task: () => T, bool?: boolean): T;
547
549
  /**
548
- * Deep-merges object-like values, does necessary checks so use without doubts. Only `o2` keys are checked when `skipUndefined` is true.
550
+ * Deep-merges object-like values, does necessary checks so use without doubts. Only `o2` keys are checked when `skipUndef` is true.
549
551
  * @example
550
552
  * const next = mergeObjs({ user: { name: "Kosi" } }, { user: { role: "admin" } }); // { ...o1, ...o2 } // o2 over o1 and deep!
551
553
  */
552
554
  declare function mergeObjs<T1 extends object, T2 extends object>(o1?: T1 | null, o2?: T2 | null, config?: {
553
555
  crossRealms?: boolean;
554
- skipUndefined?: boolean;
556
+ skipUndef?: boolean;
555
557
  }, pojocheck?: boolean): DeepMerge<T1, T2>;
556
558
  /** Returns [path, parent, value] records from root to the target path. */
557
559
  declare function getTrailRecords<T extends object>(obj: T, path: WildPaths<T>, reverse?: boolean): [WildPaths<T>, PathBranchValue<T, WildPaths<T>>, PathValue<T, WildPaths<T>>][];
@@ -592,7 +594,7 @@ declare function isLeafPath<T extends object, const S extends string = ".", P ex
592
594
  separator?: S;
593
595
  } & typeof CTX.defaults, value?: PathValue<T, P, S>): boolean;
594
596
  /**
595
- * Creates a two-way, array-safe, echo-proof sync bridge between two S.I.A Reactors. Uses a synchronous origin lock to prevent infinite echo loops.
597
+ * Creates a two-way, array-atomic, echo-proof sync bridge between two S.I.A Reactors. Uses a synchronous origin lock to prevent infinite echo loops.
596
598
  * On setup, `rA` hydrates `rB` at `prefixB` with a deep clone of its current state at `prefixA` (primary drives initial truth).
597
599
  * @param rA Primary reactor — source of truth. Its `prefixA` slice seeds `rB.prefixB` on setup.
598
600
  * @param rB Secondary reactor — the wider store (e.g. `ctlr.config`). Holds the primary at a named path.
@@ -1,4 +1,4 @@
1
- import { P as Paths, a as PathValue, b as ReactorModuleId, c as ReactorModulePathConfig, B as BaseReactorModule, T as Transaction, d as Reactor, e as REvent, f as Payload } from './index-BsH8KkqG.js';
1
+ import { P as Paths, a as PathValue, b as ReactorModuleId, c as ReactorModulePathConfig, B as BaseReactorModule, T as Transaction, d as Reactor, e as REvent, f as Payload } from './index-BtHNGnRR.js';
2
2
 
3
3
  interface StorageAdapterConstructor<Config extends StorageAdapterConfig = StorageAdapterConfig> {
4
4
  new (config?: Partial<Config>): StorageAdapter<any, Config>;
@@ -1,4 +1,4 @@
1
- import { P as Paths, a as PathValue, b as ReactorModuleId, c as ReactorModulePathConfig, B as BaseReactorModule, T as Transaction, d as Reactor, e as REvent, f as Payload } from './index-BsH8KkqG.cjs';
1
+ import { P as Paths, a as PathValue, b as ReactorModuleId, c as ReactorModulePathConfig, B as BaseReactorModule, T as Transaction, d as Reactor, e as REvent, f as Payload } from './index-BtHNGnRR.cjs';
2
2
 
3
3
  interface StorageAdapterConstructor<Config extends StorageAdapterConfig = StorageAdapterConfig> {
4
4
  new (config?: Partial<Config>): StorageAdapter<any, Config>;
package/dist/index.d.cts CHANGED
@@ -1 +1 @@
1
- export { V as APIKey, X as AddDepth, Y as CTX, Z as ChildPaths, _ as DeepKeys, $ as DeepMerge, a0 as DeepPartial, K as DeepReadonly, a1 as DeepRequired, a2 as Deleter, a3 as DeleterRecord, a4 as DepthConfig, a5 as DirectPayload, a6 as EVT_OPTS, E as EffectOptions, a7 as Getter, a8 as GetterRecord, a9 as INDIFFABLE, aa as INERTIA, L as Inert, ab as Intent, ac as Listener, ad as ListenerOptions, ae as ListenerOptionsTuple, af as ListenerRecord, ag as Live, ah as MaxDepth, ai as NIL, aj as NOOP, ak as NextDepth, al as NoTraverse, am as PathBranch, an as PathBranchValue, ao as PathDepth, ap as PathKey, aq as PathLeaf, a as PathValue, P as Paths, f as Payload, ar as PrevDepth, as as Primitive, at as Pure, au as RAW, av as REJECTABLE, e as REvent, aw as RTR_BATCH, ax as RTR_LOG, R as Reactive, ay as ReactivePreferences, d as Reactor, J as ReactorBuild, az as ReactorEvent, aA as SSVERSION, aB as Setter, aC as SetterRecord, aD as Stable, aE as State, aF as StrictPathKey, aG as SubtractDepth, aH as SyncOptions, aI as SyncOptionsTuple, aJ as TERMINATOR, aK as Target, aL as Unflatten, aM as UnionToIntersection, aN as UpdatePayload, aO as VERSION, aP as Volatile, aQ as Watcher, aR as WatcherRecord, W as WildPaths, aS as getRaw, aT as getReactor, aU as getSnapshotVersion, aV as getVersion, aW as inert, aX as intent, aY as isInert, aZ as isIntent, a_ as isVolatile, a$ as live, b0 as methods, b1 as reactive, b2 as stable, b3 as state, b4 as volatile } from './index-BsH8KkqG.cjs';
1
+ export { V as APIKey, X as AddDepth, Y as CTX, Z as ChildPaths, _ as DeepKeys, $ as DeepMerge, a0 as DeepPartial, K as DeepReadonly, a1 as DeepRequired, a2 as Deleter, a3 as DeleterRecord, a4 as DepthConfig, a5 as DirectPayload, a6 as EVT_OPTS, E as EffectOptions, a7 as Getter, a8 as GetterRecord, a9 as INDIFFABLE, aa as INERTIA, L as Inert, ab as Intent, ac as Listener, ad as ListenerOptions, ae as ListenerOptionsTuple, af as ListenerRecord, ag as Live, ah as MaxDepth, ai as NIL, aj as NOOP, ak as NextDepth, al as NoTraverse, am as PathBranch, an as PathBranchValue, ao as PathDepth, ap as PathKey, aq as PathLeaf, a as PathValue, P as Paths, f as Payload, ar as PrevDepth, as as Primitive, at as Pure, au as RAW, av as REJECTABLE, e as REvent, aw as RTR_BATCH, ax as RTR_LOG, R as Reactive, ay as ReactivePreferences, d as Reactor, J as ReactorBuild, az as ReactorEvent, aA as SSVERSION, aB as Setter, aC as SetterRecord, aD as Stable, aE as State, aF as StrictPathKey, aG as SubtractDepth, aH as SyncOptions, aI as SyncOptionsTuple, aJ as TERMINATOR, aK as Target, aL as Unflatten, aM as UnionToIntersection, aN as UpdatePayload, aO as VERSION, aP as Volatile, aQ as Watcher, aR as WatcherRecord, W as WildPaths, aS as getRaw, aT as getReactor, aU as getSnapshotVersion, aV as getVersion, aW as inert, aX as intent, aY as isInert, aZ as isIntent, a_ as isVolatile, a$ as live, b0 as methods, b1 as reactive, b2 as stable, b3 as state, b4 as volatile } from './index-BtHNGnRR.cjs';
package/dist/index.d.ts CHANGED
@@ -1 +1 @@
1
- export { V as APIKey, X as AddDepth, Y as CTX, Z as ChildPaths, _ as DeepKeys, $ as DeepMerge, a0 as DeepPartial, K as DeepReadonly, a1 as DeepRequired, a2 as Deleter, a3 as DeleterRecord, a4 as DepthConfig, a5 as DirectPayload, a6 as EVT_OPTS, E as EffectOptions, a7 as Getter, a8 as GetterRecord, a9 as INDIFFABLE, aa as INERTIA, L as Inert, ab as Intent, ac as Listener, ad as ListenerOptions, ae as ListenerOptionsTuple, af as ListenerRecord, ag as Live, ah as MaxDepth, ai as NIL, aj as NOOP, ak as NextDepth, al as NoTraverse, am as PathBranch, an as PathBranchValue, ao as PathDepth, ap as PathKey, aq as PathLeaf, a as PathValue, P as Paths, f as Payload, ar as PrevDepth, as as Primitive, at as Pure, au as RAW, av as REJECTABLE, e as REvent, aw as RTR_BATCH, ax as RTR_LOG, R as Reactive, ay as ReactivePreferences, d as Reactor, J as ReactorBuild, az as ReactorEvent, aA as SSVERSION, aB as Setter, aC as SetterRecord, aD as Stable, aE as State, aF as StrictPathKey, aG as SubtractDepth, aH as SyncOptions, aI as SyncOptionsTuple, aJ as TERMINATOR, aK as Target, aL as Unflatten, aM as UnionToIntersection, aN as UpdatePayload, aO as VERSION, aP as Volatile, aQ as Watcher, aR as WatcherRecord, W as WildPaths, aS as getRaw, aT as getReactor, aU as getSnapshotVersion, aV as getVersion, aW as inert, aX as intent, aY as isInert, aZ as isIntent, a_ as isVolatile, a$ as live, b0 as methods, b1 as reactive, b2 as stable, b3 as state, b4 as volatile } from './index-BsH8KkqG.js';
1
+ export { V as APIKey, X as AddDepth, Y as CTX, Z as ChildPaths, _ as DeepKeys, $ as DeepMerge, a0 as DeepPartial, K as DeepReadonly, a1 as DeepRequired, a2 as Deleter, a3 as DeleterRecord, a4 as DepthConfig, a5 as DirectPayload, a6 as EVT_OPTS, E as EffectOptions, a7 as Getter, a8 as GetterRecord, a9 as INDIFFABLE, aa as INERTIA, L as Inert, ab as Intent, ac as Listener, ad as ListenerOptions, ae as ListenerOptionsTuple, af as ListenerRecord, ag as Live, ah as MaxDepth, ai as NIL, aj as NOOP, ak as NextDepth, al as NoTraverse, am as PathBranch, an as PathBranchValue, ao as PathDepth, ap as PathKey, aq as PathLeaf, a as PathValue, P as Paths, f as Payload, ar as PrevDepth, as as Primitive, at as Pure, au as RAW, av as REJECTABLE, e as REvent, aw as RTR_BATCH, ax as RTR_LOG, R as Reactive, ay as ReactivePreferences, d as Reactor, J as ReactorBuild, az as ReactorEvent, aA as SSVERSION, aB as Setter, aC as SetterRecord, aD as Stable, aE as State, aF as StrictPathKey, aG as SubtractDepth, aH as SyncOptions, aI as SyncOptionsTuple, aJ as TERMINATOR, aK as Target, aL as Unflatten, aM as UnionToIntersection, aN as UpdatePayload, aO as VERSION, aP as Volatile, aQ as Watcher, aR as WatcherRecord, W as WildPaths, aS as getRaw, aT as getReactor, aU as getSnapshotVersion, aV as getVersion, aW as inert, aX as intent, aY as isInert, aZ as isIntent, a_ as isVolatile, a$ as live, b0 as methods, b1 as reactive, b2 as stable, b3 as state, b4 as volatile } from './index-BtHNGnRR.js';
package/dist/index.js CHANGED
@@ -30,7 +30,7 @@ import {
30
30
  stable,
31
31
  state,
32
32
  volatile
33
- } from "./chunk-DCUPDG7B.js";
33
+ } from "./chunk-LZJYX2LE.js";
34
34
  export {
35
35
  CTX,
36
36
  EVT_OPTS,
package/dist/modules.cjs CHANGED
@@ -215,24 +215,25 @@ function parseEvtOpts(options, opts, boolOpt = opts[0], result = {}) {
215
215
  function fanout(a, b, c, d) {
216
216
  const isEvPd = !!a?.target, isPath = !isEvPd && "string" === typeof b, [state, path, olds, news, opts, type] = isEvPd ? [a.root, a.currentTarget.path, a.currentTarget.oldValue, a.currentTarget.value, b || NIL, a.type] : isPath ? [a, b, getPath(a, b), c, d || NIL, void 0] : [void 0, void 0, a, b, c || NIL, void 0], target = isEvPd ? getPath(a.root, a.currentTarget.path) : isPath ? getPath(state, path) : olds;
217
217
  if (isEvPd && type !== "set" && type !== "delete" || !target || !canHandle(news, opts)) return;
218
+ const { merge = false, depth, atomic = true, skipUndef = false, cloneSets = false, txLabel } = opts;
218
219
  const func = () => {
219
- const walk = (target2, obj, depth = isEvPd ? 1 : Infinity, keys = Object.keys(obj)) => {
220
+ const walk = (target2, obj, depth2 = isEvPd ? 1 : Infinity, keys = Object.keys(obj)) => {
220
221
  for (let i = 0, len = keys.length; i < len; i++) {
221
222
  const key = keys[i], val = obj[key];
222
223
  try {
223
- if ((opts.atomic ?? true) && Array.isArray(val)) target2[key] = val, target2[key].length = target2[key].length;
224
- else depth > 1 && canHandle(val, opts) ? walk(target2[key] ||= {}, val, depth - 1) : (!opts.skipUndefined || val !== void 0) && (target2[key] = val);
224
+ if (atomic && Array.isArray(val)) target2[key] = cloneSets ? deepClone(val) : val, target2[key].length = target2[key].length;
225
+ else depth2 > 1 && canHandle(val, opts) ? walk(target2[key] ||= {}, val, depth2 - 1) : (!skipUndef || val !== void 0) && (target2[key] = cloneSets ? deepClone(val) : val);
225
226
  } catch (e) {
226
227
  if (e instanceof RangeError) throw e;
227
228
  }
228
229
  }
229
230
  };
230
- if ((opts.atomic ?? true) && Array.isArray(news) && isPath) setPath(state, path, news), getPath(state, path).length = news.length;
231
- else walk(target, opts.merge ? mergeObjs(olds, news, opts) : news, opts.depth === true ? Infinity : opts.depth);
231
+ if (atomic && Array.isArray(news) && isPath) setPath(state, path, cloneSets ? deepClone(news) : news), getPath(state, path).length = news.length;
232
+ else walk(target, merge ? mergeObjs(olds, news, opts) : news, depth === true ? Infinity : depth);
232
233
  };
233
- force(() => transaction(func, opts.txLabel ?? `${path ? `Fanout -> '${path}'` : `Fanout`} (Tx ${txId + 1})`), CTX.usingForce || isEvPd);
234
+ force(() => transaction(func, txLabel ?? `${path ? `Fanout -> '${path}'` : `Fanout`} (Tx ${txId + 1})`), CTX.usingForce || isEvPd);
234
235
  }
235
- var fanoutOptsArr = ["merge", "depth", "atomic", "skipUndefined"];
236
+ var fanoutOptsArr = ["merge", "depth", "atomic", "skipUndef"];
236
237
  function force(task, bool = true) {
237
238
  const prev = CTX.usingForce;
238
239
  CTX.usingForce = bool;
@@ -245,8 +246,8 @@ function force(task, bool = true) {
245
246
  function mergeObjs(o1, o2, config = NIL, pojocheck = true) {
246
247
  if (pojocheck && (!isPOJO(o1 || NIL, config) || !isPOJO(o2 || NIL, config))) return o2;
247
248
  o1 ||= {}, o2 ||= {};
248
- const merged = config.skipUndefined ? { ...o1 } : { ...o1, ...o2 };
249
- if (config.skipUndefined) {
249
+ const merged = config.skipUndef ? { ...o1 } : { ...o1, ...o2 };
250
+ if (config.skipUndef) {
250
251
  const keys2 = Object.keys(o1);
251
252
  for (let i = 0, len = keys2.length; i < len; i++) {
252
253
  const key = keys2[i], val = o2[key];
@@ -1650,9 +1651,9 @@ var PersistModule = class extends BaseReactorModule {
1650
1651
  for (const [rid, rtr] of this.deps) this.attachPaths(rtr, rid);
1651
1652
  value && this.adapter?.remove(this.config.key);
1652
1653
  }
1653
- hydrate(entry, rtr, rid = this.rids.get(rtr), { depth, merge = true, atomic, skipUndefined } = parseEvtOpts(this.config.fanout, fanoutOptsArr, "depth"), tick = true) {
1654
+ hydrate(entry, rtr, rid = this.rids.get(rtr), { depth, merge = true, atomic, skipUndef } = parseEvtOpts(this.config.fanout, fanoutOptsArr, "depth"), tick = true) {
1654
1655
  if (!entry) return;
1655
- const whites = this.getPaths(rid), blacks = this.getPaths(rid, this.config.blacklist, true), set = (p, curr, prev) => (depth ? fanout : setPath)(rtr.core, p, merge ? mergeObjs(curr, prev, rtr.config) : prev, depth ? { depth, atomic, skipUndefined, crossRealms: rtr.config.crossRealms } : void 0);
1656
+ const whites = this.getPaths(rid), blacks = this.getPaths(rid, this.config.blacklist, true), set = (p, curr, prev) => (depth ? fanout : setPath)(rtr.core, p, merge ? mergeObjs(curr, prev, rtr.config) : prev, depth ? { depth, atomic, skipUndef, crossRealms: rtr.config.crossRealms } : void 0);
1656
1657
  let ticks = this.tickMap.get(rid);
1657
1658
  for (let i = 0, len = blacks.length; i < len; i++) deletePath(entry, blacks[i]);
1658
1659
  for (let i = 0, len = whites.length; i < len; i++) {
@@ -1,7 +1,7 @@
1
- import { P as Paths, c as ReactorModulePathConfig, L as Inert, F as FanoutOptionsTuple, B as BaseReactorModule, b as ReactorModuleId, d as Reactor, e as REvent } from './index-BsH8KkqG.cjs';
2
- export { M as ModulePaths, N as ReactorModuleConstructor, T as Transaction, O as endTx, Q as startTx, S as transaction, U as txId } from './index-BsH8KkqG.cjs';
3
- import { S as StorageAdapterConfig, a as StorageAdapter, J as JSONReviver, b as JSONReplacer, A as AsyncStorageAdapter, c as StorageAdapterConstructor, d as AsyncStorageAdapterConstructor, e as TimeTravelConfig, H as HistoryEntry, f as HistoryNode } from './index-DBx4TIVW.cjs';
4
- export { B as BaseStorageAdapter, g as HistoryTransaction, T as TimeTravelModule, h as TimeTravelState } from './index-DBx4TIVW.cjs';
1
+ import { P as Paths, c as ReactorModulePathConfig, L as Inert, F as FanoutOptionsTuple, B as BaseReactorModule, b as ReactorModuleId, d as Reactor, e as REvent } from './index-BtHNGnRR.cjs';
2
+ export { M as ModulePaths, N as ReactorModuleConstructor, T as Transaction, O as endTx, Q as startTx, S as transaction, U as txId } from './index-BtHNGnRR.cjs';
3
+ import { S as StorageAdapterConfig, a as StorageAdapter, J as JSONReviver, b as JSONReplacer, A as AsyncStorageAdapter, c as StorageAdapterConstructor, d as AsyncStorageAdapterConstructor, e as TimeTravelConfig, H as HistoryEntry, f as HistoryNode } from './index-C_djeddc.cjs';
4
+ export { B as BaseStorageAdapter, g as HistoryTransaction, T as TimeTravelModule, h as TimeTravelState } from './index-C_djeddc.cjs';
5
5
 
6
6
  /**
7
7
  * - The LocalStorage Adapter (~5MB per origin, browser-dependent).
@@ -291,7 +291,7 @@ declare class PersistModule<T extends object = any, P extends Paths<T> = Paths<T
291
291
  protected persist(): Promise<void>;
292
292
  protected handleAdapter({ value }: REvent<PersistConfig<T, P>, "adapter">): Promise<void>;
293
293
  protected handleDisabled({ value }: REvent<PersistConfig<T, P>, "disabled">): void;
294
- protected hydrate(entry: any, rtr: Reactor<any>, rid?: ReactorModuleId, { depth, merge, atomic, skipUndefined }?: FanoutOptionsTuple & {
294
+ protected hydrate(entry: any, rtr: Reactor<any>, rid?: ReactorModuleId, { depth, merge, atomic, skipUndef }?: FanoutOptionsTuple & {
295
295
  depth: number | boolean | undefined;
296
296
  }, tick?: boolean): void;
297
297
  /** Clears persisted payload for this module instance by removing the stored key from the adapter and drops any pending save. */
package/dist/modules.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { P as Paths, c as ReactorModulePathConfig, L as Inert, F as FanoutOptionsTuple, B as BaseReactorModule, b as ReactorModuleId, d as Reactor, e as REvent } from './index-BsH8KkqG.js';
2
- export { M as ModulePaths, N as ReactorModuleConstructor, T as Transaction, O as endTx, Q as startTx, S as transaction, U as txId } from './index-BsH8KkqG.js';
3
- import { S as StorageAdapterConfig, a as StorageAdapter, J as JSONReviver, b as JSONReplacer, A as AsyncStorageAdapter, c as StorageAdapterConstructor, d as AsyncStorageAdapterConstructor, e as TimeTravelConfig, H as HistoryEntry, f as HistoryNode } from './index-D4DGBS2N.js';
4
- export { B as BaseStorageAdapter, g as HistoryTransaction, T as TimeTravelModule, h as TimeTravelState } from './index-D4DGBS2N.js';
1
+ import { P as Paths, c as ReactorModulePathConfig, L as Inert, F as FanoutOptionsTuple, B as BaseReactorModule, b as ReactorModuleId, d as Reactor, e as REvent } from './index-BtHNGnRR.js';
2
+ export { M as ModulePaths, N as ReactorModuleConstructor, T as Transaction, O as endTx, Q as startTx, S as transaction, U as txId } from './index-BtHNGnRR.js';
3
+ import { S as StorageAdapterConfig, a as StorageAdapter, J as JSONReviver, b as JSONReplacer, A as AsyncStorageAdapter, c as StorageAdapterConstructor, d as AsyncStorageAdapterConstructor, e as TimeTravelConfig, H as HistoryEntry, f as HistoryNode } from './index-CKHoDs6x.js';
4
+ export { B as BaseStorageAdapter, g as HistoryTransaction, T as TimeTravelModule, h as TimeTravelState } from './index-CKHoDs6x.js';
5
5
 
6
6
  /**
7
7
  * - The LocalStorage Adapter (~5MB per origin, browser-dependent).
@@ -291,7 +291,7 @@ declare class PersistModule<T extends object = any, P extends Paths<T> = Paths<T
291
291
  protected persist(): Promise<void>;
292
292
  protected handleAdapter({ value }: REvent<PersistConfig<T, P>, "adapter">): Promise<void>;
293
293
  protected handleDisabled({ value }: REvent<PersistConfig<T, P>, "disabled">): void;
294
- protected hydrate(entry: any, rtr: Reactor<any>, rid?: ReactorModuleId, { depth, merge, atomic, skipUndefined }?: FanoutOptionsTuple & {
294
+ protected hydrate(entry: any, rtr: Reactor<any>, rid?: ReactorModuleId, { depth, merge, atomic, skipUndef }?: FanoutOptionsTuple & {
295
295
  depth: number | boolean | undefined;
296
296
  }, tick?: boolean): void;
297
297
  /** Clears persisted payload for this module instance by removing the stored key from the adapter and drops any pending save. */
package/dist/modules.js CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-JGEI2Q4M.js";
6
6
  import {
7
7
  BaseReactorModule
8
- } from "./chunk-FOD32N6J.js";
8
+ } from "./chunk-KPJ5SPXP.js";
9
9
  import "./chunk-ORK3EGB6.js";
10
10
  import {
11
11
  CTX,
@@ -27,7 +27,7 @@ import {
27
27
  transaction,
28
28
  txId,
29
29
  withMeta
30
- } from "./chunk-DCUPDG7B.js";
30
+ } from "./chunk-LZJYX2LE.js";
31
31
 
32
32
  // src/ts/modules/persist/storage/base/index.ts
33
33
  var BaseStorageAdapter = class {
@@ -489,9 +489,9 @@ var PersistModule = class extends BaseReactorModule {
489
489
  for (const [rid, rtr] of this.deps) this.attachPaths(rtr, rid);
490
490
  value && this.adapter?.remove(this.config.key);
491
491
  }
492
- hydrate(entry, rtr, rid = this.rids.get(rtr), { depth, merge = true, atomic, skipUndefined } = parseEvtOpts(this.config.fanout, fanoutOptsArr, "depth"), tick = true) {
492
+ hydrate(entry, rtr, rid = this.rids.get(rtr), { depth, merge = true, atomic, skipUndef } = parseEvtOpts(this.config.fanout, fanoutOptsArr, "depth"), tick = true) {
493
493
  if (!entry) return;
494
- const whites = this.getPaths(rid), blacks = this.getPaths(rid, this.config.blacklist, true), set = (p, curr, prev) => (depth ? fanout : setPath)(rtr.core, p, merge ? mergeObjs(curr, prev, rtr.config) : prev, depth ? { depth, atomic, skipUndefined, crossRealms: rtr.config.crossRealms } : void 0);
494
+ const whites = this.getPaths(rid), blacks = this.getPaths(rid, this.config.blacklist, true), set = (p, curr, prev) => (depth ? fanout : setPath)(rtr.core, p, merge ? mergeObjs(curr, prev, rtr.config) : prev, depth ? { depth, atomic, skipUndef, crossRealms: rtr.config.crossRealms } : void 0);
495
495
  let ticks = this.tickMap.get(rid);
496
496
  for (let i = 0, len = blacks.length; i < len; i++) deletePath(entry, blacks[i]);
497
497
  for (let i = 0, len = whites.length; i < len; i++) {
package/dist/super.d.ts CHANGED
@@ -509,10 +509,12 @@ interface FanoutOptionsTuple extends Partial<Record<(typeof fanoutOptsArr)[numbe
509
509
  depth?: number | boolean;
510
510
  /** Whether to assign arrays as a whole and only touch `.length` for common cases. Only works with the `path` parameter overload or in nested levels.
511
511
  * Arrays can lead to unnecessary work as more often than not, you won't be watching index paths but waiting on the parent bubble instead.
512
- * If you happen to be watching, it might be more optimal to re-set it yourself if it's only a few indexes or just turn set this to `false`. */
512
+ * If you happen to be watching, it might be more optimal to re-set it yourself if it's only a few indexes or just set this to `false`. @default `true` */
513
513
  atomic?: boolean;
514
514
  /** Whether to skip `undefined` values during fanout. @default `false`. */
515
- skipUndefined?: boolean;
515
+ skipUndef?: boolean;
516
+ /** Whether to clone before setting any final values, prevents unintended reference sharing across the state tree. @default `false`. */
517
+ cloneSets?: boolean;
516
518
  /** A label for the transaction that will be started, useful for debugging and tracking. @default `Fanout -> "${path}"` : `Fanout`} (Tx ${CTX.txId})`. */
517
519
  txLabel?: string;
518
520
  }
@@ -536,7 +538,7 @@ declare function fanout<T extends object>(target: T, value: Partial<T> | Partial
536
538
  declare function fanout<T extends object, P extends WildPaths<T> = WildPaths<T>>(state: T, path: P, value: Partial<PathValue<T, P>>, options?: {
537
539
  crossRealms?: boolean;
538
540
  } & FanoutOptionsTuple): void;
539
- declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndefined"];
541
+ declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndef"];
540
542
  /**
541
543
  * Executes a task while forcing all reactive writes to bypass equality checks.
542
544
  * @param task The mutation logic to execute.
@@ -545,13 +547,13 @@ declare const fanoutOptsArr: readonly ["merge", "depth", "atomic", "skipUndefine
545
547
  */
546
548
  declare function force<T>(task: () => T, bool?: boolean): T;
547
549
  /**
548
- * Deep-merges object-like values, does necessary checks so use without doubts. Only `o2` keys are checked when `skipUndefined` is true.
550
+ * Deep-merges object-like values, does necessary checks so use without doubts. Only `o2` keys are checked when `skipUndef` is true.
549
551
  * @example
550
552
  * const next = mergeObjs({ user: { name: "Kosi" } }, { user: { role: "admin" } }); // { ...o1, ...o2 } // o2 over o1 and deep!
551
553
  */
552
554
  declare function mergeObjs<T1 extends object, T2 extends object>(o1?: T1 | null, o2?: T2 | null, config?: {
553
555
  crossRealms?: boolean;
554
- skipUndefined?: boolean;
556
+ skipUndef?: boolean;
555
557
  }, pojocheck?: boolean): DeepMerge<T1, T2>;
556
558
  /** Returns [path, parent, value] records from root to the target path. */
557
559
  declare function getTrailRecords<T extends object>(obj: T, path: WildPaths<T>, reverse?: boolean): [WildPaths<T>, PathBranchValue<T, WildPaths<T>>, PathValue<T, WildPaths<T>>][];
@@ -592,7 +594,7 @@ declare function isLeafPath<T extends object, const S extends string = ".", P ex
592
594
  separator?: S;
593
595
  } & typeof CTX.defaults, value?: PathValue<T, P, S>): boolean;
594
596
  /**
595
- * Creates a two-way, array-safe, echo-proof sync bridge between two S.I.A Reactors. Uses a synchronous origin lock to prevent infinite echo loops.
597
+ * Creates a two-way, array-atomic, echo-proof sync bridge between two S.I.A Reactors. Uses a synchronous origin lock to prevent infinite echo loops.
596
598
  * On setup, `rA` hydrates `rB` at `prefixB` with a deep clone of its current state at `prefixA` (primary drives initial truth).
597
599
  * @param rA Primary reactor — source of truth. Its `prefixA` slice seeds `rB.prefixB` on setup.
598
600
  * @param rB Secondary reactor — the wider store (e.g. `ctlr.config`). Holds the primary at a named path.
@@ -1956,7 +1958,7 @@ declare class PersistModule<T extends object = any, P extends Paths<T> = Paths<T
1956
1958
  protected persist(): Promise<void>;
1957
1959
  protected handleAdapter({ value }: REvent<PersistConfig<T, P>, "adapter">): Promise<void>;
1958
1960
  protected handleDisabled({ value }: REvent<PersistConfig<T, P>, "disabled">): void;
1959
- protected hydrate(entry: any, rtr: Reactor<any>, rid?: ReactorModuleId, { depth, merge, atomic, skipUndefined }?: FanoutOptionsTuple & {
1961
+ protected hydrate(entry: any, rtr: Reactor<any>, rid?: ReactorModuleId, { depth, merge, atomic, skipUndef }?: FanoutOptionsTuple & {
1960
1962
  depth: number | boolean | undefined;
1961
1963
  }, tick?: boolean): void;
1962
1964
  /** Clears persisted payload for this module instance by removing the stored key from the adapter and drops any pending save. */
@@ -288,24 +288,25 @@ var sia = (() => {
288
288
  function fanout(a, b, c, d) {
289
289
  const isEvPd = !!a?.target, isPath = !isEvPd && "string" === typeof b, [state2, path, olds, news, opts, type] = isEvPd ? [a.root, a.currentTarget.path, a.currentTarget.oldValue, a.currentTarget.value, b || NIL, a.type] : isPath ? [a, b, getPath(a, b), c, d || NIL, void 0] : [void 0, void 0, a, b, c || NIL, void 0], target = isEvPd ? getPath(a.root, a.currentTarget.path) : isPath ? getPath(state2, path) : olds;
290
290
  if (isEvPd && type !== "set" && type !== "delete" || !target || !canHandle(news, opts)) return;
291
+ const { merge = false, depth, atomic = true, skipUndef = false, cloneSets = false, txLabel } = opts;
291
292
  const func = () => {
292
- const walk = (target2, obj, depth = isEvPd ? 1 : Infinity, keys2 = Object.keys(obj)) => {
293
+ const walk = (target2, obj, depth2 = isEvPd ? 1 : Infinity, keys2 = Object.keys(obj)) => {
293
294
  for (let i = 0, len = keys2.length; i < len; i++) {
294
295
  const key = keys2[i], val = obj[key];
295
296
  try {
296
- if ((opts.atomic ?? true) && Array.isArray(val)) target2[key] = val, target2[key].length = target2[key].length;
297
- else depth > 1 && canHandle(val, opts) ? walk(target2[key] ||= {}, val, depth - 1) : (!opts.skipUndefined || val !== void 0) && (target2[key] = val);
297
+ if (atomic && Array.isArray(val)) target2[key] = cloneSets ? deepClone(val) : val, target2[key].length = target2[key].length;
298
+ else depth2 > 1 && canHandle(val, opts) ? walk(target2[key] ||= {}, val, depth2 - 1) : (!skipUndef || val !== void 0) && (target2[key] = cloneSets ? deepClone(val) : val);
298
299
  } catch (e) {
299
300
  if (e instanceof RangeError) throw e;
300
301
  }
301
302
  }
302
303
  };
303
- if ((opts.atomic ?? true) && Array.isArray(news) && isPath) setPath(state2, path, news), getPath(state2, path).length = news.length;
304
- else walk(target, opts.merge ? mergeObjs(olds, news, opts) : news, opts.depth === true ? Infinity : opts.depth);
304
+ if (atomic && Array.isArray(news) && isPath) setPath(state2, path, cloneSets ? deepClone(news) : news), getPath(state2, path).length = news.length;
305
+ else walk(target, merge ? mergeObjs(olds, news, opts) : news, depth === true ? Infinity : depth);
305
306
  };
306
- force(() => transaction(func, opts.txLabel ?? `${path ? `Fanout -> '${path}'` : `Fanout`} (Tx ${txId + 1})`), CTX.usingForce || isEvPd);
307
+ force(() => transaction(func, txLabel ?? `${path ? `Fanout -> '${path}'` : `Fanout`} (Tx ${txId + 1})`), CTX.usingForce || isEvPd);
307
308
  }
308
- var fanoutOptsArr = ["merge", "depth", "atomic", "skipUndefined"];
309
+ var fanoutOptsArr = ["merge", "depth", "atomic", "skipUndef"];
309
310
  function force(task, bool = true) {
310
311
  const prev = CTX.usingForce;
311
312
  CTX.usingForce = bool;
@@ -318,8 +319,8 @@ var sia = (() => {
318
319
  function mergeObjs(o1, o2, config = NIL, pojocheck = true) {
319
320
  if (pojocheck && (!isPOJO(o1 || NIL, config) || !isPOJO(o2 || NIL, config))) return o2;
320
321
  o1 ||= {}, o2 ||= {};
321
- const merged = config.skipUndefined ? { ...o1 } : { ...o1, ...o2 };
322
- if (config.skipUndefined) {
322
+ const merged = config.skipUndef ? { ...o1 } : { ...o1, ...o2 };
323
+ if (config.skipUndef) {
323
324
  const keys3 = Object.keys(o1);
324
325
  for (let i = 0, len = keys3.length; i < len; i++) {
325
326
  const key = keys3[i], val = o2[key];
@@ -412,20 +413,18 @@ var sia = (() => {
412
413
  return path !== "*" && !canHandle(value, config);
413
414
  }
414
415
  function createReactorSync(rA, rB, prefixA, prefixB = "", signal) {
415
- const reactorA = getReactor(rA, true), reactorB = getReactor(rB, true);
416
+ const rtrA = getReactor(rA, true), rtrB = getReactor(rB, true);
416
417
  let origin = null;
417
- const sync = (srcOrigin, destCore, pSrc, pDest) => (val, payload) => {
418
- if (origin === (srcOrigin ^ 1)) return;
419
- const { path, object, key } = payload.target;
420
- if (pSrc && path !== pSrc && !path.startsWith(pSrc + ".")) return;
421
- origin = srcOrigin;
422
- const syncPath = Array.isArray(object) ? path.slice(0, -(key.length + 1)) : path, stripped = syncPath === pSrc ? "" : pSrc ? syncPath.slice(pSrc.length + 1) : syncPath;
423
- setPath(destCore, pDest ? stripped ? `${pDest}.${stripped}` : pDest : stripped || "*", Array.isArray(object) ? object : val);
424
- origin = null;
418
+ const sync = (src, dest, srcP, destP) => (val, payload) => {
419
+ if (origin === (src ^ 1)) return;
420
+ const { path, object: obj, key } = payload.target;
421
+ if (srcP && path !== srcP && !path.startsWith(srcP + ".")) return;
422
+ const isArr = Array.isArray(obj), origP = isArr ? path.slice(0, -(key.length + 1)) : path, syncP = origP === srcP ? "" : srcP ? origP.slice(srcP.length + 1) : origP;
423
+ origin = src, setPath(dest, destP ? syncP ? `${destP}.${syncP}` : destP : syncP || "*", isArr ? deepClone(obj) : val), origin = null;
425
424
  };
426
- const initialA = prefixA ? getPath(reactorA.core, prefixA) : reactorA.core;
427
- if (initialA !== void 0) fanout(reactorB.core, prefixB || "*", deepClone(initialA), { depth: 1 });
428
- const clupA = reactorA.watch("*", sync(0, reactorB.core, prefixA, prefixB), { signal }), clupB = reactorB.watch("*", sync(1, reactorA.core, prefixB, prefixA), { signal });
425
+ const initA = prefixA ? getPath(rtrA.core, prefixA) : rtrA.core;
426
+ if (initA !== void 0) fanout(rtrB.core, prefixB || "*", initA, { depth: 1, cloneSets: true, txLabel: `ReactorSync: ${prefixA}^ <-> ${prefixB}` });
427
+ const clupA = rtrA.watch("*", sync(0, rtrB.core, prefixA, prefixB), { signal }), clupB = rtrB.watch("*", sync(1, rtrA.core, prefixB, prefixA), { signal });
429
428
  return () => (clupA(), clupB());
430
429
  }
431
430
 
@@ -1941,9 +1940,9 @@ var sia = (() => {
1941
1940
  for (const [rid, rtr] of this.deps) this.attachPaths(rtr, rid);
1942
1941
  value && this.adapter?.remove(this.config.key);
1943
1942
  }
1944
- hydrate(entry, rtr, rid = this.rids.get(rtr), { depth, merge = true, atomic, skipUndefined } = parseEvtOpts(this.config.fanout, fanoutOptsArr, "depth"), tick = true) {
1943
+ hydrate(entry, rtr, rid = this.rids.get(rtr), { depth, merge = true, atomic, skipUndef } = parseEvtOpts(this.config.fanout, fanoutOptsArr, "depth"), tick = true) {
1945
1944
  if (!entry) return;
1946
- const whites = this.getPaths(rid), blacks = this.getPaths(rid, this.config.blacklist, true), set = (p, curr, prev) => (depth ? fanout : setPath)(rtr.core, p, merge ? mergeObjs(curr, prev, rtr.config) : prev, depth ? { depth, atomic, skipUndefined, crossRealms: rtr.config.crossRealms } : void 0);
1945
+ const whites = this.getPaths(rid), blacks = this.getPaths(rid, this.config.blacklist, true), set = (p, curr, prev) => (depth ? fanout : setPath)(rtr.core, p, merge ? mergeObjs(curr, prev, rtr.config) : prev, depth ? { depth, atomic, skipUndef, crossRealms: rtr.config.crossRealms } : void 0);
1947
1946
  let ticks = this.tickMap.get(rid);
1948
1947
  for (let i = 0, len = blacks.length; i < len; i++) deletePath(entry, blacks[i]);
1949
1948
  for (let i = 0, len = whites.length; i < len; i++) {
@@ -2437,7 +2436,7 @@ var sia = (() => {
2437
2436
  this.config = reactive({ title: `Time Travel Console ${this.index = ++_TimeTravelConsole.count}`, ...build });
2438
2437
  this.state.open = !!this.config.startOpen;
2439
2438
  let wlLive = false, blLive = false;
2440
- const s = this.time.state, host = this.host = createEl("div", { className: "sia-tt-console-host" }), toggle = createEl("button", { className: "sia-tt-console-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "sia-tt-console", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: () => this.time.undo(this.state.stride) }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: () => this.time.redo(this.state.stride) }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), trackUntrack = createEl("button", { onclick: () => this.time[s.tracking ? "untrack" : "track"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.trackUntrack, false) }), range = createEl("input", { type: "range", min: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "sia-tt-io", readOnly: true, placeholder: "current payload json", title: "Current History Entry" }), io = createEl("textarea", { className: "sia-tt-io", placeholder: "timeline payload json", title: "Time History", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "sia-tt-footnote", innerHTML: "<span>Want this in your app? </span>" }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "sia-tt-status-box" }), status = createEl("div", { className: "sia-tt-status-row" }), filters = createEl("div", { className: "sia-tt-status-row" }), filterBox = createEl("div", { className: "sia-tt-status-box" }), whitelistLabel = createEl("span", { className: "muted", textContent: "Whitelist:" }), blacklistLabel = createEl("span", { className: "muted", textContent: "Blacklist:" }), whitelist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Whitelist paths", onfocus: () => wlLive = true, onblur: () => (wlLive = false, whitelist.value = formatPaths(this.time.config.whitelist, "*")), oninput: (_, parsed = parsePaths(whitelist.value)) => parsed !== null && (this.time.config.whitelist = parsed) }), blacklist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Blacklist paths", onfocus: () => blLive = true, onblur: () => (blLive = false, blacklist.value = formatPaths(this.time.config.blacklist, "")), oninput: (_, parsed = parsePaths(blacklist.value, true)) => parsed !== null && (this.time.config.blacklist = parsed) }), speed = createEl("select", { className: "sia-tt-speed", title: "Playback Speed", onchange: () => this.time.config.playbackRate = Number(speed.value) }), stride = createEl("input", { className: "sia-tt-stride sia-tt-button sia-tt-mini-input", type: "number", min: "1", title: "Skip Stride i.e. how many steps count as one unit", oninput: () => this.state.stride = Math.max(1, Number(stride.value) || 1) }), stats = createEl("span", { className: "sia-tt-stats" }), limit = createEl("input", { className: "sia-tt-limit sia-tt-mini-input sia-tt-button", type: "number", min: "1", title: "Maximum number of history entries kept in memory before older entries are discarded.", oninput: () => this.time.config.limit = Math.max(1, Number(limit.value) || 1) }), delay = createEl("input", { className: "sia-tt-delay sia-tt-mini-input sia-tt-button", type: "number", min: "0", step: "50", title: "Maximum playback delay between timeline frames in milliseconds.", oninput: () => this.time.config.maxPlaybackDelay = Math.max(0, Number(delay.value) || 0) }), read = createEl("label", { className: "sia-tt-check", title: "When recording intent mutations, read previous values from the matching state path instead of the intent path. Useful for accurate undo reconstruction of intent-driven flows." }), readBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorReads, onchange: () => this.time.config.mirrorReads = readBox.checked }), write = createEl("label", { className: "sia-tt-check", title: "During playback and teleportation, mirror state writes into matching intent paths to re-enact the recorded history. Useful for accurate reconstruction of the whole session." }), writeBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorWrites, onchange: () => this.time.config.mirrorWrites = writeBox.checked }), filterRow1 = createEl("div", { className: "sia-tt-filter-row" }), filterRow2 = createEl("div", { className: "sia-tt-filter-row" }), row1 = createEl("div", { className: "sia-tt-row" }), row2 = createEl("div", { className: "sia-tt-row" }), row3 = createEl("div", { className: "sia-tt-row" }), row4 = createEl("div", { className: "sia-tt-row" }), row5 = createEl("div", { className: "sia-tt-row sia-tt-config-row" });
2439
+ const s = this.time.state, host = this.host = createEl("div", { className: "sia-tt-console-host" }), toggle = createEl("button", { className: "sia-tt-console-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "sia-tt-console", ariaLabel: "time travel overlay" }), title = createEl("div", { className: "title" }), frame = createEl("span", { className: "muted" }), clrHistory = createEl("button", { textContent: `Clear History${formatKeyForDisplay(keys.shortcuts.clrHistory)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clrHistory, false), onclick: () => (this.time.clear(), this.state.import = "") }), undo = createEl("button", { textContent: `Undo${formatKeyForDisplay(keys.shortcuts.undo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.undo, false), onclick: () => this.time.undo(this.state.stride) }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: () => this.time.redo(this.state.stride) }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.genesis, false), onclick: () => this.time.jumpTo(0) }), playPause = createEl("button", { onclick: () => this.time[s.paused ? "play" : "pause"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.playPause, false) }), rewind = createEl("button", { textContent: `Rewind${formatKeyForDisplay(keys.shortcuts.rewind)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.rewind, false), onclick: this.time.rewind }), trackUntrack = createEl("button", { onclick: () => this.time[s.tracking ? "untrack" : "track"](), ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.trackUntrack, false) }), range = createEl("input", { type: "range", min: "0", title: "time travel frame", ariaLabel: "time travel frame", oninput: () => this.time.jumpTo(Number(range.value)) }), exp = createEl("button", { textContent: `Export${formatKeyForDisplay(keys.shortcuts.export)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.export, false), onclick: () => this.state.import = this.time.export(null, 2) }), imp = createEl("button", { textContent: `Import${formatKeyForDisplay(keys.shortcuts.import)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.import, false), onclick: () => this.state.import.trim().length && this.time.import(this.state.import) }), clr = createEl("button", { textContent: `Clear${formatKeyForDisplay(keys.shortcuts.clear)}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.clear, false), onclick: () => this.state.import = "" }), payload = createEl("textarea", { className: "sia-tt-io", readOnly: true, placeholder: "current payload json", title: "Current History Entry" }), io = createEl("textarea", { className: "sia-tt-io", placeholder: "timeline payload json", title: "Time History", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "sia-tt-footnote", innerHTML: "<span>Try this in your app? </span>" }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "sia-tt-status-box" }), status = createEl("div", { className: "sia-tt-status-row" }), filters = createEl("div", { className: "sia-tt-status-row" }), filterBox = createEl("div", { className: "sia-tt-status-box" }), whitelistLabel = createEl("span", { className: "muted", textContent: "Whitelist:" }), blacklistLabel = createEl("span", { className: "muted", textContent: "Blacklist:" }), whitelist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Whitelist paths", onfocus: () => wlLive = true, onblur: () => (wlLive = false, whitelist.value = formatPaths(this.time.config.whitelist, "*")), oninput: (_, parsed = parsePaths(whitelist.value)) => parsed !== null && (this.time.config.whitelist = parsed) }), blacklist = createEl("input", { className: "sia-tt-filter-input sia-tt-io", placeholder: 'a.b, c.d or {"0":["a.b"]}', title: "Blacklist paths", onfocus: () => blLive = true, onblur: () => (blLive = false, blacklist.value = formatPaths(this.time.config.blacklist, "")), oninput: (_, parsed = parsePaths(blacklist.value, true)) => parsed !== null && (this.time.config.blacklist = parsed) }), speed = createEl("select", { className: "sia-tt-speed", title: "Playback Speed", onchange: () => this.time.config.playbackRate = Number(speed.value) }), stride = createEl("input", { className: "sia-tt-stride sia-tt-button sia-tt-mini-input", type: "number", min: "1", title: "Skip Stride i.e. how many steps count as one unit", oninput: () => this.state.stride = Math.max(1, Number(stride.value) || 1) }), stats = createEl("span", { className: "sia-tt-stats" }), limit = createEl("input", { className: "sia-tt-limit sia-tt-mini-input sia-tt-button", type: "number", min: "1", title: "Maximum number of history entries kept in memory before older entries are discarded.", oninput: () => this.time.config.limit = Math.max(1, Number(limit.value) || 1) }), delay = createEl("input", { className: "sia-tt-delay sia-tt-mini-input sia-tt-button", type: "number", min: "0", step: "50", title: "Maximum playback delay between timeline frames in milliseconds.", oninput: () => this.time.config.maxPlaybackDelay = Math.max(0, Number(delay.value) || 0) }), read = createEl("label", { className: "sia-tt-check", title: "When recording intent mutations, read previous values from the matching state path instead of the intent path. Useful for accurate undo reconstruction of intent-driven flows." }), readBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorReads, onchange: () => this.time.config.mirrorReads = readBox.checked }), write = createEl("label", { className: "sia-tt-check", title: "During playback and teleportation, mirror state writes into matching intent paths to re-enact the recorded history. Useful for accurate reconstruction of the whole session." }), writeBox = createEl("input", { type: "checkbox", checked: !!this.time.config.mirrorWrites, onchange: () => this.time.config.mirrorWrites = writeBox.checked }), filterRow1 = createEl("div", { className: "sia-tt-filter-row" }), filterRow2 = createEl("div", { className: "sia-tt-filter-row" }), row1 = createEl("div", { className: "sia-tt-row" }), row2 = createEl("div", { className: "sia-tt-row" }), row3 = createEl("div", { className: "sia-tt-row" }), row4 = createEl("div", { className: "sia-tt-row" }), row5 = createEl("div", { className: "sia-tt-row sia-tt-config-row" });
2441
2440
  speed.append(...[0.25, 0.5, 0.75, 1, 1.25, 1.5, 2, 4, 8, 16, 32].map((v) => createEl("option", { value: String(v), textContent: `${v}x` })));
2442
2441
  status.append((box.append(frame), box), clrHistory);
2443
2442
  filters.append((filterBox.append((filterRow1.append(whitelistLabel, whitelist), filterRow1), (filterRow2.append(blacklistLabel, blacklist), filterRow2)), filterBox));
package/dist/utils.cjs CHANGED
@@ -941,24 +941,25 @@ function parseEvtOpts(options, opts, boolOpt = opts[0], result = {}) {
941
941
  function fanout(a, b, c, d) {
942
942
  const isEvPd = !!a?.target, isPath = !isEvPd && "string" === typeof b, [state, path, olds, news, opts, type] = isEvPd ? [a.root, a.currentTarget.path, a.currentTarget.oldValue, a.currentTarget.value, b || NIL, a.type] : isPath ? [a, b, getPath(a, b), c, d || NIL, void 0] : [void 0, void 0, a, b, c || NIL, void 0], target = isEvPd ? getPath(a.root, a.currentTarget.path) : isPath ? getPath(state, path) : olds;
943
943
  if (isEvPd && type !== "set" && type !== "delete" || !target || !canHandle(news, opts)) return;
944
+ const { merge = false, depth, atomic = true, skipUndef = false, cloneSets = false, txLabel } = opts;
944
945
  const func = () => {
945
- const walk = (target2, obj, depth = isEvPd ? 1 : Infinity, keys = Object.keys(obj)) => {
946
+ const walk = (target2, obj, depth2 = isEvPd ? 1 : Infinity, keys = Object.keys(obj)) => {
946
947
  for (let i = 0, len = keys.length; i < len; i++) {
947
948
  const key = keys[i], val = obj[key];
948
949
  try {
949
- if ((opts.atomic ?? true) && Array.isArray(val)) target2[key] = val, target2[key].length = target2[key].length;
950
- else depth > 1 && canHandle(val, opts) ? walk(target2[key] ||= {}, val, depth - 1) : (!opts.skipUndefined || val !== void 0) && (target2[key] = val);
950
+ if (atomic && Array.isArray(val)) target2[key] = cloneSets ? deepClone(val) : val, target2[key].length = target2[key].length;
951
+ else depth2 > 1 && canHandle(val, opts) ? walk(target2[key] ||= {}, val, depth2 - 1) : (!skipUndef || val !== void 0) && (target2[key] = cloneSets ? deepClone(val) : val);
951
952
  } catch (e) {
952
953
  if (e instanceof RangeError) throw e;
953
954
  }
954
955
  }
955
956
  };
956
- if ((opts.atomic ?? true) && Array.isArray(news) && isPath) setPath(state, path, news), getPath(state, path).length = news.length;
957
- else walk(target, opts.merge ? mergeObjs(olds, news, opts) : news, opts.depth === true ? Infinity : opts.depth);
957
+ if (atomic && Array.isArray(news) && isPath) setPath(state, path, cloneSets ? deepClone(news) : news), getPath(state, path).length = news.length;
958
+ else walk(target, merge ? mergeObjs(olds, news, opts) : news, depth === true ? Infinity : depth);
958
959
  };
959
- force(() => transaction(func, opts.txLabel ?? `${path ? `Fanout -> '${path}'` : `Fanout`} (Tx ${txId + 1})`), CTX.usingForce || isEvPd);
960
+ force(() => transaction(func, txLabel ?? `${path ? `Fanout -> '${path}'` : `Fanout`} (Tx ${txId + 1})`), CTX.usingForce || isEvPd);
960
961
  }
961
- var fanoutOptsArr = ["merge", "depth", "atomic", "skipUndefined"];
962
+ var fanoutOptsArr = ["merge", "depth", "atomic", "skipUndef"];
962
963
  function force(task, bool = true) {
963
964
  const prev = CTX.usingForce;
964
965
  CTX.usingForce = bool;
@@ -971,8 +972,8 @@ function force(task, bool = true) {
971
972
  function mergeObjs(o1, o2, config = NIL, pojocheck = true) {
972
973
  if (pojocheck && (!isPOJO(o1 || NIL, config) || !isPOJO(o2 || NIL, config))) return o2;
973
974
  o1 ||= {}, o2 ||= {};
974
- const merged = config.skipUndefined ? { ...o1 } : { ...o1, ...o2 };
975
- if (config.skipUndefined) {
975
+ const merged = config.skipUndef ? { ...o1 } : { ...o1, ...o2 };
976
+ if (config.skipUndef) {
976
977
  const keys2 = Object.keys(o1);
977
978
  for (let i = 0, len = keys2.length; i < len; i++) {
978
979
  const key = keys2[i], val = o2[key];
@@ -1065,20 +1066,18 @@ function isLeafPath(obj, path, config = CTX.defaults, value = getPath(obj, path,
1065
1066
  return path !== "*" && !canHandle(value, config);
1066
1067
  }
1067
1068
  function createReactorSync(rA, rB, prefixA, prefixB = "", signal) {
1068
- const reactorA = getReactor(rA, true), reactorB = getReactor(rB, true);
1069
+ const rtrA = getReactor(rA, true), rtrB = getReactor(rB, true);
1069
1070
  let origin = null;
1070
- const sync = (srcOrigin, destCore, pSrc, pDest) => (val, payload) => {
1071
- if (origin === (srcOrigin ^ 1)) return;
1072
- const { path, object, key } = payload.target;
1073
- if (pSrc && path !== pSrc && !path.startsWith(pSrc + ".")) return;
1074
- origin = srcOrigin;
1075
- const syncPath = Array.isArray(object) ? path.slice(0, -(key.length + 1)) : path, stripped = syncPath === pSrc ? "" : pSrc ? syncPath.slice(pSrc.length + 1) : syncPath;
1076
- setPath(destCore, pDest ? stripped ? `${pDest}.${stripped}` : pDest : stripped || "*", Array.isArray(object) ? object : val);
1077
- origin = null;
1071
+ const sync = (src, dest, srcP, destP) => (val, payload) => {
1072
+ if (origin === (src ^ 1)) return;
1073
+ const { path, object: obj, key } = payload.target;
1074
+ if (srcP && path !== srcP && !path.startsWith(srcP + ".")) return;
1075
+ const isArr = Array.isArray(obj), origP = isArr ? path.slice(0, -(key.length + 1)) : path, syncP = origP === srcP ? "" : srcP ? origP.slice(srcP.length + 1) : origP;
1076
+ origin = src, setPath(dest, destP ? syncP ? `${destP}.${syncP}` : destP : syncP || "*", isArr ? deepClone(obj) : val), origin = null;
1078
1077
  };
1079
- const initialA = prefixA ? getPath(reactorA.core, prefixA) : reactorA.core;
1080
- if (initialA !== void 0) fanout(reactorB.core, prefixB || "*", deepClone(initialA), { depth: 1 });
1081
- const clupA = reactorA.watch("*", sync(0, reactorB.core, prefixA, prefixB), { signal }), clupB = reactorB.watch("*", sync(1, reactorA.core, prefixB, prefixA), { signal });
1078
+ const initA = prefixA ? getPath(rtrA.core, prefixA) : rtrA.core;
1079
+ if (initA !== void 0) fanout(rtrB.core, prefixB || "*", initA, { depth: 1, cloneSets: true, txLabel: `ReactorSync: ${prefixA}^ <-> ${prefixB}` });
1080
+ const clupA = rtrA.watch("*", sync(0, rtrB.core, prefixA, prefixB), { signal }), clupB = rtrB.watch("*", sync(1, rtrA.core, prefixB, prefixA), { signal });
1082
1081
  return () => (clupA(), clupB());
1083
1082
  }
1084
1083
 
package/dist/utils.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { F as FanoutOptionsTuple, g as arrRegex, h as canHandle, i as createReactorSync, j as deepClone, k as deletePath, l as fanout, m as fanoutOptsArr, n as force, o as getDepth, p as getPath, q as getPaths, r as getTrailRecords, s as hasPath, t as isLeafPath, u as isObj, v as isPOJO, x as matchPaths, y as mergeObjs, z as nuke, C as parseEvtOpts, D as parsePathObj, G as resetMeta, H as setPath, I as withMeta } from './index-BsH8KkqG.cjs';
1
+ export { F as FanoutOptionsTuple, g as arrRegex, h as canHandle, i as createReactorSync, j as deepClone, k as deletePath, l as fanout, m as fanoutOptsArr, n as force, o as getDepth, p as getPath, q as getPaths, r as getTrailRecords, s as hasPath, t as isLeafPath, u as isObj, v as isPOJO, x as matchPaths, y as mergeObjs, z as nuke, C as parseEvtOpts, D as parsePathObj, G as resetMeta, H as setPath, I as withMeta } from './index-BtHNGnRR.cjs';
2
2
 
3
3
  declare function clamp(min: number | undefined, val: number, max?: number): number;
4
4
 
package/dist/utils.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { F as FanoutOptionsTuple, g as arrRegex, h as canHandle, i as createReactorSync, j as deepClone, k as deletePath, l as fanout, m as fanoutOptsArr, n as force, o as getDepth, p as getPath, q as getPaths, r as getTrailRecords, s as hasPath, t as isLeafPath, u as isObj, v as isPOJO, x as matchPaths, y as mergeObjs, z as nuke, C as parseEvtOpts, D as parsePathObj, G as resetMeta, H as setPath, I as withMeta } from './index-BsH8KkqG.js';
1
+ export { F as FanoutOptionsTuple, g as arrRegex, h as canHandle, i as createReactorSync, j as deepClone, k as deletePath, l as fanout, m as fanoutOptsArr, n as force, o as getDepth, p as getPath, q as getPaths, r as getTrailRecords, s as hasPath, t as isLeafPath, u as isObj, v as isPOJO, x as matchPaths, y as mergeObjs, z as nuke, C as parseEvtOpts, D as parsePathObj, G as resetMeta, H as setPath, I as withMeta } from './index-BtHNGnRR.js';
2
2
 
3
3
  declare function clamp(min: number | undefined, val: number, max?: number): number;
4
4
 
package/dist/utils.js CHANGED
@@ -48,7 +48,7 @@ import {
48
48
  resetMeta,
49
49
  setPath,
50
50
  withMeta
51
- } from "./chunk-DCUPDG7B.js";
51
+ } from "./chunk-LZJYX2LE.js";
52
52
  export {
53
53
  KEYS_BLOCKS,
54
54
  arrRegex,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sia-reactor",
3
- "version": "0.0.39",
3
+ "version": "0.0.40",
4
4
  "description": "The Programmable Data DOM. A high-performance State & Intent Architecture (S.I.A.) engine that gives your data transactional mutation routing and multi-phase state observation.",
5
5
  "author": "Oketade Oluwatobiloba <tobioketade007@gmail.com>",
6
6
  "license": "MIT",