sia-reactor 0.0.21 → 0.0.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +115 -89
  2. package/dist/{TimeTravelOverlay-DxqJL0Zk.d.ts → TimeTravelOverlay-Dglcwpg-.d.ts} +9 -8
  3. package/dist/{TimeTravelOverlay-CJv-S_Km.d.cts → TimeTravelOverlay-OjklzuCD.d.cts} +9 -8
  4. package/dist/adapters/react.cjs +74 -91
  5. package/dist/adapters/react.d.cts +23 -22
  6. package/dist/adapters/react.d.ts +23 -22
  7. package/dist/adapters/react.js +3 -3
  8. package/dist/adapters/vanilla.cjs +74 -91
  9. package/dist/adapters/vanilla.d.cts +4 -4
  10. package/dist/adapters/vanilla.d.ts +4 -4
  11. package/dist/adapters/vanilla.js +3 -3
  12. package/dist/{chunk-TFLYCXK4.js → chunk-5JNWC7Z4.js} +14 -13
  13. package/dist/{chunk-DP74DVRT.js → chunk-MKL3JUPO.js} +55 -15
  14. package/dist/{chunk-2WBPGSRL.js → chunk-MSTHQVNK.js} +61 -78
  15. package/dist/{index-Oie9hhE8.d.cts → index-m0aAWxhX.d.cts} +330 -218
  16. package/dist/{index-Oie9hhE8.d.ts → index-m0aAWxhX.d.ts} +330 -218
  17. package/dist/index.cjs +69 -89
  18. package/dist/index.d.cts +1 -1
  19. package/dist/index.d.ts +1 -1
  20. package/dist/index.js +2 -4
  21. package/dist/{plugins.cjs → modules.cjs} +464 -195
  22. package/dist/modules.d.cts +52 -0
  23. package/dist/modules.d.ts +52 -0
  24. package/dist/modules.js +619 -0
  25. package/dist/super.d.ts +642 -298
  26. package/dist/super.global.js +481 -210
  27. package/dist/timeTravel-DExvNb04.d.ts +352 -0
  28. package/dist/timeTravel-DctvcHVt.d.cts +352 -0
  29. package/dist/utils.cjs +59 -14
  30. package/dist/utils.d.cts +1 -1
  31. package/dist/utils.d.ts +1 -1
  32. package/dist/utils.js +7 -1
  33. package/package.json +6 -6
  34. package/dist/plugins.d.cts +0 -112
  35. package/dist/plugins.d.ts +0 -112
  36. package/dist/plugins.js +0 -370
  37. package/dist/timeTravel-B1vedDQc.d.ts +0 -76
  38. package/dist/timeTravel-WpgWmKu-.d.cts +0 -76
@@ -43,7 +43,9 @@ var useISOLayoutEffect = "undefined" !== typeof window ? import_react.useLayoutE
43
43
  var CTX = {
44
44
  /** Flag indicating whether the application is running in development mode. */
45
45
  isDevEnv: "undefined" !== typeof process ? process.env.NODE_ENV !== "production" : true,
46
- /** active `Autotracker` instance, override for automatic dependency collection on `Reactor` traps. */
46
+ /** Flag indicating whether a cascade is currently ongoing so reactors can allow all writes. */
47
+ isCascading: false,
48
+ /** Active `Autotracker` instance, override for automatic dependency collection on `Reactor` traps. */
47
49
  autotracker: null
48
50
  };
49
51
  var RAW = /* @__PURE__ */ Symbol.for("S.I.A_RAW");
@@ -55,14 +57,13 @@ var VERSION = /* @__PURE__ */ Symbol.for("S.I.A_VERSION");
55
57
  var SSVERSION = /* @__PURE__ */ Symbol.for("S.I.A_SNAPSHOT_VERSION");
56
58
  var RTR_BATCH = "undefined" !== typeof window ? ("undefined" !== typeof queueMicrotask ? queueMicrotask : setTimeout).bind(window) : "undefined" !== typeof process && process.nextTick ? process.nextTick : setTimeout;
57
59
  var RTR_LOG = console.log.bind(console, "[S.I.A Reactor]");
58
- var EVT_WARN = console.warn.bind(console, "[S.I.A Event]");
59
60
  var EVT_OPTS = { LISTENER: ["capture", "depth", "once", "signal", "immediate"], MEDIATOR: ["lazy", "signal", "immediate"] };
60
61
  var NIL = Object.freeze({});
61
62
  var NOOP = () => {
62
63
  };
63
64
 
64
65
  // src/ts/utils/obj.ts
65
- var arrRx = /^([^\[\]]+)\[(\d+)\]$/;
66
+ var arrRegex = /^([^\[\]]+)\[(\d+)\]$/;
66
67
  function isObj(obj, arraycheck = true) {
67
68
  return "object" === typeof obj && obj !== null && (arraycheck ? !Array.isArray(obj) : true);
68
69
  }
@@ -70,7 +71,7 @@ function isPOJO(obj, config = NIL, typecheck = true) {
70
71
  return (typecheck ? isObj(obj, false) : true) && (config.crossRealms ? Object.prototype.toString.call(obj) === "[object Object]" : obj.constructor === Object);
71
72
  }
72
73
  function canHandle(obj, config = NIL, typecheck = true) {
73
- if (typecheck && !isObj(obj, false)) return false;
74
+ if (typecheck && !isObj(obj, false) || obj[INERTIA]) return false;
74
75
  if (Array.isArray(obj) || !config.preserveContext && isPOJO(obj, config, false)) return true;
75
76
  if (config.preserveContext) return !(obj instanceof Map) && !(obj instanceof Set) && !(obj instanceof WeakMap) && !(obj instanceof WeakSet) && !(obj instanceof Error) && !(obj instanceof Number) && !(obj instanceof Date) && !(obj instanceof String) && !(obj instanceof RegExp) && !(obj instanceof ArrayBuffer) && !(obj instanceof Promise);
76
77
  return false;
@@ -81,7 +82,7 @@ function getAny(source, key, separator = ".", keyFunc) {
81
82
  const keys2 = key.split(separator);
82
83
  let currObj = source;
83
84
  for (let i = 0, len = keys2.length; i < len; i++) {
84
- const key2 = keyFunc ? keyFunc(keys2[i]) : keys2[i], match = key2.includes("[") && key2.match(arrRx);
85
+ const key2 = keyFunc ? keyFunc(keys2[i]) : keys2[i], match = key2.includes("[") && key2.match(arrRegex);
85
86
  if (match) {
86
87
  const [, key3, iStr] = match;
87
88
  if (!Array.isArray(currObj[key3]) || !(key3 in currObj)) return void 0;
@@ -98,7 +99,7 @@ function setAny(target, key, value, separator = ".", keyFunc) {
98
99
  if (!key.includes(separator)) return void (target[keyFunc ? keyFunc(key) : key] = value);
99
100
  const keys2 = key.split(separator);
100
101
  for (let currObj = target, i = 0, len = keys2.length; i < len; i++) {
101
- const key2 = keyFunc ? keyFunc(keys2[i]) : keys2[i], match = key2.includes("[") && key2.match(arrRx);
102
+ const key2 = keyFunc ? keyFunc(keys2[i]) : keys2[i], match = key2.includes("[") && key2.match(arrRegex);
102
103
  if (match) {
103
104
  const [, key3, iStr] = match;
104
105
  if (!Array.isArray(currObj[key3])) currObj[key3] = [];
@@ -119,7 +120,7 @@ function deleteAny(target, key, separator = ".", keyFunc) {
119
120
  if (!key.includes(separator)) return void delete target[keyFunc ? keyFunc(key) : key];
120
121
  const keys2 = key.split(separator);
121
122
  for (let currObj = target, i = 0, len = keys2.length; i < len; i++) {
122
- const key2 = keyFunc ? keyFunc(keys2[i]) : keys2[i], match = key2.includes("[") && key2.match(arrRx);
123
+ const key2 = keyFunc ? keyFunc(keys2[i]) : keys2[i], match = key2.includes("[") && key2.match(arrRegex);
123
124
  if (match) {
124
125
  const [, key3, iStr] = match;
125
126
  if (!Array.isArray(currObj[key3]) || !(key3 in currObj)) return;
@@ -137,7 +138,7 @@ function inAny(source, key, separator = ".", keyFunc) {
137
138
  if (!key.includes(separator)) return key in source;
138
139
  const keys2 = key.split(separator);
139
140
  for (let currObj = source, i = 0, len = keys2.length; i < len; i++) {
140
- const key2 = keyFunc ? keyFunc(keys2[i]) : keys2[i], match = key2.includes("[") && key2.match(arrRx);
141
+ const key2 = keyFunc ? keyFunc(keys2[i]) : keys2[i], match = key2.includes("[") && key2.match(arrRegex);
141
142
  if (match) {
142
143
  const [, key3, iStr] = match;
143
144
  if (!Array.isArray(currObj[key3]) || !(key3 in currObj)) return false;
@@ -154,10 +155,6 @@ function inAny(source, key, separator = ".", keyFunc) {
154
155
  function parseEvtOpts(options, opts, boolOpt = opts[0], result = {}) {
155
156
  return Object.assign(result, "boolean" === typeof options ? { [boolOpt]: options } : options), result;
156
157
  }
157
- function mergeObjs(o1 = {}, o2 = {}) {
158
- const merged = { ...o1 || {}, ...o2 || {} };
159
- return Object.keys(merged).forEach((k) => isObj(o1?.[k]) && isObj(o2?.[k]) && (merged[k] = mergeObjs(o1[k], o2[k]))), merged;
160
- }
161
158
  function getTrailRecords(obj, path, reverse = false) {
162
159
  const parts = path.split("."), chain = [["*", obj, obj]];
163
160
  for (let acc = "", currObj = obj, i = 0, len = parts.length; i < len; i++) chain.push([acc += (i ? "." : "") + parts[i], currObj, currObj = currObj?.[parts[i]]]);
@@ -200,35 +197,34 @@ var ReactorEvent = class _ReactorEvent {
200
197
  staticType;
201
198
  /** Original event target context. */
202
199
  target;
203
- /** Root reactive object for this event wave. */
200
+ /** Root reactive object for this event instance wave. */
204
201
  root;
205
- /** Original target path for this event wave. */
202
+ /** Original target path for this event instance wave. */
206
203
  path;
207
204
  /** Current value at the event target path. */
208
205
  value;
209
206
  /** Previous value at the event target path. */
210
207
  oldValue;
211
- /** Whether resolve/reject intent semantics are allowed for this event. */
208
+ /** Whether resolve/reject intent semantics are allowed for this event instance. */
212
209
  rejectable;
213
- /** Whether this event wave can bubble back up to ancestors or just capture down. */
210
+ /** Whether this event instance wave can bubble back up to ancestors or just capture down. */
214
211
  bubbles;
215
212
  /**
216
- * `DOMHighResTimeStamp` for this event payload for native event parity and accuracy.
213
+ * `DOMHighResTimeStamp` for this event instance payload for native event parity and accuracy.
217
214
  * Enable `eventTimeStamps` option, then use this over custom timestamps in listeners for accuracy.
218
215
  * */
219
216
  timestamp;
220
- _warn = NOOP;
217
+ /** The `Reactor` instance that dispatched this event instance. */
218
+ reactor;
221
219
  _resolved = "";
222
220
  _rejected = "";
223
221
  _propagationStopped = false;
224
222
  _immediatePropagationStopped = false;
225
223
  /**
226
224
  * @param payload Source payload for this event instance.
227
- * @param bubbles Whether bubbling is enabled for this wave.
228
- * @param canWarn Whether warning output is enabled.
229
- * @param canStamp Whether timestamping is enabled.
225
+ * @param reactor The `Reactor` instance creating this event instance.
230
226
  */
231
- constructor(payload, bubbles = false, canStamp = false, canWarn = true) {
227
+ constructor(payload, reactor) {
232
228
  this.staticType = this.type = payload.type;
233
229
  this.target = payload.target;
234
230
  this.currentTarget = payload.currentTarget;
@@ -237,9 +233,9 @@ var ReactorEvent = class _ReactorEvent {
237
233
  this.value = payload.target.value;
238
234
  this.oldValue = payload.target.oldValue;
239
235
  this.rejectable = payload.rejectable;
240
- this.bubbles = bubbles;
241
- if (canStamp) this.timestamp = performance.now();
242
- if (canWarn) this._warn = EVT_WARN;
236
+ this.bubbles = !!reactor.config.eventBubbling;
237
+ if (reactor.config.eventTimeStamps) this.timestamp = performance.now();
238
+ this.reactor = reactor;
243
239
  }
244
240
  /** Whether propagation has been stopped. */
245
241
  get propagationStopped() {
@@ -269,9 +265,9 @@ var ReactorEvent = class _ReactorEvent {
269
265
  * @example e.resolve("API Load successful"); // message
270
266
  */
271
267
  resolve(message) {
272
- if (!this.rejectable) return this._warn(`[ReactorEvent] Ignored resolve() call on a non-rejectable ${this.staticType} at "${this.path}"`);
273
- if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this._warn(`[ReactorEvent] Resolving an intent on ${this.staticType} at "${this.path}" outside of the capture phase is unadvised.`);
274
- if (this.rejectable) this._resolved = message || `Could ${this.staticType} intended value at "${this.path}"`;
268
+ if (!this.rejectable) return this.reactor.log(`[ReactorEvent] Ignored \`resolve()\` call on a non-rejectable ${this.staticType} at "${this.path}"`);
269
+ if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this.reactor.log(`[ReactorEvent] Resolving an intent on ${this.staticType} at "${this.path}" outside of the capture phase is unadvised.`);
270
+ if (this.rejectable) this.reactor.log(`[ReactorEvent] ${this._resolved = message || `Could ${this.staticType} intended value at "${this.path}"`}`);
275
271
  }
276
272
  /** Rejection reason for rejectable events. */
277
273
  get rejected() {
@@ -284,9 +280,9 @@ var ReactorEvent = class _ReactorEvent {
284
280
  * @example e.resolve("User is not logged in"); // reason
285
281
  */
286
282
  reject(reason) {
287
- if (!this.rejectable) return this._warn(`[ReactorEvent] Ignored reject() call on a non-rejectable ${this.staticType} at "${this.path}"`);
288
- if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this._warn(`[ReactorEvent] Rejecting an intent on ${this.staticType} at "${this.path}" outside of the capture phase is unadvised.`);
289
- if (this.rejectable) this._rejected = reason || `Couldn't ${this.staticType} intended value at "${this.path}"`;
283
+ if (!this.rejectable) return this.reactor.log(`[ReactorEvent] Ignored \`reject()\` call on a non-rejectable ${this.staticType} at "${this.path}"`);
284
+ if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this.reactor.log(`[ReactorEvent] Rejecting an intent on ${this.staticType} at "${this.path}" outside of the capture phase is unadvised.`);
285
+ if (this.rejectable) this.reactor.log(`[ReactorEvent] ${this._rejected = reason || `Couldn't ${this.staticType} intended value at "${this.path}"`}`);
290
286
  }
291
287
  /**
292
288
  * Returns event path values from target to root.
@@ -295,24 +291,22 @@ var ReactorEvent = class _ReactorEvent {
295
291
  composedPath() {
296
292
  return getTrailRecords(this.root, this.path, true).map((r) => r[2]);
297
293
  }
298
- get canWarn() {
299
- return this._warn !== NOOP;
300
- }
301
294
  };
302
295
 
303
296
  // src/ts/core/reactor.ts
304
297
  var Reactor = class {
298
+ /** Logger function for this reactor instance, override if desired, `this.canLog = false` resets. */
305
299
  log = NOOP;
300
+ /** The core state object for this reactor instance. */
306
301
  core;
307
302
  // `?:`s | pay the ~800 byte price upfront for what u might never use
308
- plugins;
303
+ /** The modules being used by this reactor. */
304
+ modules;
305
+ /** Configuration options for this reactor instance. */
309
306
  config;
307
+ /** Whether this reactor instance is currently batching updates, a window view into the engine timing */
310
308
  isBatching = false;
311
309
  // Async Batching
312
- isCascading = false;
313
- // Setter Cascading
314
- isLogging = false;
315
- // keeping track so API getter doesn't slow down internal iterations in any way
316
310
  queue;
317
311
  // Tasks to run after flush
318
312
  batch;
@@ -345,7 +339,7 @@ var Reactor = class {
345
339
  if (this.config.referenceTracking && parent && key && !this.link(target, parent, key, false)) return target;
346
340
  const cached = this.proxyCache.get(target);
347
341
  if (cached) return cached;
348
- if (target[INERTIA] || !canHandle(target, this.config, false)) return target;
342
+ if (!canHandle(target, this.config, false)) return target;
349
343
  rejectable ||= target[REJECTABLE];
350
344
  indiffable ||= target[INDIFFABLE];
351
345
  const proxy = new Proxy(target, {
@@ -379,7 +373,7 @@ var Reactor = class {
379
373
  safeValue = value?.[RAW] || value;
380
374
  unchanged = this.config.equalityFunction(safeValue, safeOldValue);
381
375
  }
382
- if (!indiffable && unchanged && !this.isCascading) return this.log(`\u{1F504} [Reactor \`set\` Trap] Unchanged for "${keyStr}" on "${paths}"`), true;
376
+ if (!indiffable && unchanged && !CTX.isCascading) return this.log(`\u{1F504} [Reactor \`set\` Trap] Unchanged for "${keyStr}" on "${paths}"`), true;
383
377
  if (this.config.set) terminated = (value = this.config.set(object, key2, value, oldValue, receiver, paths)) === TERMINATOR;
384
378
  if (this.setters) {
385
379
  const wildcords = this.setters.get("*");
@@ -533,7 +527,7 @@ var Reactor = class {
533
527
  if (this.queue?.size) for (const task of this.queue) task(), this.queue.delete(task);
534
528
  }
535
529
  wave(path, payload) {
536
- const e = new ReactorEvent(payload, this.config.eventBubbling, this.config.eventTimeStamps, this.isLogging), chain = getTrailRecords(this.core, path);
530
+ const e = new ReactorEvent(payload, this), chain = getTrailRecords(this.core, path);
537
531
  e.eventPhase = ReactorEvent.CAPTURING_PHASE;
538
532
  for (let i = 0; i <= chain.length - 2; i++) {
539
533
  if (e.propagationStopped) break;
@@ -607,8 +601,8 @@ var Reactor = class {
607
601
  return depth;
608
602
  }
609
603
  getContext(path) {
610
- const lastDot = path.lastIndexOf("."), value = getAny(this.core, path), object = lastDot === -1 ? this.core : getAny(this.core, path.slice(0, lastDot));
611
- return { path, value, key: path.slice(lastDot + 1) || "", hadKey: true, object };
604
+ const last = path.lastIndexOf("."), value = getAny(this.core, path), object = last === -1 ? this.core : getAny(this.core, path.slice(0, last));
605
+ return { path, value, key: path.slice(last + 1) || "", hadKey: true, object };
612
606
  }
613
607
  bindSignal(cord, sig) {
614
608
  if (sig) sig.aborted ? cord.clup() : sig.addEventListener("abort", cord.clup, { once: true });
@@ -624,7 +618,12 @@ var Reactor = class {
624
618
  const clone = !raw ? this.config.preserveContext ? Object.create(Object.getPrototypeOf(obj)) : Array.isArray(obj) ? [] : {} : obj;
625
619
  seen.set(obj, clone);
626
620
  const keys2 = this.config.preserveContext ? Reflect.ownKeys(obj) : Object.keys(obj);
627
- for (let i = 0, len = keys2.length; i < len; i++) clone[keys2[i]] = this.cloned(obj[keys2[i]], raw, seen);
621
+ for (let i = 0, len = keys2.length; i < len; i++)
622
+ try {
623
+ clone[keys2[i]] = this.cloned(obj[keys2[i]], raw, seen);
624
+ } catch (e) {
625
+ if (e instanceof RangeError) throw e;
626
+ }
628
627
  if (!raw && this.config.smartCloning) this.snapCache.set(obj, clone), obj[SSVERSION] = version;
629
628
  return clone;
630
629
  }
@@ -712,7 +711,7 @@ var Reactor = class {
712
711
  * rtr.delete("cache.temp", () => TERMINATOR);
713
712
  */
714
713
  delete(path, callback, options) {
715
- return this.syncAdd("delete", path, callback, options, (imm) => (imm !== "auto" || inAny(this.core, path)) && deleteAny(this.core, path, void 0));
714
+ return this.syncAdd("delete", path, callback, options, (imm) => (imm !== "auto" || inAny(this.core, path)) && deleteAny(this.core, path));
716
715
  }
717
716
  /** Registers a delete mediator for a path that only triggers once. */
718
717
  donce(path, callback, options) {
@@ -729,7 +728,7 @@ var Reactor = class {
729
728
  }
730
729
  /**
731
730
  * Registers a watcher for a path.
732
- * Watch callbacks run synchronously with the operation.
731
+ * Watch callbacks run synchronously with the operation, use leaf paths for reliability as it sees exact sets; no bubbling here.
733
732
  * @param path Path or wildcard path.
734
733
  * @param callback Watch callback.
735
734
  * @param options Sync options.
@@ -778,7 +777,7 @@ var Reactor = class {
778
777
  cord = { cb: callback, capture, depth, once, clup: () => this.off(path, callback, options), lDepth: depth !== void 0 ? this.getDepth(path) : depth };
779
778
  if (immediate && (immediate !== "auto" || inAny(this.core, path))) {
780
779
  const target = this.getContext(path);
781
- callback(new ReactorEvent({ type: "init", target, currentTarget: target, root: this.core, rejectable: false }, this.config.eventBubbling, this.isLogging));
780
+ callback(new ReactorEvent({ type: "init", target, currentTarget: target, root: this.core, rejectable: false }, this));
782
781
  }
783
782
  (cords ?? (this.listeners.set(path, cords = []), cords)).push(cord);
784
783
  return this.bindSignal(cord, signal);
@@ -809,56 +808,39 @@ var Reactor = class {
809
808
  return this.cloned(arguments.length < 2 ? this.core : branch, raw);
810
809
  }
811
810
  /**
812
- * Cascades object updates into direct child paths.
813
- * @param payload Event or payload source.
814
- * @param objectSafe Merge old/new object values before cascading, don't set for arrays; merger doesn't play nice
815
- * @example
816
- * rtr.on("user", (event) => rtr.cascade(event));
817
- * @example
818
- * rtr.watch("user", (_value, payload) => rtr.cascade(payload));
819
- */
820
- cascade({ type, currentTarget: { path, value: news, oldValue: olds } }, objectSafe = true) {
821
- if (type !== "set" && type !== "delete" || !canHandle(news, this.config) || (objectSafe ? !canHandle(olds, this.config) : false)) return;
822
- const obj = objectSafe ? mergeObjs(olds, news) : news, keys2 = Object.keys(obj);
823
- this.isCascading = true;
824
- for (let i = 0, len = keys2.length; i < len; i++) setAny(this.core, path === "*" ? keys2[i] : path + "." + keys2[i], obj[keys2[i]]);
825
- this.isCascading = false;
826
- }
827
- /**
828
- * Installs a plugin instance.
829
- * @param plugin Plugin instance.
830
- * @returns Current reactor for fluent chaining.
811
+ * Installs a module instance.
812
+ * @param target Module instance.
813
+ * @param id Optional identification tag for this instance in the module.
814
+ * @returns Current `Reactor` instance for fluent chaining.
831
815
  */
832
- plugIn(plugin) {
833
- const name = plugin.constructor.plugName;
834
- this.plugins?.get(name)?.destroy();
835
- return (this.plugins ??= /* @__PURE__ */ new Map()).set(name, (plugin.setup(this), plugin)), this;
816
+ use(target, id) {
817
+ return (this.modules ??= /* @__PURE__ */ new Set()).add(target.setup(this, id)), this;
836
818
  }
837
- /** Resets the reactor to its initial state. */
819
+ /** Resets this reactor instance to its initial state. */
838
820
  reset() {
839
821
  this.getters?.clear(), this.setters?.clear(), this.deleters?.clear(), this.watchers?.clear(), this.listeners?.clear();
840
822
  this.batch?.clear(), this.queue?.clear(), this.isBatching = false;
841
823
  }
842
824
  destroy() {
843
- if (this.plugins) for (const plug of this.plugins.values()) plug.destroy();
825
+ if (this.modules) for (const mdle of this.modules) mdle.destroy();
844
826
  this.reset(), nuke(this);
845
827
  }
846
828
  get canLog() {
847
- return this.isLogging = this.log !== NOOP;
829
+ return this.log !== NOOP;
848
830
  }
849
831
  set canLog(value) {
850
- this.log = (this.isLogging = value) ? RTR_LOG : NOOP;
832
+ this.log = value ? RTR_LOG : NOOP;
851
833
  }
852
- get canTraceLineage() {
853
- return this.config.referenceTracking && !!this.config.lineageTracing;
834
+ get canLineageTrace() {
835
+ return this.config.lineageTracing && this.config.referenceTracking;
854
836
  }
855
837
  get canSmartClone() {
856
- return this.config.referenceTracking && !!this.config.smartCloning;
838
+ return this.config.smartCloning && this.config.referenceTracking;
857
839
  }
858
840
  };
859
841
 
860
842
  // src/ts/core/mixins.ts
861
- var methods = ["tick", "stall", "nostall", "get", "gonce", "noget", "set", "sonce", "noset", "delete", "donce", "nodelete", "watch", "wonce", "nowatch", "on", "once", "off", "snapshot", "cascade", "plugIn", "reset", "destroy"];
843
+ var methods = ["tick", "stall", "nostall", "get", "gonce", "noget", "set", "sonce", "noset", "delete", "donce", "nodelete", "watch", "wonce", "nowatch", "on", "once", "off", "snapshot", "use", "reset", "destroy"];
862
844
  function reactive(target, build, preferences = NIL) {
863
845
  if ("__Reactor__" in target) return target;
864
846
  const descriptors = {}, rtr = getReactor(target, true, build), locks = { enumerable: false, configurable: true, writable: false }, hasAffix = !!(preferences.prefix || preferences.suffix);
@@ -866,7 +848,7 @@ function reactive(target, build, preferences = NIL) {
866
848
  let key = methods[i];
867
849
  if (hasAffix) (preferences.whitelist?.includes(key) ?? true) && (key = `${preferences.prefix || ""}${key}${preferences.suffix || ""}`);
868
850
  else if (preferences.whitelist?.includes(key)) continue;
869
- descriptors[key] = { value: rtr[key].bind(rtr), ...locks };
851
+ descriptors[key] = { value: rtr[methods[i]].bind(rtr), ...locks };
870
852
  }
871
853
  descriptors["__Reactor__"] = { value: rtr, ...locks };
872
854
  return Object.defineProperties(rtr.core, descriptors), rtr.core;
@@ -979,9 +961,9 @@ var Autotracker = class {
979
961
  * const stop = atrkr.callback(() => console.log("changed")); // re-run after when ".user.name" changes
980
962
  * @example Packaged Customization
981
963
  * const atrkr = new Autotracker(); // no reactor passed
982
- * withTracker(atrkr, () => state.user.name); // import `withTracker` first
964
+ * withTracker(atrkr, () => state.user.name); // import `withTracker` too
983
965
  * const stop = atrkr.callback(() => console.log("sync"), { sync: true }); // re-run immediately when ".user.name" changes, works on any path used from any reactor state
984
- * @example Extensive customization
966
+ * @example Extensive Customization
985
967
  * atrkr.unblock();
986
968
  * const prev = CTX.autotracker;
987
969
  * CTX.autotracker = atrkr; // import CTX first
@@ -1181,8 +1163,8 @@ function effect(callback, options) {
1181
1163
 
1182
1164
  // src/ts/adapters/vanilla/TimeTravelOverlay.ts
1183
1165
  var keys = {
1184
- overrides: ["Ctrl+z", "Cmd+z", "Ctrl+y", "Cmd+y", "Ctrl+Shift+z", "Cmd+Shift+z", "Ctrl+g", "Cmd+g", ",", ".", "ArrowLeft", "ArrowRight", "Space", "Alt+Space", "Escape", "Delete", "e", "i", "c"],
1185
- shortcuts: { undo: ["Ctrl+z", "Cmd+z"], redo: ["Ctrl+y", "Cmd+y", "Ctrl+Shift+z", "Cmd+Shift+z"], genesis: ["Ctrl+g", "Cmd+g"], prevFrame: ",", nextFrame: ".", skipBwd: "ArrowLeft", skipFwd: "ArrowRight", playPause: "Space", rewind: "Alt+Space", closeOverlay: "Escape", clrHistory: "Delete", export: "e", import: "i", clear: "c" }
1166
+ overrides: ["Ctrl+z", "Cmd+z", "Ctrl+y", "Cmd+y", "Ctrl+Shift+z", "Cmd+Shift+z", "Home", "End", ",", ".", "ArrowLeft", "ArrowRight", "Space", "Alt+Space", "Escape", "Delete", "e", "i", "c"],
1167
+ shortcuts: { undo: ["Ctrl+z", "Cmd+z"], redo: ["Ctrl+y", "Cmd+y", "Ctrl+Shift+z", "Cmd+Shift+z"], genesis: "Home", ending: "End", prevFrame: ",", nextFrame: ".", skipBwd: "ArrowLeft", skipFwd: "ArrowRight", playPause: "Space", rewind: "Alt+Space", closeOverlay: "Escape", clrHistory: "Delete", export: "e", import: "i", clear: "c" }
1186
1168
  };
1187
1169
  var TimeTravelOverlay = class _TimeTravelOverlay {
1188
1170
  static count = 0;
@@ -1193,22 +1175,22 @@ var TimeTravelOverlay = class _TimeTravelOverlay {
1193
1175
  els;
1194
1176
  clups = [];
1195
1177
  keyup;
1196
- /** Creates a docked TimeTravel overlay bound to a plugin instance.
1197
- * @param time TimeTravel plugin instance that owns timeline operations.
1178
+ /** Creates a docked TimeTravel overlay bound to a module instance.
1179
+ * @param time TimeTravel module instance that owns timeline operations.
1198
1180
  * @param build Optional initial overlay config overrides.
1199
1181
  */
1200
1182
  constructor(time, build = {}) {
1201
1183
  this.time = time;
1202
1184
  this.config = reactive({ title: `Time Travel Overlay ${this.index = ++_TimeTravelOverlay.count}`, ...build });
1203
1185
  this.state.open = !!this.config.startOpen;
1204
- const s = this.time.state, host = createEl("div", { className: "tt-overlay-host" }), toggle = createEl("button", { className: "tt-overlay-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "tt-overlay", 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 }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: this.time.redo }), genesis = createEl("button", { textContent: `Genesis${formatKeyForDisplay(keys.shortcuts.genesis[0])}`, 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 }), range = createEl("input", { type: "range", min: "0", max: "0", value: "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: "tt-io", readOnly: true, placeholder: "current payload json", title: "current payload" }), io = createEl("textarea", { className: "tt-io", placeholder: "timeline payload json", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "tt-footnote", textContent: "Want this in your app? " }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "tt-status-box" }), status = createEl("div", { className: "tt-status-row" }), row1 = createEl("div", { className: "tt-row" }), row2 = createEl("div", { className: "tt-row" }), row3 = createEl("div", { className: "tt-row" });
1186
+ const s = this.time.state, host = createEl("div", { className: "tt-overlay-host" }), toggle = createEl("button", { className: "tt-overlay-toggle", type: "button", onclick: () => this.state.open = !this.state.open }), panel = createEl("aside", { className: "tt-overlay", 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 }), redo = createEl("button", { textContent: `Redo${formatKeyForDisplay(keys.shortcuts.redo[0])}`, ariaKeyShortcuts: parseForARIAKS(keys.shortcuts.redo, false), onclick: this.time.redo }), 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 }), range = createEl("input", { type: "range", min: "0", max: "0", value: "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: "tt-io", readOnly: true, placeholder: "current payload json", title: "current payload" }), io = createEl("textarea", { className: "tt-io", placeholder: "timeline payload json", oninput: () => this.state.import = io.value }), foot = createEl("p", { className: "tt-footnote", textContent: "Want this in your app? " }), link = createEl("a", { target: "_blank", rel: "noreferrer noopener", textContent: "sia-reactor", href: "https://www.npmjs.com/package/sia-reactor" }), box = createEl("div", { className: "tt-status-box" }), status = createEl("div", { className: "tt-status-row" }), row1 = createEl("div", { className: "tt-row" }), row2 = createEl("div", { className: "tt-row" }), row3 = createEl("div", { className: "tt-row" });
1205
1187
  status.append((box.append(frame), box), clrHistory);
1206
1188
  panel.append(title, status, (row1.append(undo, redo, genesis), row1), (row2.append(playPause, rewind), row2), payload, range, (row3.append(exp, imp, clr), row3), io, (foot.appendChild(link), foot));
1207
1189
  host.append(toggle, panel);
1208
1190
  this.els = { host, toggle, panel, title, frame, clrHistory, undo, redo, genesis, playPause, rewind, range, exp, imp, clr, payload, io };
1209
1191
  this.keyup = (e) => {
1210
- const a = this.state.open && keyEventAllowed(e, keys);
1211
- a === "undo" ? this.time.undo() : a === "redo" ? this.time.redo() : a === "genesis" ? this.time.jumpTo(0) : a === "prevFrame" ? this.time.step(1, false) : a === "nextFrame" ? this.time.step(1, true) : a === "skipBwd" ? this.time.step(5, false) : a === "skipFwd" ? this.time.step(5, true) : a === "rewind" ? this.time.rewind() : a === "playPause" ? this.time[s.paused ? "play" : "pause"]() : a === "clrHistory" ? this.time.clear() : a === "closeOverlay" ? this.state.open = false : a === "export" ? this.state.import = this.time.export() : a === "import" ? this.state.import.trim().length && this.time.import(this.state.import) : a === "clear" && (this.state.import = "");
1192
+ const a = this.state.open && (this.config.devOnly ? CTX.isDevEnv : true) && keyEventAllowed(e, keys);
1193
+ a === "undo" ? this.time.undo() : a === "redo" ? this.time.redo() : a === "genesis" ? this.time.jumpTo(0) : a === "ending" ? this.time.jumpTo(s.history.length) : a === "prevFrame" ? this.time.step(1, false) : a === "nextFrame" ? this.time.step(1, true) : a === "skipBwd" ? this.time.step(5, false) : a === "skipFwd" ? this.time.step(5, true) : a === "rewind" ? this.time.rewind() : a === "playPause" ? this.time[s.paused ? "play" : "pause"]() : a === "clrHistory" ? this.time.clear() : a === "closeOverlay" ? this.state.open = false : a === "export" ? this.state.import = this.time.export() : a === "import" ? this.state.import.trim().length && this.time.import(this.state.import) : a === "clear" && (this.state.import = "");
1212
1194
  };
1213
1195
  window.addEventListener("keydown", this.keyup);
1214
1196
  const sync = [
@@ -1223,7 +1205,8 @@ var TimeTravelOverlay = class _TimeTravelOverlay {
1223
1205
  effect(() => {
1224
1206
  frame.textContent = `Frame: ${s.currentFrame} / ${s.history.length}`;
1225
1207
  range.disabled = clrHistory.disabled = !s.history.length;
1226
- genesis.disabled = rewind.disabled = undo.disabled = !s.currentFrame;
1208
+ genesis.disabled = undo.disabled = !s.currentFrame;
1209
+ rewind.disabled = !s.paused || !s.currentFrame;
1227
1210
  playPause.disabled = redo.disabled = s.currentFrame >= s.history.length;
1228
1211
  range.max = String(s.history.length);
1229
1212
  range.value = String(Math.min(s.currentFrame, s.history.length));
@@ -1237,7 +1220,7 @@ var TimeTravelOverlay = class _TimeTravelOverlay {
1237
1220
  this.clups.push(...sync);
1238
1221
  }
1239
1222
  destroy() {
1240
- this.clups.forEach((fn) => fn());
1223
+ for (const clup of this.clups) clup();
1241
1224
  this.keyup && window.removeEventListener("keydown", this.keyup);
1242
1225
  this.els.host.remove();
1243
1226
  nuke(this), --_TimeTravelOverlay.count;
@@ -1,7 +1,7 @@
1
- import { E as EffectOptions, b as Reactor, R as Reactive, o as ReactorBuild, W as WildPaths, q as PathValue } from '../index-Oie9hhE8.cjs';
1
+ import { E as EffectOptions, R as Reactor, d as Reactive, u as ReactorBuild, W as WildPaths, v as PathValue } from '../index-m0aAWxhX.cjs';
2
2
  import { useLayoutEffect } from 'react';
3
- import { T as TimeTravelPlugin } from '../timeTravel-WpgWmKu-.cjs';
4
- import { T as TimeTravelConfig } from '../TimeTravelOverlay-CJv-S_Km.cjs';
3
+ import { m as TimeTravelModule } from '../timeTravel-DctvcHVt.cjs';
4
+ import { T as TimeTravelConfig } from '../TimeTravelOverlay-OjklzuCD.cjs';
5
5
 
6
6
  /**
7
7
  * Subscribes a component to desired Reactor state and returns it.
@@ -12,12 +12,12 @@ import { T as TimeTravelConfig } from '../TimeTravelOverlay-CJv-S_Km.cjs';
12
12
  * @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
13
13
  * @returns State for render usage if state is scoped locally or just desired.
14
14
  * @example
15
- * const a = useReactor({ user: { name: "Ada" } }); // per-component scoped
15
+ * const a = useReactor({ user: { name: "Kosi" } }); // per-component scoped
16
16
  * @example
17
- * const state = reactive({ user: { name: "Ada" } });
17
+ * const state = reactive({ user: { name: "Kosi" } });
18
18
  * const b = useReactor(state);
19
19
  * @example
20
- * const rtr = new Reactor({ user: { name: "Ada" } });
20
+ * const rtr = new Reactor({ user: { name: "Kosi" } });
21
21
  * const c = useReactor(rtr);
22
22
  */
23
23
  declare function useReactor<T extends object>(target: T | Reactor<T> | Reactive<T>, options?: EffectOptions, build?: ReactorBuild<T>): T;
@@ -39,12 +39,12 @@ declare function useAnyReactor(options?: EffectOptions): void;
39
39
  * @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
40
40
  * @returns Tracked snapshot snap for render usage.
41
41
  * @example
42
- * const a = useReactorSnapshot({ user: { name: "Ada" } }); // per-component scoped
42
+ * const a = useReactorSnapshot({ user: { name: "Kosi" } }); // per-component scoped
43
43
  * @example
44
- * const state = reactive({ user: { name: "Ada" } });
44
+ * const state = reactive({ user: { name: "Kosi" } });
45
45
  * const b = useReactorSnapshot(state);
46
46
  * @example
47
- * const rtr = new Reactor({ user: { name: "Ada" } });
47
+ * const rtr = new Reactor({ user: { name: "Kosi" } });
48
48
  * const c = useReactorSnapshot(rtr);
49
49
  */
50
50
  declare function useReactorSnapshot<T extends object>(target: T | Reactor<T> | Reactive<T>, options?: EffectOptions, build?: ReactorBuild<T>): T;
@@ -62,12 +62,12 @@ declare function useReactorSnapshot<T extends object>(target: T | Reactor<T> | R
62
62
  * @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
63
63
  * @returns The selected slice.
64
64
  * @example
65
- * const a = useSelector({ user: { name: "Ada" } }, (s) => s.user.name); // per-component scoped
65
+ * const a = useSelector({ user: { name: "Kosi" } }, (s) => s.user.name); // per-component scoped
66
66
  * @example
67
- * const state = reactive({ user: { name: "Ada" } });
67
+ * const state = reactive({ user: { name: "Kosi" } });
68
68
  * const b = useSelector(state, (s) => s.user.name);
69
69
  * @example
70
- * const rtr = new Reactor({ user: { name: "Ada" } });
70
+ * const rtr = new Reactor({ user: { name: "Kosi" } });
71
71
  * const c = useSelector(rtr, (s) => s.user.name);
72
72
  */
73
73
  declare function useSelector<T extends object, R>(target: T | Reactor<T> | Reactive<T>, sel: (state: T) => R, eq?: (prev: R | undefined, next: R) => boolean, options?: EffectOptions, build?: ReactorBuild<T>): R;
@@ -95,12 +95,12 @@ declare function useAnySelector<R>(sel: () => R, eq?: (value1: any, value2: any)
95
95
  * @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
96
96
  * @returns The selected slice.
97
97
  * @example
98
- * const a = useSelectorSnapshot({ user: { name: "Ada" } }, (s) => s.user.name); // per-component scoped
98
+ * const a = useSelectorSnapshot({ user: { name: "Kosi" } }, (s) => s.user.name); // per-component scoped
99
99
  * @example
100
- * const state = reactive({ user: { name: "Ada" } });
100
+ * const state = reactive({ user: { name: "Kosi" } });
101
101
  * const b = useSelectorSnapshot(state, (s) => s.user.name);
102
102
  * @example
103
- * const rtr = new Reactor({ user: { name: "Ada" } });
103
+ * const rtr = new Reactor({ user: { name: "Kosi" } });
104
104
  * const c = useSelectorSnapshot(rtr, (s) => s.user.name);
105
105
  */
106
106
  declare function useSelectorSnapshot<T extends object, R>(target: T | Reactor<T> | Reactive<T>, sel: (state: T) => R, eq?: (value1: any, value2: any) => boolean, options?: EffectOptions, build?: ReactorBuild<T>): R;
@@ -116,12 +116,12 @@ declare function useSelectorSnapshot<T extends object, R>(target: T | Reactor<T>
116
116
  * @param build Optional Reactor build options used when creating a scoped Reactor for plain objects.
117
117
  * @returns Current value at the requested path.
118
118
  * @example
119
- * const a = usePath({ user: { profile: { name: "Ada" } } }, "user.profile.name");
119
+ * const a = usePath({ user: { profile: { name: "Kosi" } } }, "user.profile.name");
120
120
  * @example
121
- * const state = reactive({ user: { profile: { name: "Ada" } } });
121
+ * const state = reactive({ user: { profile: { name: "Kosi" } } });
122
122
  * const b = usePath(state, "user.profile.name");
123
123
  * @example
124
- * const rtr = new Reactor({ user: { profile: { name: "Ada" } } });
124
+ * const rtr = new Reactor({ user: { profile: { name: "Kosi" } } });
125
125
  * const c = usePath(rtr, "user.profile.name");
126
126
  * @example
127
127
  * const wholeState = usePath(state, "*");
@@ -133,11 +133,12 @@ declare const useISOLayoutEffect: typeof useLayoutEffect;
133
133
 
134
134
  /** React props for controlling the vanilla TimeTravel overlay. */
135
135
  interface TimeTravelOverlayProps extends Partial<TimeTravelConfig> {
136
- /** Plugin instance controlled by this overlay bridge. */
137
- time: TimeTravelPlugin;
136
+ /** Module instance controlled by this overlay bridge. */
137
+ time: TimeTravelModule;
138
138
  }
139
- /** React bridge for mounting and controlling a vanilla TimeTravelOverlay instance.
140
- * Instantiates a `TimeTravelOverlay` for the provided plugin, tears it down on unmount, and syncs prop changes into reactive `config`.
139
+ /**
140
+ - React bridge for mounting and controlling a vanilla TimeTravelOverlay instance.
141
+ - Instantiates a `TimeTravelOverlay` for the provided module, tears it down on unmount, and syncs prop changes into reactive `config`.
141
142
  * Use this when your app is React but you want the overlay behavior with react-safe instance lifecycle management.
142
143
  * @param props Overlay bridge props.
143
144
  */