sia-reactor 0.0.20 → 0.0.22

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 (39) hide show
  1. package/README.md +120 -96
  2. package/dist/{TimeTravelOverlay-BYSnHBXx.d.cts → TimeTravelOverlay-DiXUgbUU.d.cts} +9 -8
  3. package/dist/{TimeTravelOverlay-DoNrZwvX.d.ts → TimeTravelOverlay-eWjAy0yr.d.ts} +9 -8
  4. package/dist/adapters/react.cjs +140 -176
  5. package/dist/adapters/react.d.cts +59 -17
  6. package/dist/adapters/react.d.ts +59 -17
  7. package/dist/adapters/react.js +35 -11
  8. package/dist/adapters/vanilla.cjs +107 -169
  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-VPR5SP3E.js → chunk-3SKLWTEA.js} +80 -110
  13. package/dist/{chunk-DP74DVRT.js → chunk-BTA6MIQ6.js} +40 -8
  14. package/dist/{chunk-RFQ2JJSV.js → chunk-CS3FOV6J.js} +27 -58
  15. package/dist/{index-DCG3sacH.d.cts → index-BgbbNXTW.d.cts} +312 -212
  16. package/dist/{index-DCG3sacH.d.ts → index-BgbbNXTW.d.ts} +312 -212
  17. package/dist/index.cjs +82 -115
  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} +476 -210
  22. package/dist/modules.d.cts +53 -0
  23. package/dist/modules.d.ts +53 -0
  24. package/dist/modules.js +627 -0
  25. package/dist/styles/time-travel-overlay.css +1 -1
  26. package/dist/super.d.ts +620 -289
  27. package/dist/super.global.js +497 -263
  28. package/dist/timeTravel-CraHdbXZ.d.cts +352 -0
  29. package/dist/timeTravel-YUxRHRgh.d.ts +352 -0
  30. package/dist/utils.cjs +41 -7
  31. package/dist/utils.d.cts +1 -1
  32. package/dist/utils.d.ts +1 -1
  33. package/dist/utils.js +3 -1
  34. package/package.json +6 -6
  35. package/dist/plugins.d.cts +0 -112
  36. package/dist/plugins.d.ts +0 -112
  37. package/dist/plugins.js +0 -363
  38. package/dist/timeTravel-Bv_u5M1D.d.ts +0 -75
  39. package/dist/timeTravel-L8CEhHIo.d.cts +0 -75
package/README.md CHANGED
@@ -16,7 +16,7 @@
16
16
 
17
17
  - [sia-reactor](#sia-reactor)
18
18
  - [Table of contents](#table-of-contents)
19
- - [Reading Paths](#reading-paths)
19
+ - [Why sia-reactor?](#why-sia-reactor)
20
20
  - [Getting Started](#getting-started)
21
21
  - [Usage](#usage)
22
22
  - [API Reference](#api-reference)
@@ -30,41 +30,45 @@
30
30
 
31
31
  ---
32
32
 
33
- ## Reading Paths
33
+ ## Why sia-reactor?
34
34
 
35
- Choose your reading mode:
35
+ Most state libraries react to changes.
36
36
 
37
- - **I want to understand the architecture shift first**:
38
- Read [Chronicles](https://github.com/Tobi007-del/tmg-media-player/blob/main/CHRONICLES.md) and [Interaction Folklore](https://github.com/Tobi007-del/tmg-media-player/blob/main/FOLKLORE.md), then continue here.
39
- - **I just need to use this fast**:
40
- Jump directly to [Getting Started](#getting-started) and [API Reference](#api-reference).
37
+ `sia-reactor` lets you:
41
38
 
42
- ### Quick Overview
39
+ - intercept changes BEFORE they happen
40
+ - approve or reject user intent
41
+ - observe changes AFTER they settle
42
+ - treat your state like a programmable event system
43
43
 
44
- `sia-reactor` treats nested data like a programmable evented tree.
45
-
46
- - **State** = factual reality.
47
- - **Intent** = requested reality.
48
- - **Mediators** (`get|set|delete`) = synchronous gatekeepers.
49
- - **Watchers** (`watch`) = synchronous post-mutation observers.
50
- - **Listeners** (`on`) = microtask-batched event observers.
51
-
52
- Semantic split recommendation:
53
- - `intent`: async/delayed requests.
54
- - `state`: granted facts.
55
- - `settings/config (custom)`: immediate user prefs.
56
- - `status (custom)`: read-only system facts.
44
+ ```js
45
+ const player = reactive({
46
+ intent: intent({ playing: false }),
47
+ state: { playing: false }
48
+ });
57
49
 
58
- ```javascript
59
- import { reactive, intent } from 'sia-reactor';
50
+ // Logic layer (capture phase)
51
+ player.on("intent.playing", (e) => {
52
+ if (!ready) return e.reject();
53
+ player.state.playing = true;
54
+ }, { capture: true });
60
55
 
61
- const player = reactive({
62
- intent: intent({ playing: false, fullscreen: false }),
63
- state: { playing: false, fullscreen: false },
64
- settings: { theme: "dark", defaultPlaybackRate: 1 },
65
- status: { buffering: false, duration: 120 }
56
+ // UI layer
57
+ player.on("state.playing", (e) => {
58
+ console.log("Now playing:", e.value);
66
59
  });
60
+
61
+ // User action
62
+ player.intent.playing = true;
67
63
  ```
64
+ ***"This is the entire system."***
65
+
66
+ Choose your reading mode:
67
+
68
+ - **I want to understand the architecture shift first**:
69
+ Read [Chronicles](https://github.com/Tobi007-del/tmg-media-player/blob/main/CHRONICLES.md) and [Interaction Folklore](https://github.com/Tobi007-del/tmg-media-player/blob/main/FOLKLORE.md), then continue here.
70
+ - **I just need to use this fast**:
71
+ Jump directly to [Getting Started](#getting-started) and [API Reference](#api-reference).
68
72
 
69
73
  ---
70
74
 
@@ -84,10 +88,10 @@ pnpm add sia-reactor
84
88
 
85
89
  ```javascript
86
90
  // 1. Core Engine
87
- import { reactive, Reactor, TERMINATOR } from 'sia-reactor';
91
+ import { reactive, Reactor, TERMINATOR } from "sia-reactor";
88
92
 
89
93
  // 2. Deep Object Utilities
90
- import { setAny, getAny, mergeObjs } from 'sia-reactor/utils';
94
+ import { setAny, getAny, mergeObjs } from "sia-reactor/utils";
91
95
  ```
92
96
 
93
97
  ---
@@ -97,12 +101,12 @@ import { setAny, getAny, mergeObjs } from 'sia-reactor/utils';
97
101
  ### Modern Bundlers (ESM)
98
102
 
99
103
  ```javascript
100
- import { reactive, Reactor } from 'sia-reactor';
101
- import 'sia-reactor/utils'; // deep object helpers (setAny/getAny/mergeObjs/...)
102
- import 'sia-reactor/plugins'; // built-in plugins + storage adapters
103
- import 'sia-reactor/adapters/vanilla'; // Autotracker + effect API + TimeTravelOverlay class
104
- import 'sia-reactor/adapters/vanilla/time-travel-overlay.css'; // TimeTravelOverlay CSS
105
- import 'sia-reactor/adapters/react'; // useReactor/useSelector/usePath hooks
104
+ import { reactive, Reactor } from "sia-reactor";
105
+ import "sia-reactor/utils"; // deep object helpers (setAny/getAny/deleteAny/inAny/parseAnyObj/fanout/mergeObjs/deepClone/nuke...)
106
+ import "sia-reactor/modules"; // built-in modules + storage adapters
107
+ import "sia-reactor/adapters/vanilla"; // Autotracker + effect API + TimeTravelOverlay class
108
+ import "sia-reactor/adapters/react"; // useReactor/useSelector/usePath hooks
109
+ import "sia-reactor/styles/time-travel-overlay.css"; // TimeTravelOverlay CSS
106
110
  ```
107
111
 
108
112
  ### CDN / Browser (Global)
@@ -115,7 +119,7 @@ import 'sia-reactor/adapters/react'; // useReactor/useSelector/usePath hooks
115
119
  <script>
116
120
  const { reactive, Reactor } = window.sia;
117
121
  window.sia.utils;
118
- window.sia.plugins;
122
+ window.sia.modules;
119
123
  window.sia.adapters.vanilla;
120
124
  </script>
121
125
  </body>
@@ -143,8 +147,8 @@ getReactor(state); state.__Reactor__; // Reference to the underlying reactor
143
147
 
144
148
  Alternatively, you can instantiate the `Reactor` class directly to keep the API from interfering with your data or [try this](#reactive-preferences-method-naming):
145
149
  ```javascript
146
- const reactor = new Reactor({ player: { volume: 50 } }, { debug: true, referenceTracking: true });
147
- reactor.core.player.volume = 100;
150
+ const reactor = new Reactor({ player: { volume: 50 } }, { debug: true });
151
+ reactor.core.player.volume = 100; // re-assign core if desired
148
152
  ```
149
153
 
150
154
  ### Core Methods
@@ -157,10 +161,10 @@ All methods are available on `Reactor` instances or objects wrapped in `reactive
157
161
  - **`delete(path, callback, options)`**: Intercept property deletion.
158
162
 
159
163
  #### **Watchers (Synchronous Observers)**
160
- - **`watch(path, callback, options)`**: Fires instantly after a mutation. Use strictly for critical internal engine syncing.
164
+ - **`watch(path, callback, options)`**: Fires instantly after a mutation. Use strictly for critical internal engine syncing on leaf paths preferably, sees only direct operations.
161
165
 
162
166
  #### **Listeners (Asynchronous/Batched UI Observers)**
163
- - **`on(path, callback, options)`**: Attach DOM-style event listeners. Supports `{ capture: true, depth: 1, once: true, immediate: true }`.
167
+ - **`on(path, callback, options)`**: Attach DOM-style event listeners that respect `depth`. Supports `{ capture: true, depth: 1, once: true, immediate: true }`.
164
168
  - **`once(path, callback, options)`**: Fires once and self-destructs.
165
169
  - **`off(path, callback, options)`**: Removes a listener.
166
170
 
@@ -168,8 +172,7 @@ All methods are available on `Reactor` instances or objects wrapped in `reactive
168
172
  - **`tick(path)`**: Forces a synchronous flush of the batch queue for a specific path.
169
173
  - **`stall(task)` / `nostall(task)`**: Manually stall the queue to wait for calculations before rendering.
170
174
  - **`snapshot(raw)`**: Generates a strict, structurally-shared, un-proxied clone of the current state tree.
171
- - **`cascade(eventOrPayload, objectSafe)`**: Manually trigger direct object values event waves, bypassing strict unchanged-proxy traps, `objectSafe` merges `value` with `oldValue`.
172
- - **`plugIn(new ReactorPlugin(config))`**: Allows extended behaviour with external logic.
175
+ - **`use(new ReactorModule(config), id)`**: Allows extended behaviour with external logic.
173
176
  - **`reset()`**: Clears all records bringing everything back to a clean slate.
174
177
  - **`destroy()`**: Last resort destruction, nukes everything by nullifying it's properties for full disposal, lives on every class.
175
178
 
@@ -182,7 +185,7 @@ You can wrap properties in special flags *before* initializing the reactor to di
182
185
  - **`volatile(obj)` / `stable(obj)`**: Forces the reactor to fire event waves even if the new value is identical to the old value (bypassing the Proxy's unchanged performance check).
183
186
 
184
187
  ```javascript
185
- import { reactive, intent, volatile, inert } from 'sia-reactor';
188
+ import { reactive, intent, volatile, inert } from "sia-reactor";
186
189
 
187
190
  const data = reactive({
188
191
  apiResponse: inert({ heavy: "data" }), // Proxy won't traverse this
@@ -193,26 +196,26 @@ const data = reactive({
193
196
 
194
197
  ### React Hooks & Effects
195
198
 
196
- The engine provides native React bindings utilizing `useSyncExternalStore` and an internal `Autotracker` for concurrent-safe, surgically precise component re-renders. All hooks natively accept a `Reactor` instance, a `reactive()` proxy, or a plain object (which will be auto-wrapped on the fly).
199
+ The engine provides native React bindings utilizing `useSyncExternalStore` and an internal `Autotracker` for concurrent-safe, surgically precise component re-renders. All hooks natively accept a `Reactor` instance, a `reactive()` proxy, or a plain object (which will be auto-wrapped on the fly). Just import, your editor will reveal more details.
197
200
 
198
201
  ```javascript
199
- import { reactive } from 'sia-reactor';
200
- import { useReactor, useSelector, usePath, effect } from 'sia-reactor/react';
202
+ import { reactive } from "sia-reactor";
203
+ import { useReactor, useAnyReactor, useSelector, useAnySelector, usePath, effect } from "sia-reactor/adapters/react";
201
204
 
202
- const state = reactive({ user: { name: "Ada", age: 25 }, theme: "dark" });
205
+ const state = reactive({ user: { name: "Kosi", age: 25 }, theme: "dark" });
203
206
 
204
207
  // 1. The Tracked State (Valtio-style)
205
208
  function Profile() {
206
- const sameState = useReactor(state); // pass in a normal object for an auto-scoped instance
207
- useAnyReactor(); // use this when you just want to use any state from any reactor
209
+ const sameState = useReactor(state); // `useReactorSnapshot()` if mutable issues arise
210
+ useAnyReactor(); // when you just want state from any reactor
208
211
  // Only re-renders if state.user.name mutates. Completely ignores age and theme!
209
212
  return <div>{sameState.user.name + otherState.user.name}</div>;
210
213
  } // no snapshots like Valtio, you can read or write to anything
211
214
 
212
215
  // 2. The Slice Selector (Zustand-style)
213
216
  function Theme() {
214
- const theme = useSelector(state, (s) => s.theme); // pass in a normal object for an auto-scoped instance
215
- const newName = useAnySelector(() => state.user.name + spouseState.user.name); // use this when you just want to derive any state from any reactor
217
+ const theme = useSelector(state, (s) => s.theme); // `useSelectorSnapshot()` if mutable issues arise
218
+ const newName = useAnySelector(() => state.user.name + spouseState.user.name); // when you just want to derive any state from any reactor
216
219
  return <div>Theme: {theme}</div>;
217
220
  }
218
221
 
@@ -223,56 +226,59 @@ function AgeObserver() {
223
226
  }
224
227
 
225
228
  // 4. Vanilla Side Effects (Runs anywhere, framework agnostic)
226
- const stopTracking = effect(() => {
227
- console.log("User name changed to:", state.user.name);
228
- });
229
+ const stopTracking = effect(() => console.log("User name changed to:", state.user.name)); // read or write as you wish
229
230
  ```
230
231
 
231
- ### Plugins: The Extension Port
232
+ ### Modules: The Extension Port
232
233
 
233
- The `Reactor` is designed to be a lightweight core. Extended capabilities are attached via Plugins. It ships with a suite of built-in plugins for common architectural needs.
234
+ The `Reactor` is designed to be a lightweight core. Extended capabilities are attached via Modules. It ships with a suite of powerful modules for common architectural needs.
234
235
 
235
- #### The Persistence Plugin
236
- Automatically syncs your State to LocalStorage, SessionStorage, Memory or IndexedDB. It respects the async nature of any adapter while keeping your app synchronous.
236
+ #### The Persistence Module
237
+ Automatically syncs your State to LocalStorage, SessionStorage, Memory or IndexedDB. Always use this module first to avoid re-initialization issues.
237
238
 
238
239
  ```javascript
239
- import { reactive, Reactor, getReactor } from 'sia-reactor';
240
- import { PersistPlugin, LocalStorageAdapter, IndexedDBAdapter } from 'sia-reactor/plugins';
240
+ import { reactive, Reactor, getReactor } from "sia-reactor";
241
+ import { PersistModule, LocalStorageAdapter, IndexedDBAdapter, SessionStorageAdapter, CookieAdapter, MemoryAdapter } from "sia-reactor/modules";
241
242
 
242
243
  const state = reactive({ theme: "dark", settings: { volume: 50, brightness: 30 } });
243
- state.plugIn(new PersistPlugin({ // Plug it in. State is now automatically hydrated and throttled-saved.
244
+ const persist = new PersistModule({ // Plug it in. State is now automatically hydrated and throttled-saved.
244
245
  key: "APP_PREFS",
245
246
  paths: ["theme", "settings.brightness"],
246
247
  throttle: 5000,
247
- adapter: new IndexedDBAdapter({ dbName: "Session", version: 1, onversionchange: () => location.reload() }) // or `LocalStorageAdapter` (instance or signature)
248
- }, getReactor(state))); // Put Reactor as second arg if you want type inference, e.g. for the paths in the array.
248
+ fanout: true, // async hydration should use leaf writes incase UI listeners already initialized.
249
+ adapter: new IndexedDBAdapter({ dbName: "Session", version: 1, onversionchange: () => location.reload(), useSnapshot: true }) // or `LocalStorageAdapter` (instance or signature)
250
+ };
251
+ state.use(persist, getReactor(state))); // Put `Reactor` as second constructor arg if you want type inference, e.g. for the paths in the array.
249
252
  ```
250
253
 
251
- #### The Time Travel Plugin
254
+ #### The Time Travel Module
252
255
  Record state frames, step through history, and optionally attach a ready-to-use vanilla debug overlay.
253
256
 
254
257
  ```javascript
255
- import { reactive } from 'sia-reactor';
256
- import { TimeTravelPlugin } from 'sia-reactor/plugins';
257
- import { TimeTravelOverlay } from 'sia-reactor/adapters/vanilla';
258
- import 'sia-reactor/css/time-travel-overlay.css';
259
-
260
- const state = reactive({ count: 0, filter: "all" });
261
- const time = new TimeTravelPlugin({ maxHistory: 300, loop: false, rate: 150 });
262
- state.plugIn(time);
258
+ import { TimeTravelModule } from "sia-reactor/modules";
259
+ import { effect, TimeTravelOverlay } from "sia-reactor/adapters/vanilla";
260
+ import "sia-reactor/css/time-travel-overlay.css";
261
+
262
+ const time = new TimeTravelModule({ maxHistory: 300, loop: false, rate: 150 });
263
+ state.use(time);
264
+
265
+ // If persist uses an async adapter (e.g. IndexedDB), wait till after hydration:
266
+ persist.state.once("hydrated", () => state.use(time)); // starts `false`, one-time stall until it flips
267
+ effect(() => persist.state.hydrated && state.use(time), { once: true }) // same logic, different look :)
268
+
263
269
  const overlay = new TimeTravelOverlay(time, { color: "#e26e02", startOpen: false, devOnly: true, container: document.body }); // optional debug interface for visulazation
264
270
  ```
265
271
  ```jsx
266
- import { TimeTravelOverlay } from 'sia-reactor/adapters/react';
272
+ import { TimeTravelOverlay } from "sia-reactor/adapters/react";
267
273
 
268
274
  <TimeTravelOverlay time={time} color="#e26e02" startOpen devOnly /> // react-safe instance lifecycle management, e.g. for HMR predictability.
269
275
  ```
270
276
 
271
- Useful plugin methods: `play()`, `pause()`, `rewind()`, `clear()`, `undo()`, `redo()`, `step(n, forward)`, `jumpTo(frame)`, `export()`, `import(serialized)`.
277
+ Useful methods: `play()`, `pause()`, `rewind()`, `clear()`, `undo()`, `redo()`, `step(n, forward)`, `jumpTo(frame)`, `export(replacer)`, `import(json, reviver)`.
272
278
 
273
279
  ### Reactor Build Options
274
280
 
275
- These are some core build options accepted by `new Reactor(core, build)` and `reactive(core, build, preferences)`.
281
+ These are some core build options accepted by `new Reactor(core, build)` and `reactive(core, build, preferences)` configurable via `Reactor.config`.
276
282
 
277
283
  - **`debug?`**: 1-time set. Enables debug logging and diagnostics of core operations. (default: `false`)
278
284
  - **`crossRealms?`**: Enables cross-realm object detection support by using slower but safer type checks. (e.g. iframes) (default: `false`).
@@ -283,8 +289,6 @@ These are some core build options accepted by `new Reactor(core, build)` and `re
283
289
  - **`equalityFunction?`**: Custom equality used by setters and adapter comparisons (default: `Object.is`).
284
290
  - **`batchingFunction?`**: Custom batching scheduler for listener notification flushes (default: `queueMicrotask`)
285
291
  - **`referenceTracking?`**: Enables identity/reference tracking features in the runtime. (default: `false`).
286
-
287
- *NOTE: those not marked as 1-time set are configurable via `Reactor.config`. Also, plugs and hooks turn on whatever they need automatically.*
288
292
 
289
293
  ### Reactive Preferences (Method Naming)
290
294
 
@@ -295,7 +299,7 @@ These are some core build options accepted by `new Reactor(core, build)` and `re
295
299
  - **`whitelist?`**: Keeps specific methods on their original names while others get affixed.
296
300
 
297
301
  ```javascript
298
- import { reactive } from 'sia-reactor';
302
+ import { reactive } from "sia-reactor";
299
303
 
300
304
  const state = reactive(
301
305
  { count: 0 },
@@ -341,9 +345,10 @@ player.on("intent.playing", (e) => {
341
345
 
342
346
  ### Troubleshooting
343
347
 
344
- - Listener timing feels late: `on` is microtask-batched by design; use `watch` only for strict immediate engine sync.
345
- - `reject()` appears ignored: call it in capture phase and ensure branch is wrapped in `intent(...)`, remember it's the listener's choice to listen also.
346
- - Snapshot behavior feels stale: enable `referenceTracking: true` with `smartCloning: true`.
348
+ - Listener timing feels late: `on(path, ...)` is microtask-batched by design; use `watch(path, ...)` only for strict immediate engine sync on leaf paths preferably.
349
+ - Listeners don't react to changes: use `fanout(state, path, object, { depth: n })` instead of direct object sets to keep immutable semantics.
350
+ - `reject()` appears ignored: call it in capture phase and ensure branch is wrapped in `intent(...)`, also remember it's the listener's choice to comply.
351
+ - Snapshot behavior feels stale: enable `referenceTracking: true` with `smartCloning: true`, also use these when persisting to environments that don't take proxies, e.g. IndexedDB.
347
352
  - Cross-frame data is skipped: enable `crossRealms: true` for iframe/other realm objects.
348
353
  - Class/prototype behavior is odd: enable `preserveContext: true` (tradeoff: slower hot paths).
349
354
  - Working with symbol keys and you want blind writes/reads: unwrap first with `getRaw` or `RAW` and operate on the raw object.
@@ -355,9 +360,9 @@ player.on("intent.playing", (e) => {
355
360
  The S.I.A. Reactor operates in two distinct dimensions: **The Synchronous Dimension** (Gatekeepers & Watchers) and **The Asynchronous Dimension** (Listeners). Because they intercept data at entirely different points in time, they receive different objects and possess different capabilities.
356
361
 
357
362
  ### 1. The Synchronous Dimension: The `Payload`
358
- When you use `get`, `set`, `delete`, or `watch`, you are sitting *directly inside the Javascript Proxy Trap*. The memory has not been written yet (or is being written right at that exact millisecond).
363
+ When you use `.get()`, `.set()`, `.delete()`, or `.watch()`, you are sitting *directly inside the Javascript Proxy Trap*. The memory has not been written yet (or is being written right at that exact millisecond).
359
364
 
360
- Because there is no "bubbling" or "event wave" yet, these methods do not receive a complex event object. They receive a lightweight, factual `Payload`.
365
+ Because there is no "bubbling" or "event wave" yet, these methods do not receive an event object. They receive a lightweight, factual `Payload`.
361
366
 
362
367
  #### The `Payload` Anatomy
363
368
  ```javascript
@@ -390,7 +395,7 @@ The `target` and `currentTarget` objects give you absolute surgical awareness of
390
395
  Because `set` and `delete` mediators execute *before* the memory is written, you have the power to alter reality or stop it entirely using the `TERMINATOR` symbol.
391
396
 
392
397
  ```javascript
393
- import { TERMINATOR } from 'sia-reactor';
398
+ import { TERMINATOR } from "sia-reactor";
394
399
 
395
400
  // Example: Data Sanitization & Blocking
396
401
  rtr.set("user.age", (value) => {
@@ -400,14 +405,14 @@ rtr.set("user.age", (value) => {
400
405
  ```
401
406
 
402
407
  ### 2. The Asynchronous Dimension: The S.I.A. Event Loop
403
- When you use `on` or `once` (Listeners), you are sitting in the **Microtask Queue**. The memory has already been safely written, the Proxy traps have closed, and the engine is now broadcasting a DOM-Style "Mutation Wave" across the state tree.
408
+ When you use `.on()` or `.once()` (Listeners), you are sitting in the **Microtask Queue**. The memory has already been safely written, the Proxy traps have closed, and the engine is now broadcasting a DOM-Style "Mutation Wave" across the state tree.
404
409
 
405
- If you mutate `state.user.profile.name = "Ada"`, the event wave travels like this:
410
+ If you mutate `state.user.profile.name = "Kosi"`, the event wave travels like this:
406
411
  1. **Capture Phase:** `*` (Root) ➔ `user` ➔ `user.profile`
407
412
  2. **Target Phase:** `user.profile.name`
408
413
  3. **Bubble Phase:** `user.profile` ➔ `user` ➔ `*` (Root)
409
414
 
410
- *NOTE: Only `on` does this since it is batched tree walking to stay within recursive limits.*
415
+ *NOTE: Only `on` does this since it is batched to stay within recursive limits.*
411
416
 
412
417
  #### The Event Anatomy (`REvent` type)
413
418
  Listeners receive a `ReactorEvent` (`REvent`). This object *inherits* everything from the `Payload`, but adds **Political Event Routing**, providing absolute surgical awareness of what is happening in the tree.
@@ -419,13 +424,13 @@ rtr.on("user.profile", (e) => {
419
424
  console.log(e.staticType); // "set" (The original action)
420
425
  console.log(e.path); // "user.profile.name" (The actual property changed)
421
426
  console.log(e.currentTarget); // { path: "user.profile", value: {...} } (Where we are listening)
422
- console.log(e.value); // "Ada" (The new value)
427
+ console.log(e.value); // "Kosi" (The new value)
423
428
  console.log(e.oldValue); // "John" (The previous value)
424
429
  // 2. Political Routing
425
430
  console.log(e.eventPhase); // 3 (Bubbling Phase)
426
431
  console.log(e.bubbles); // true/false
427
432
  // 3. Misc
428
- console.log(e.composedPath()); // ["Ada", { name: "Ada", age: 26 }, { profile: { name: "Ada", age: 26 } }, { user: { profile: { name: "Ada", age: 26 } } }] (refs, target -> root)
433
+ console.log(e.composedPath()); // ["Kosi", { name: "Kosi", age: 26 }, { profile: { name: "Kosi", age: 26 } }, { user: { profile: { name: "Kosi", age: 26 } } }] (refs, target -> root)
429
434
  }); // you could use external callbacks but typed with `REvent<T, "user.age">`
430
435
  ```
431
436
 
@@ -454,9 +459,29 @@ When you listen to a parent object (like `"user.profile"`), you will naturally c
454
459
 
455
460
  To help you instantly differentiate between the object *itself* being replaced, versus a *child* property mutating deep inside of it, the Reactor intelligently morphs the `e.type`:
456
461
  * If `state.user.profile = {}` happens, the listener receives `e.type === "set"`.
457
- * If `state.user.profile.name = "Ada"` happens, the parent listener receives `e.type === "update"`.
462
+ * If `state.user.profile.name = "Kosi"` happens, the parent listener receives `e.type === "update"`.
458
463
 
459
- This allows for highly fine-grained syncing bridges across your application without writing heavy, manual for-loop diffing algorithms!
464
+ This allows for highly fine-grained syncing bridges across your application without writing heavy for-loop diffing algorithms! Use `{ depth: n }` to control how deep the path bubbles you see are, i.e.
465
+
466
+ ```javascript
467
+ rtr.on("todos", (e) => console.log(e), { depth : 1 }); // only sees updates on direct children
468
+ ```
469
+
470
+ Typing tip (for depth-aware `update` narrowing): `depth` mainly affects inferred `target.key` unions. To preserve type narrowing where desired, avoid destructuring in the callback signature. Types can be too accurate thereby causing issues, cast where necessary. e.g. `e.value as any`.
471
+
472
+ ```javascript
473
+ // Less reliable inference for depth-aware unions
474
+ rtr.on("todos", ({ type, target: { path, key } }) => {
475
+ if (type === "update") console.log(path, key);
476
+ }, { depth: 1 });
477
+ // Better: narrow first, then destructure inside
478
+ rtr.on("todos", (e: REvent<user, "todos", 1>) => {
479
+ if (e.type === "update") {
480
+ const { path, key } = e.target;
481
+ console.log(path, key); // or e.target.path, e.target.key
482
+ }
483
+ }, { depth: 1 }); // you need the generic for external callbacks only
484
+ ```
460
485
 
461
486
  ---
462
487
 
@@ -464,7 +489,7 @@ This allows for highly fine-grained syncing bridges across your application with
464
489
 
465
490
  ### The CSS Black Box
466
491
 
467
- Imagine you have 50 different CSS variables in your state (`settings.css.containerWidth`, `settings.css.themeColor`, etc.). Registering 50 individual `watch()` or `on()` listeners would need manual css crawling that will be blind dynamically added variables.
492
+ Imagine you have 50 different CSS variables in your state (`settings.css.containerWidth`, `settings.css.themeColor`, etc.). Registering 50 individual `watch()` or `on()` listeners would need manual css crawling that will be blind to dynamically added variables.
468
493
 
469
494
  Instead, we use the **Root Wildcard** (`"*"`) for both Reading (`get`) and Writing (`watch`).
470
495
 
@@ -486,8 +511,8 @@ this.ctlr.config.get("*", (val, { target: { key, path } }) => {
486
511
  });
487
512
  ```
488
513
  #### Why this pattern is elite:
489
- 1. **Synchronous Execution (`watch`):** CSSOM needs immediate updates. If you used an asynchronous `.on()` listener, the browser might paint the old frame before the microtask resolves, causing UI flicker. `.watch()` executes synchronously during the proxy trap.
490
- 2. **The Wildcard Tradeoff:** By listening to `*`, this callback runs synchronously on *every single mutation* in the entire reactor.
514
+ 1. **Synchronous Execution (`watch`):** CSSOM needs immediate updates. If you used an `.on()` listener, a slow browser might paint the old frame before the microtask resolves, causing UI flicker. `.watch()` executes synchronously during the proxy trap.
515
+ 2. **The Wildcard Tradeoff:** By listening to `*`, this callback runs synchronously on *every single mutation* in the entire reactor. This is the only synchronous way to catch deep nested updates.
491
516
  3. **The Ultimate Illusion:** A developer writes `console.log(state.settings.css.themeColor)`. To them, it looks like a standard plain object property access. In reality, the Reactor just executed a surgical DOM read. It is a true black box.
492
517
 
493
518
  ---
@@ -499,7 +524,6 @@ S.I.A. Reactor synthesizes core concepts from the heavyweights of web and media
499
524
  * **The Native JavaScript Proxy API:** Arguably the most powerful, slept-on feature in the ECMAScript specification. The Reactor is essentially a love letter to the Proxy API, packaging its raw, interception-level power into a structured and safe Data DOM so the community can finally use what it's truly capable of.
500
525
  * **Video.js (VJS):** The philosophy of "Intent vs. State" MEDIATION, ensuring UI actions only commit when the underlying engine allows it.
501
526
  * **The Browser DOM:** Treating a raw JSON state tree like HTML nodes, complete with deep, path-based event bubbling.
502
- * **The JavaScript Event Loop:** Utilizing `queueMicrotask` to batch thousands of synchronous state mutations into a single, noiseless render tick.
503
527
  * **Vue, MobX & Valtio:** Leveraging native ES6 Proxies for instant, deep reactivity without forcing clunky `get()` or `set()` wrapper functions.
504
528
 
505
529
  ---
@@ -1,5 +1,5 @@
1
- import { R as Reactive } from './index-DCG3sacH.cjs';
2
- import { T as TimeTravelPlugin } from './timeTravel-L8CEhHIo.cjs';
1
+ import { d as Reactive } from './index-BgbbNXTW.cjs';
2
+ import { m as TimeTravelModule } from './timeTravel-CraHdbXZ.cjs';
3
3
 
4
4
  /** Reactive options for the TimeTravel overlay instance. */
5
5
  interface TimeTravelConfig {
@@ -14,8 +14,9 @@ interface TimeTravelConfig {
14
14
  /** Container element that owns the overlay layer and dock. */
15
15
  container: HTMLElement;
16
16
  }
17
- /** Vanilla overlay controller for visual time-travel controls and timeline I/O.
18
- * Mounts a docked HUD into the configured container, syncs its UI with plugin state, and forwards keyboard/button actions to the TimeTravelPlugin.
17
+ /**
18
+ * - Vanilla overlay controller for visual time-travel controls and timeline I/O.
19
+ * - Mounts a docked HUD into the configured container, syncs its UI with module state, and forwards keyboard/button actions to the TimeTravelModule.
19
20
  * Supports reactive `config` updates (title/color/container/devOnly) and maintains local overlay UI state (`open` and `import` payload text).
20
21
  */
21
22
  declare class TimeTravelOverlay {
@@ -26,15 +27,15 @@ declare class TimeTravelOverlay {
26
27
  open: boolean;
27
28
  import: string;
28
29
  }, undefined>;
29
- readonly time: TimeTravelPlugin;
30
+ readonly time: TimeTravelModule;
30
31
  readonly els: Record<string, HTMLElement>;
31
32
  private clups;
32
33
  private keyup?;
33
- /** Creates a docked TimeTravel overlay bound to a plugin instance.
34
- * @param time TimeTravel plugin instance that owns timeline operations.
34
+ /** Creates a docked TimeTravel overlay bound to a module instance.
35
+ * @param time TimeTravel module instance that owns timeline operations.
35
36
  * @param build Optional initial overlay config overrides.
36
37
  */
37
- constructor(time: TimeTravelPlugin, build?: Partial<TimeTravelConfig>);
38
+ constructor(time: TimeTravelModule, build?: Partial<TimeTravelConfig>);
38
39
  destroy(): void;
39
40
  }
40
41
 
@@ -1,5 +1,5 @@
1
- import { R as Reactive } from './index-DCG3sacH.js';
2
- import { T as TimeTravelPlugin } from './timeTravel-Bv_u5M1D.js';
1
+ import { d as Reactive } from './index-BgbbNXTW.js';
2
+ import { m as TimeTravelModule } from './timeTravel-YUxRHRgh.js';
3
3
 
4
4
  /** Reactive options for the TimeTravel overlay instance. */
5
5
  interface TimeTravelConfig {
@@ -14,8 +14,9 @@ interface TimeTravelConfig {
14
14
  /** Container element that owns the overlay layer and dock. */
15
15
  container: HTMLElement;
16
16
  }
17
- /** Vanilla overlay controller for visual time-travel controls and timeline I/O.
18
- * Mounts a docked HUD into the configured container, syncs its UI with plugin state, and forwards keyboard/button actions to the TimeTravelPlugin.
17
+ /**
18
+ * - Vanilla overlay controller for visual time-travel controls and timeline I/O.
19
+ * - Mounts a docked HUD into the configured container, syncs its UI with module state, and forwards keyboard/button actions to the TimeTravelModule.
19
20
  * Supports reactive `config` updates (title/color/container/devOnly) and maintains local overlay UI state (`open` and `import` payload text).
20
21
  */
21
22
  declare class TimeTravelOverlay {
@@ -26,15 +27,15 @@ declare class TimeTravelOverlay {
26
27
  open: boolean;
27
28
  import: string;
28
29
  }, undefined>;
29
- readonly time: TimeTravelPlugin;
30
+ readonly time: TimeTravelModule;
30
31
  readonly els: Record<string, HTMLElement>;
31
32
  private clups;
32
33
  private keyup?;
33
- /** Creates a docked TimeTravel overlay bound to a plugin instance.
34
- * @param time TimeTravel plugin instance that owns timeline operations.
34
+ /** Creates a docked TimeTravel overlay bound to a module instance.
35
+ * @param time TimeTravel module instance that owns timeline operations.
35
36
  * @param build Optional initial overlay config overrides.
36
37
  */
37
- constructor(time: TimeTravelPlugin, build?: Partial<TimeTravelConfig>);
38
+ constructor(time: TimeTravelModule, build?: Partial<TimeTravelConfig>);
38
39
  destroy(): void;
39
40
  }
40
41