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.
- package/README.md +115 -89
- package/dist/{TimeTravelOverlay-DxqJL0Zk.d.ts → TimeTravelOverlay-Dglcwpg-.d.ts} +9 -8
- package/dist/{TimeTravelOverlay-CJv-S_Km.d.cts → TimeTravelOverlay-OjklzuCD.d.cts} +9 -8
- package/dist/adapters/react.cjs +74 -91
- package/dist/adapters/react.d.cts +23 -22
- package/dist/adapters/react.d.ts +23 -22
- package/dist/adapters/react.js +3 -3
- package/dist/adapters/vanilla.cjs +74 -91
- package/dist/adapters/vanilla.d.cts +4 -4
- package/dist/adapters/vanilla.d.ts +4 -4
- package/dist/adapters/vanilla.js +3 -3
- package/dist/{chunk-TFLYCXK4.js → chunk-5JNWC7Z4.js} +14 -13
- package/dist/{chunk-DP74DVRT.js → chunk-MKL3JUPO.js} +55 -15
- package/dist/{chunk-2WBPGSRL.js → chunk-MSTHQVNK.js} +61 -78
- package/dist/{index-Oie9hhE8.d.cts → index-m0aAWxhX.d.cts} +330 -218
- package/dist/{index-Oie9hhE8.d.ts → index-m0aAWxhX.d.ts} +330 -218
- package/dist/index.cjs +69 -89
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +2 -4
- package/dist/{plugins.cjs → modules.cjs} +464 -195
- package/dist/modules.d.cts +52 -0
- package/dist/modules.d.ts +52 -0
- package/dist/modules.js +619 -0
- package/dist/super.d.ts +642 -298
- package/dist/super.global.js +481 -210
- package/dist/timeTravel-DExvNb04.d.ts +352 -0
- package/dist/timeTravel-DctvcHVt.d.cts +352 -0
- package/dist/utils.cjs +59 -14
- package/dist/utils.d.cts +1 -1
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +7 -1
- package/package.json +6 -6
- package/dist/plugins.d.cts +0 -112
- package/dist/plugins.d.ts +0 -112
- package/dist/plugins.js +0 -370
- package/dist/timeTravel-B1vedDQc.d.ts +0 -76
- package/dist/timeTravel-WpgWmKu-.d.cts +0 -76
|
@@ -17,28 +17,34 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
17
17
|
};
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
|
|
20
|
-
// src/ts/
|
|
21
|
-
var
|
|
22
|
-
__export(
|
|
23
|
-
|
|
20
|
+
// src/ts/modules.ts
|
|
21
|
+
var modules_exports = {};
|
|
22
|
+
__export(modules_exports, {
|
|
23
|
+
AsyncStorageAdapter: () => AsyncStorageAdapter,
|
|
24
|
+
BaseReactorModule: () => BaseReactorModule,
|
|
24
25
|
BaseStorageAdapter: () => BaseStorageAdapter,
|
|
26
|
+
COOKIE_ADAPTER_BUILD: () => COOKIE_ADAPTER_BUILD,
|
|
27
|
+
CookieAdapter: () => CookieAdapter,
|
|
25
28
|
INDEXED_DB_ADAPTER_BUILD: () => INDEXED_DB_ADAPTER_BUILD,
|
|
26
29
|
IndexedDBAdapter: () => IndexedDBAdapter,
|
|
27
30
|
LocalStorageAdapter: () => LocalStorageAdapter,
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
+
MemoryAdapter: () => MemoryAdapter,
|
|
32
|
+
PERSIST_MODULE_BUILD: () => PERSIST_MODULE_BUILD,
|
|
33
|
+
PersistModule: () => PersistModule,
|
|
34
|
+
SessionStorageAdapter: () => SessionStorageAdapter,
|
|
31
35
|
StorageAdapter: () => StorageAdapter,
|
|
32
|
-
|
|
33
|
-
|
|
36
|
+
TIME_TRAVEL_MODULE_BUILD: () => TIME_TRAVEL_MODULE_BUILD,
|
|
37
|
+
TimeTravelModule: () => TimeTravelModule
|
|
34
38
|
});
|
|
35
|
-
module.exports = __toCommonJS(
|
|
39
|
+
module.exports = __toCommonJS(modules_exports);
|
|
36
40
|
|
|
37
41
|
// src/ts/core/consts.ts
|
|
38
42
|
var CTX = {
|
|
39
43
|
/** Flag indicating whether the application is running in development mode. */
|
|
40
44
|
isDevEnv: "undefined" !== typeof process ? process.env.NODE_ENV !== "production" : true,
|
|
41
|
-
/**
|
|
45
|
+
/** Flag indicating whether a cascade is currently ongoing so reactors can allow all writes. */
|
|
46
|
+
isCascading: false,
|
|
47
|
+
/** Active `Autotracker` instance, override for automatic dependency collection on `Reactor` traps. */
|
|
42
48
|
autotracker: null
|
|
43
49
|
};
|
|
44
50
|
var RAW = /* @__PURE__ */ Symbol.for("S.I.A_RAW");
|
|
@@ -50,14 +56,13 @@ var VERSION = /* @__PURE__ */ Symbol.for("S.I.A_VERSION");
|
|
|
50
56
|
var SSVERSION = /* @__PURE__ */ Symbol.for("S.I.A_SNAPSHOT_VERSION");
|
|
51
57
|
var RTR_BATCH = "undefined" !== typeof window ? ("undefined" !== typeof queueMicrotask ? queueMicrotask : setTimeout).bind(window) : "undefined" !== typeof process && process.nextTick ? process.nextTick : setTimeout;
|
|
52
58
|
var RTR_LOG = console.log.bind(console, "[S.I.A Reactor]");
|
|
53
|
-
var EVT_WARN = console.warn.bind(console, "[S.I.A Event]");
|
|
54
59
|
var EVT_OPTS = { LISTENER: ["capture", "depth", "once", "signal", "immediate"], MEDIATOR: ["lazy", "signal", "immediate"] };
|
|
55
60
|
var NIL = Object.freeze({});
|
|
56
61
|
var NOOP = () => {
|
|
57
62
|
};
|
|
58
63
|
|
|
59
64
|
// src/ts/utils/obj.ts
|
|
60
|
-
var
|
|
65
|
+
var arrRegex = /^([^\[\]]+)\[(\d+)\]$/;
|
|
61
66
|
function isObj(obj, arraycheck = true) {
|
|
62
67
|
return "object" === typeof obj && obj !== null && (arraycheck ? !Array.isArray(obj) : true);
|
|
63
68
|
}
|
|
@@ -65,7 +70,7 @@ function isPOJO(obj, config = NIL, typecheck = true) {
|
|
|
65
70
|
return (typecheck ? isObj(obj, false) : true) && (config.crossRealms ? Object.prototype.toString.call(obj) === "[object Object]" : obj.constructor === Object);
|
|
66
71
|
}
|
|
67
72
|
function canHandle(obj, config = NIL, typecheck = true) {
|
|
68
|
-
if (typecheck && !isObj(obj, false)) return false;
|
|
73
|
+
if (typecheck && !isObj(obj, false) || obj[INERTIA]) return false;
|
|
69
74
|
if (Array.isArray(obj) || !config.preserveContext && isPOJO(obj, config, false)) return true;
|
|
70
75
|
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);
|
|
71
76
|
return false;
|
|
@@ -76,7 +81,7 @@ function getAny(source, key, separator = ".", keyFunc) {
|
|
|
76
81
|
const keys = key.split(separator);
|
|
77
82
|
let currObj = source;
|
|
78
83
|
for (let i = 0, len = keys.length; i < len; i++) {
|
|
79
|
-
const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(
|
|
84
|
+
const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRegex);
|
|
80
85
|
if (match) {
|
|
81
86
|
const [, key3, iStr] = match;
|
|
82
87
|
if (!Array.isArray(currObj[key3]) || !(key3 in currObj)) return void 0;
|
|
@@ -93,7 +98,7 @@ function setAny(target, key, value, separator = ".", keyFunc) {
|
|
|
93
98
|
if (!key.includes(separator)) return void (target[keyFunc ? keyFunc(key) : key] = value);
|
|
94
99
|
const keys = key.split(separator);
|
|
95
100
|
for (let currObj = target, i = 0, len = keys.length; i < len; i++) {
|
|
96
|
-
const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(
|
|
101
|
+
const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRegex);
|
|
97
102
|
if (match) {
|
|
98
103
|
const [, key3, iStr] = match;
|
|
99
104
|
if (!Array.isArray(currObj[key3])) currObj[key3] = [];
|
|
@@ -114,7 +119,7 @@ function deleteAny(target, key, separator = ".", keyFunc) {
|
|
|
114
119
|
if (!key.includes(separator)) return void delete target[keyFunc ? keyFunc(key) : key];
|
|
115
120
|
const keys = key.split(separator);
|
|
116
121
|
for (let currObj = target, i = 0, len = keys.length; i < len; i++) {
|
|
117
|
-
const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(
|
|
122
|
+
const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRegex);
|
|
118
123
|
if (match) {
|
|
119
124
|
const [, key3, iStr] = match;
|
|
120
125
|
if (!Array.isArray(currObj[key3]) || !(key3 in currObj)) return;
|
|
@@ -132,7 +137,7 @@ function inAny(source, key, separator = ".", keyFunc) {
|
|
|
132
137
|
if (!key.includes(separator)) return key in source;
|
|
133
138
|
const keys = key.split(separator);
|
|
134
139
|
for (let currObj = source, i = 0, len = keys.length; i < len; i++) {
|
|
135
|
-
const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(
|
|
140
|
+
const key2 = keyFunc ? keyFunc(keys[i]) : keys[i], match = key2.includes("[") && key2.match(arrRegex);
|
|
136
141
|
if (match) {
|
|
137
142
|
const [, key3, iStr] = match;
|
|
138
143
|
if (!Array.isArray(currObj[key3]) || !(key3 in currObj)) return false;
|
|
@@ -149,9 +154,38 @@ function inAny(source, key, separator = ".", keyFunc) {
|
|
|
149
154
|
function parseEvtOpts(options, opts, boolOpt = opts[0], result = {}) {
|
|
150
155
|
return Object.assign(result, "boolean" === typeof options ? { [boolOpt]: options } : options), result;
|
|
151
156
|
}
|
|
152
|
-
function
|
|
153
|
-
const
|
|
154
|
-
|
|
157
|
+
function fanout(a, b, c, d) {
|
|
158
|
+
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, getAny(a, b), c, d || NIL, void 0] : [void 0, void 0, a, b, c || NIL, void 0], target = isEvPd ? getAny(a.root, a.currentTarget.path) : isPath ? getAny(state, path) : olds;
|
|
159
|
+
if (isEvPd && type !== "set" && type !== "delete" || !target || !canHandle(news, opts)) return;
|
|
160
|
+
const prev = CTX.isCascading;
|
|
161
|
+
CTX.isCascading = isEvPd;
|
|
162
|
+
try {
|
|
163
|
+
const walk = (target2, obj, depth = isEvPd ? 1 : Infinity, keys = Object.keys(obj)) => {
|
|
164
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
165
|
+
const val = obj[keys[i]];
|
|
166
|
+
try {
|
|
167
|
+
if ((opts.atomic ?? true) && Array.isArray(val)) target2[keys[i]] = val, target2[keys[i]].length = target2[keys[i]].length;
|
|
168
|
+
else depth > 1 && canHandle(val, opts) ? walk(target2[keys[i]] ||= {}, val, depth - 1) : target2[keys[i]] = val;
|
|
169
|
+
} catch (e) {
|
|
170
|
+
if (e instanceof RangeError) throw e;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
if ((opts.atomic ?? true) && Array.isArray(news) && isPath) setAny(state, path, news), getAny(state, path).length = news.length;
|
|
175
|
+
else walk(target, opts.merge ? mergeObjs(olds, news, opts) : news, opts.depth === true ? Infinity : opts.depth);
|
|
176
|
+
} finally {
|
|
177
|
+
CTX.isCascading = prev;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
var fanoutOptsArr = ["merge", "depth", "atomic"];
|
|
181
|
+
function mergeObjs(o1, o2, config, pojocheck = true) {
|
|
182
|
+
if (pojocheck && (!isPOJO(o1 || NIL, config) || !isPOJO(o2 || NIL, config))) return o2;
|
|
183
|
+
const merged = { ...o1 ||= {}, ...o2 ||= {} }, keys = Object.keys(merged);
|
|
184
|
+
for (let i = 0, len = keys.length; i < len; i++) {
|
|
185
|
+
const o1C = o1[keys[i]], o2C = o2[keys[i]];
|
|
186
|
+
if (isPOJO(o1C, config) && isPOJO(o2C, config)) merged[keys[i]] = mergeObjs(o1C, o2C, config, false);
|
|
187
|
+
}
|
|
188
|
+
return merged;
|
|
155
189
|
}
|
|
156
190
|
function getTrailRecords(obj, path, reverse = false) {
|
|
157
191
|
const parts = path.split("."), chain = [["*", obj, obj]];
|
|
@@ -166,7 +200,12 @@ function deepClone(obj, config = NIL, seen = /* @__PURE__ */ new WeakMap()) {
|
|
|
166
200
|
const clone = config.preserveContext ? Object.create(Object.getPrototypeOf(obj)) : Array.isArray(obj) ? [] : {};
|
|
167
201
|
seen.set(obj, clone);
|
|
168
202
|
const keys = config.preserveContext ? Reflect.ownKeys(obj) : Object.keys(obj);
|
|
169
|
-
for (let i = 0, len = keys.length; i < len; i++)
|
|
203
|
+
for (let i = 0, len = keys.length; i < len; i++)
|
|
204
|
+
try {
|
|
205
|
+
clone[keys[i]] = deepClone(obj[keys[i]], config, seen);
|
|
206
|
+
} catch (e) {
|
|
207
|
+
if (e instanceof RangeError) throw e;
|
|
208
|
+
}
|
|
170
209
|
return clone;
|
|
171
210
|
}
|
|
172
211
|
function nuke(target) {
|
|
@@ -206,35 +245,34 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
206
245
|
staticType;
|
|
207
246
|
/** Original event target context. */
|
|
208
247
|
target;
|
|
209
|
-
/** Root reactive object for this event wave. */
|
|
248
|
+
/** Root reactive object for this event instance wave. */
|
|
210
249
|
root;
|
|
211
|
-
/** Original target path for this event wave. */
|
|
250
|
+
/** Original target path for this event instance wave. */
|
|
212
251
|
path;
|
|
213
252
|
/** Current value at the event target path. */
|
|
214
253
|
value;
|
|
215
254
|
/** Previous value at the event target path. */
|
|
216
255
|
oldValue;
|
|
217
|
-
/** Whether resolve/reject intent semantics are allowed for this event. */
|
|
256
|
+
/** Whether resolve/reject intent semantics are allowed for this event instance. */
|
|
218
257
|
rejectable;
|
|
219
|
-
/** Whether this event wave can bubble back up to ancestors or just capture down. */
|
|
258
|
+
/** Whether this event instance wave can bubble back up to ancestors or just capture down. */
|
|
220
259
|
bubbles;
|
|
221
260
|
/**
|
|
222
|
-
* `DOMHighResTimeStamp` for this event payload for native event parity and accuracy.
|
|
261
|
+
* `DOMHighResTimeStamp` for this event instance payload for native event parity and accuracy.
|
|
223
262
|
* Enable `eventTimeStamps` option, then use this over custom timestamps in listeners for accuracy.
|
|
224
263
|
* */
|
|
225
264
|
timestamp;
|
|
226
|
-
|
|
265
|
+
/** The `Reactor` instance that dispatched this event instance. */
|
|
266
|
+
reactor;
|
|
227
267
|
_resolved = "";
|
|
228
268
|
_rejected = "";
|
|
229
269
|
_propagationStopped = false;
|
|
230
270
|
_immediatePropagationStopped = false;
|
|
231
271
|
/**
|
|
232
272
|
* @param payload Source payload for this event instance.
|
|
233
|
-
* @param
|
|
234
|
-
* @param canWarn Whether warning output is enabled.
|
|
235
|
-
* @param canStamp Whether timestamping is enabled.
|
|
273
|
+
* @param reactor The `Reactor` instance creating this event instance.
|
|
236
274
|
*/
|
|
237
|
-
constructor(payload,
|
|
275
|
+
constructor(payload, reactor) {
|
|
238
276
|
this.staticType = this.type = payload.type;
|
|
239
277
|
this.target = payload.target;
|
|
240
278
|
this.currentTarget = payload.currentTarget;
|
|
@@ -243,9 +281,9 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
243
281
|
this.value = payload.target.value;
|
|
244
282
|
this.oldValue = payload.target.oldValue;
|
|
245
283
|
this.rejectable = payload.rejectable;
|
|
246
|
-
this.bubbles =
|
|
247
|
-
if (
|
|
248
|
-
|
|
284
|
+
this.bubbles = !!reactor.config.eventBubbling;
|
|
285
|
+
if (reactor.config.eventTimeStamps) this.timestamp = performance.now();
|
|
286
|
+
this.reactor = reactor;
|
|
249
287
|
}
|
|
250
288
|
/** Whether propagation has been stopped. */
|
|
251
289
|
get propagationStopped() {
|
|
@@ -275,9 +313,9 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
275
313
|
* @example e.resolve("API Load successful"); // message
|
|
276
314
|
*/
|
|
277
315
|
resolve(message) {
|
|
278
|
-
if (!this.rejectable) return this.
|
|
279
|
-
if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this.
|
|
280
|
-
if (this.rejectable) this._resolved = message || `Could ${this.staticType} intended value at "${this.path}"
|
|
316
|
+
if (!this.rejectable) return this.reactor.log(`[ReactorEvent] Ignored \`resolve()\` call on a non-rejectable ${this.staticType} at "${this.path}"`);
|
|
317
|
+
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.`);
|
|
318
|
+
if (this.rejectable) this.reactor.log(`[ReactorEvent] ${this._resolved = message || `Could ${this.staticType} intended value at "${this.path}"`}`);
|
|
281
319
|
}
|
|
282
320
|
/** Rejection reason for rejectable events. */
|
|
283
321
|
get rejected() {
|
|
@@ -290,9 +328,9 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
290
328
|
* @example e.resolve("User is not logged in"); // reason
|
|
291
329
|
*/
|
|
292
330
|
reject(reason) {
|
|
293
|
-
if (!this.rejectable) return this.
|
|
294
|
-
if (this.eventPhase !== _ReactorEvent.CAPTURING_PHASE) this.
|
|
295
|
-
if (this.rejectable) this._rejected = reason || `Couldn't ${this.staticType} intended value at "${this.path}"
|
|
331
|
+
if (!this.rejectable) return this.reactor.log(`[ReactorEvent] Ignored \`reject()\` call on a non-rejectable ${this.staticType} at "${this.path}"`);
|
|
332
|
+
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.`);
|
|
333
|
+
if (this.rejectable) this.reactor.log(`[ReactorEvent] ${this._rejected = reason || `Couldn't ${this.staticType} intended value at "${this.path}"`}`);
|
|
296
334
|
}
|
|
297
335
|
/**
|
|
298
336
|
* Returns event path values from target to root.
|
|
@@ -301,24 +339,22 @@ var ReactorEvent = class _ReactorEvent {
|
|
|
301
339
|
composedPath() {
|
|
302
340
|
return getTrailRecords(this.root, this.path, true).map((r) => r[2]);
|
|
303
341
|
}
|
|
304
|
-
get canWarn() {
|
|
305
|
-
return this._warn !== NOOP;
|
|
306
|
-
}
|
|
307
342
|
};
|
|
308
343
|
|
|
309
344
|
// src/ts/core/reactor.ts
|
|
310
345
|
var Reactor = class {
|
|
346
|
+
/** Logger function for this reactor instance, override if desired, `this.canLog = false` resets. */
|
|
311
347
|
log = NOOP;
|
|
348
|
+
/** The core state object for this reactor instance. */
|
|
312
349
|
core;
|
|
313
350
|
// `?:`s | pay the ~800 byte price upfront for what u might never use
|
|
314
|
-
|
|
351
|
+
/** The modules being used by this reactor. */
|
|
352
|
+
modules;
|
|
353
|
+
/** Configuration options for this reactor instance. */
|
|
315
354
|
config;
|
|
355
|
+
/** Whether this reactor instance is currently batching updates, a window view into the engine timing */
|
|
316
356
|
isBatching = false;
|
|
317
357
|
// Async Batching
|
|
318
|
-
isCascading = false;
|
|
319
|
-
// Setter Cascading
|
|
320
|
-
isLogging = false;
|
|
321
|
-
// keeping track so API getter doesn't slow down internal iterations in any way
|
|
322
358
|
queue;
|
|
323
359
|
// Tasks to run after flush
|
|
324
360
|
batch;
|
|
@@ -351,7 +387,7 @@ var Reactor = class {
|
|
|
351
387
|
if (this.config.referenceTracking && parent && key && !this.link(target, parent, key, false)) return target;
|
|
352
388
|
const cached = this.proxyCache.get(target);
|
|
353
389
|
if (cached) return cached;
|
|
354
|
-
if (
|
|
390
|
+
if (!canHandle(target, this.config, false)) return target;
|
|
355
391
|
rejectable ||= target[REJECTABLE];
|
|
356
392
|
indiffable ||= target[INDIFFABLE];
|
|
357
393
|
const proxy = new Proxy(target, {
|
|
@@ -385,7 +421,7 @@ var Reactor = class {
|
|
|
385
421
|
safeValue = value?.[RAW] || value;
|
|
386
422
|
unchanged = this.config.equalityFunction(safeValue, safeOldValue);
|
|
387
423
|
}
|
|
388
|
-
if (!indiffable && unchanged && !
|
|
424
|
+
if (!indiffable && unchanged && !CTX.isCascading) return this.log(`\u{1F504} [Reactor \`set\` Trap] Unchanged for "${keyStr}" on "${paths}"`), true;
|
|
389
425
|
if (this.config.set) terminated = (value = this.config.set(object, key2, value, oldValue, receiver, paths)) === TERMINATOR;
|
|
390
426
|
if (this.setters) {
|
|
391
427
|
const wildcords = this.setters.get("*");
|
|
@@ -539,7 +575,7 @@ var Reactor = class {
|
|
|
539
575
|
if (this.queue?.size) for (const task of this.queue) task(), this.queue.delete(task);
|
|
540
576
|
}
|
|
541
577
|
wave(path, payload) {
|
|
542
|
-
const e = new ReactorEvent(payload, this
|
|
578
|
+
const e = new ReactorEvent(payload, this), chain = getTrailRecords(this.core, path);
|
|
543
579
|
e.eventPhase = ReactorEvent.CAPTURING_PHASE;
|
|
544
580
|
for (let i = 0; i <= chain.length - 2; i++) {
|
|
545
581
|
if (e.propagationStopped) break;
|
|
@@ -613,8 +649,8 @@ var Reactor = class {
|
|
|
613
649
|
return depth;
|
|
614
650
|
}
|
|
615
651
|
getContext(path) {
|
|
616
|
-
const
|
|
617
|
-
return { path, value, key: path.slice(
|
|
652
|
+
const last = path.lastIndexOf("."), value = getAny(this.core, path), object = last === -1 ? this.core : getAny(this.core, path.slice(0, last));
|
|
653
|
+
return { path, value, key: path.slice(last + 1) || "", hadKey: true, object };
|
|
618
654
|
}
|
|
619
655
|
bindSignal(cord, sig) {
|
|
620
656
|
if (sig) sig.aborted ? cord.clup() : sig.addEventListener("abort", cord.clup, { once: true });
|
|
@@ -630,7 +666,12 @@ var Reactor = class {
|
|
|
630
666
|
const clone = !raw ? this.config.preserveContext ? Object.create(Object.getPrototypeOf(obj)) : Array.isArray(obj) ? [] : {} : obj;
|
|
631
667
|
seen.set(obj, clone);
|
|
632
668
|
const keys = this.config.preserveContext ? Reflect.ownKeys(obj) : Object.keys(obj);
|
|
633
|
-
for (let i = 0, len = keys.length; i < len; i++)
|
|
669
|
+
for (let i = 0, len = keys.length; i < len; i++)
|
|
670
|
+
try {
|
|
671
|
+
clone[keys[i]] = this.cloned(obj[keys[i]], raw, seen);
|
|
672
|
+
} catch (e) {
|
|
673
|
+
if (e instanceof RangeError) throw e;
|
|
674
|
+
}
|
|
634
675
|
if (!raw && this.config.smartCloning) this.snapCache.set(obj, clone), obj[SSVERSION] = version;
|
|
635
676
|
return clone;
|
|
636
677
|
}
|
|
@@ -718,7 +759,7 @@ var Reactor = class {
|
|
|
718
759
|
* rtr.delete("cache.temp", () => TERMINATOR);
|
|
719
760
|
*/
|
|
720
761
|
delete(path, callback, options) {
|
|
721
|
-
return this.syncAdd("delete", path, callback, options, (imm) => (imm !== "auto" || inAny(this.core, path)) && deleteAny(this.core, path
|
|
762
|
+
return this.syncAdd("delete", path, callback, options, (imm) => (imm !== "auto" || inAny(this.core, path)) && deleteAny(this.core, path));
|
|
722
763
|
}
|
|
723
764
|
/** Registers a delete mediator for a path that only triggers once. */
|
|
724
765
|
donce(path, callback, options) {
|
|
@@ -735,7 +776,7 @@ var Reactor = class {
|
|
|
735
776
|
}
|
|
736
777
|
/**
|
|
737
778
|
* Registers a watcher for a path.
|
|
738
|
-
* Watch callbacks run synchronously with the operation.
|
|
779
|
+
* Watch callbacks run synchronously with the operation, use leaf paths for reliability as it sees exact sets; no bubbling here.
|
|
739
780
|
* @param path Path or wildcard path.
|
|
740
781
|
* @param callback Watch callback.
|
|
741
782
|
* @param options Sync options.
|
|
@@ -784,7 +825,7 @@ var Reactor = class {
|
|
|
784
825
|
cord = { cb: callback, capture, depth, once, clup: () => this.off(path, callback, options), lDepth: depth !== void 0 ? this.getDepth(path) : depth };
|
|
785
826
|
if (immediate && (immediate !== "auto" || inAny(this.core, path))) {
|
|
786
827
|
const target = this.getContext(path);
|
|
787
|
-
callback(new ReactorEvent({ type: "init", target, currentTarget: target, root: this.core, rejectable: false }, this
|
|
828
|
+
callback(new ReactorEvent({ type: "init", target, currentTarget: target, root: this.core, rejectable: false }, this));
|
|
788
829
|
}
|
|
789
830
|
(cords ?? (this.listeners.set(path, cords = []), cords)).push(cord);
|
|
790
831
|
return this.bindSignal(cord, signal);
|
|
@@ -815,56 +856,39 @@ var Reactor = class {
|
|
|
815
856
|
return this.cloned(arguments.length < 2 ? this.core : branch, raw);
|
|
816
857
|
}
|
|
817
858
|
/**
|
|
818
|
-
*
|
|
819
|
-
* @param
|
|
820
|
-
* @param
|
|
821
|
-
* @
|
|
822
|
-
* rtr.on("user", (event) => rtr.cascade(event));
|
|
823
|
-
* @example
|
|
824
|
-
* rtr.watch("user", (_value, payload) => rtr.cascade(payload));
|
|
825
|
-
*/
|
|
826
|
-
cascade({ type, currentTarget: { path, value: news, oldValue: olds } }, objectSafe = true) {
|
|
827
|
-
if (type !== "set" && type !== "delete" || !canHandle(news, this.config) || (objectSafe ? !canHandle(olds, this.config) : false)) return;
|
|
828
|
-
const obj = objectSafe ? mergeObjs(olds, news) : news, keys = Object.keys(obj);
|
|
829
|
-
this.isCascading = true;
|
|
830
|
-
for (let i = 0, len = keys.length; i < len; i++) setAny(this.core, path === "*" ? keys[i] : path + "." + keys[i], obj[keys[i]]);
|
|
831
|
-
this.isCascading = false;
|
|
832
|
-
}
|
|
833
|
-
/**
|
|
834
|
-
* Installs a plugin instance.
|
|
835
|
-
* @param plugin Plugin instance.
|
|
836
|
-
* @returns Current reactor for fluent chaining.
|
|
859
|
+
* Installs a module instance.
|
|
860
|
+
* @param target Module instance.
|
|
861
|
+
* @param id Optional identification tag for this instance in the module.
|
|
862
|
+
* @returns Current `Reactor` instance for fluent chaining.
|
|
837
863
|
*/
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
this.plugins?.get(name)?.destroy();
|
|
841
|
-
return (this.plugins ??= /* @__PURE__ */ new Map()).set(name, (plugin.setup(this), plugin)), this;
|
|
864
|
+
use(target, id) {
|
|
865
|
+
return (this.modules ??= /* @__PURE__ */ new Set()).add(target.setup(this, id)), this;
|
|
842
866
|
}
|
|
843
|
-
/** Resets
|
|
867
|
+
/** Resets this reactor instance to its initial state. */
|
|
844
868
|
reset() {
|
|
845
869
|
this.getters?.clear(), this.setters?.clear(), this.deleters?.clear(), this.watchers?.clear(), this.listeners?.clear();
|
|
846
870
|
this.batch?.clear(), this.queue?.clear(), this.isBatching = false;
|
|
847
871
|
}
|
|
848
872
|
destroy() {
|
|
849
|
-
if (this.
|
|
873
|
+
if (this.modules) for (const mdle of this.modules) mdle.destroy();
|
|
850
874
|
this.reset(), nuke(this);
|
|
851
875
|
}
|
|
852
876
|
get canLog() {
|
|
853
|
-
return this.
|
|
877
|
+
return this.log !== NOOP;
|
|
854
878
|
}
|
|
855
879
|
set canLog(value) {
|
|
856
|
-
this.log =
|
|
880
|
+
this.log = value ? RTR_LOG : NOOP;
|
|
857
881
|
}
|
|
858
|
-
get
|
|
859
|
-
return this.config.
|
|
882
|
+
get canLineageTrace() {
|
|
883
|
+
return this.config.lineageTracing && this.config.referenceTracking;
|
|
860
884
|
}
|
|
861
885
|
get canSmartClone() {
|
|
862
|
-
return this.config.
|
|
886
|
+
return this.config.smartCloning && this.config.referenceTracking;
|
|
863
887
|
}
|
|
864
888
|
};
|
|
865
889
|
|
|
866
890
|
// src/ts/core/mixins.ts
|
|
867
|
-
var methods = ["tick", "stall", "nostall", "get", "gonce", "noget", "set", "sonce", "noset", "delete", "donce", "nodelete", "watch", "wonce", "nowatch", "on", "once", "off", "snapshot", "
|
|
891
|
+
var methods = ["tick", "stall", "nostall", "get", "gonce", "noget", "set", "sonce", "noset", "delete", "donce", "nodelete", "watch", "wonce", "nowatch", "on", "once", "off", "snapshot", "use", "reset", "destroy"];
|
|
868
892
|
function reactive(target, build, preferences = NIL) {
|
|
869
893
|
if ("__Reactor__" in target) return target;
|
|
870
894
|
const descriptors = {}, rtr = getReactor(target, true, build), locks = { enumerable: false, configurable: true, writable: false }, hasAffix = !!(preferences.prefix || preferences.suffix);
|
|
@@ -872,7 +896,7 @@ function reactive(target, build, preferences = NIL) {
|
|
|
872
896
|
let key = methods[i];
|
|
873
897
|
if (hasAffix) (preferences.whitelist?.includes(key) ?? true) && (key = `${preferences.prefix || ""}${key}${preferences.suffix || ""}`);
|
|
874
898
|
else if (preferences.whitelist?.includes(key)) continue;
|
|
875
|
-
descriptors[key] = { value: rtr[
|
|
899
|
+
descriptors[key] = { value: rtr[methods[i]].bind(rtr), ...locks };
|
|
876
900
|
}
|
|
877
901
|
descriptors["__Reactor__"] = { value: rtr, ...locks };
|
|
878
902
|
return Object.defineProperties(rtr.core, descriptors), rtr.core;
|
|
@@ -909,47 +933,75 @@ function guardMethod(fn, onError = (e) => console.error(e)) {
|
|
|
909
933
|
});
|
|
910
934
|
}
|
|
911
935
|
|
|
912
|
-
// src/ts/
|
|
913
|
-
var
|
|
914
|
-
|
|
936
|
+
// src/ts/modules/base.ts
|
|
937
|
+
var wpArr = ["*"];
|
|
938
|
+
var BaseReactorModule = class {
|
|
939
|
+
static moduleName;
|
|
915
940
|
get name() {
|
|
916
|
-
return this.constructor.
|
|
941
|
+
return this.constructor.moduleName;
|
|
917
942
|
}
|
|
918
943
|
ac = new AbortController();
|
|
919
944
|
signal = this.ac.signal;
|
|
920
|
-
|
|
945
|
+
rtrs = /* @__PURE__ */ new Map();
|
|
946
|
+
rids = /* @__PURE__ */ new WeakMap();
|
|
947
|
+
// for quick 0(1) lookups over iteration
|
|
948
|
+
wired = false;
|
|
921
949
|
config;
|
|
922
950
|
state;
|
|
923
951
|
constructor(config, rtr, state) {
|
|
924
952
|
guardAllMethods(this, this.guard);
|
|
925
|
-
this.rtr = rtr;
|
|
926
953
|
this.config = isObj(config) ? reactive(config) : config;
|
|
927
954
|
this.state = isObj(state) ? reactive(state) : state;
|
|
955
|
+
rtr && this.attach(rtr);
|
|
928
956
|
}
|
|
929
|
-
/**
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
957
|
+
/**
|
|
958
|
+
* Connect to a `Reactor` instance, allows managing multiple reactors if needed.
|
|
959
|
+
* @param target `Reactor` instance or `reactive()` object to connect to.
|
|
960
|
+
* @param id Optional custom id for the reactor, prefer over default implicit index id when managing multiple reactors, supports paths to merge into a single tree.
|
|
961
|
+
* @returns Current `ReactorModule` instance for fluent chaining.
|
|
962
|
+
* @example
|
|
963
|
+
* const mod = new MyModule().attach(state1).attach(state2); // implicit index-based ids by default, add a .setup() or `Reactor.use()` when ready for init.
|
|
964
|
+
* @example
|
|
965
|
+
* const persist = new PersistModule(config).attach(sessState, "session").attach(adminState, "session.admin"); // don't use "*", causes de-serialization issues.
|
|
966
|
+
*/
|
|
967
|
+
attach(target, id = this.rtrs.size) {
|
|
968
|
+
const rtr = getReactor(target);
|
|
969
|
+
if (!rtr || this.rtrs.has(id)) return this;
|
|
970
|
+
return this.rids.set((this.rtrs.set(id, rtr), rtr), id), this.onAttach(rtr, id), this;
|
|
971
|
+
}
|
|
972
|
+
onAttach(_rtr, _rid) {
|
|
973
|
+
}
|
|
974
|
+
/**
|
|
975
|
+
* Entry point called to initialize module wiring, calls `.attach(target, id)` first, `Reactor.use()` calls this internally.
|
|
976
|
+
* Should run as last in `.attach()` chain or after all desired reactors if using multiple; so wiring is done safely after.
|
|
977
|
+
* @param target `Reactor` instance or `reactive()` object to connect to.
|
|
978
|
+
* @param id Optional id for the reactor, prefer over default implicit index id when managing multiple reactors.
|
|
979
|
+
* @returns Current `ReactorModule` instance for fluent chaining.
|
|
980
|
+
* @example
|
|
981
|
+
* const mod = new MyModule().attach(state1).setup(state2); // if using multiple, this should run last; with same params as `.attach()` for a shorter chain
|
|
982
|
+
*/
|
|
983
|
+
setup(target, id) {
|
|
984
|
+
return this.attach(target, id), !this.wired && (this.wire(), this.wired = true), this;
|
|
933
985
|
}
|
|
934
986
|
destroy() {
|
|
935
987
|
this.ac.abort();
|
|
936
988
|
this.onDestroy?.();
|
|
937
989
|
}
|
|
938
990
|
/**
|
|
939
|
-
* Wraps a function with
|
|
991
|
+
* Wraps a function with module-scoped error logging.
|
|
940
992
|
* Use this when creating functions dynamically (for example, before attaching an anonymous listener on the fly).
|
|
941
993
|
* @example
|
|
942
994
|
* window.addEventListener("resize", this.guard(() => this.syncLayout(true)), { signal: this.signal });
|
|
943
995
|
*/
|
|
944
996
|
guard = (fn) => {
|
|
945
|
-
return guardMethod(fn, (e) => this.
|
|
997
|
+
return guardMethod(fn, (e) => this.rtrs.values().next().value?.log(`[Reactor "${this.name}" Module] Error: ${e}`));
|
|
946
998
|
};
|
|
947
999
|
// `()=>{}`: needs to be bounded even before initialization
|
|
948
1000
|
};
|
|
949
1001
|
|
|
950
1002
|
// src/ts/utils/store.ts
|
|
951
1003
|
var BaseStorageAdapter = class {
|
|
952
|
-
|
|
1004
|
+
name = "StorageAdapter";
|
|
953
1005
|
config;
|
|
954
1006
|
warn = (act = "", mssg = "Support issue or Private Mode", key = "", store = "") => this.config.debug && console.warn(`[${this.constructor.name} \`${act}\`] Failed${key ? `for ${key}` : ""} ${store ? ` on "${store}"` : ""} ${this.config.dbName ? ` at ${this.config.dbName}` : ""} (${mssg})`);
|
|
955
1007
|
constructor(config) {
|
|
@@ -957,26 +1009,44 @@ var BaseStorageAdapter = class {
|
|
|
957
1009
|
}
|
|
958
1010
|
};
|
|
959
1011
|
var StorageAdapter = class extends BaseStorageAdapter {
|
|
1012
|
+
name = "SyncStorageAdapter";
|
|
960
1013
|
};
|
|
961
1014
|
var AsyncStorageAdapter = class extends BaseStorageAdapter {
|
|
1015
|
+
name = "AsyncStorageAdapter";
|
|
962
1016
|
};
|
|
963
1017
|
var LocalStorageAdapter = class extends StorageAdapter {
|
|
964
|
-
|
|
965
|
-
|
|
1018
|
+
name = "LocalStorage";
|
|
1019
|
+
/**
|
|
1020
|
+
* Reads and parses a value from localStorage.
|
|
1021
|
+
* @param key Storage key.
|
|
1022
|
+
* @returns Parsed value, or `undefined` when missing/unreadable.
|
|
1023
|
+
*/
|
|
1024
|
+
get(key, reviver = this.config.reviver) {
|
|
966
1025
|
try {
|
|
967
1026
|
const v = localStorage.getItem(key);
|
|
968
|
-
return v ? JSON.parse(v) : void 0;
|
|
1027
|
+
return v ? JSON.parse(v, reviver) : void 0;
|
|
969
1028
|
} catch {
|
|
970
1029
|
return void 0;
|
|
971
1030
|
}
|
|
972
1031
|
}
|
|
973
|
-
|
|
1032
|
+
/**
|
|
1033
|
+
* Serializes and writes a value to localStorage.
|
|
1034
|
+
* @param key Storage key.
|
|
1035
|
+
* @param value Value to serialize.
|
|
1036
|
+
* @returns `true` when write succeeds, else `false`.
|
|
1037
|
+
*/
|
|
1038
|
+
set(key, value, replacer = this.config.replacer) {
|
|
974
1039
|
try {
|
|
975
|
-
return localStorage.setItem(key, JSON.stringify(value)), true;
|
|
1040
|
+
return localStorage.setItem(key, JSON.stringify(value, replacer)), true;
|
|
976
1041
|
} catch (e) {
|
|
977
1042
|
return this.warn("setItem", void 0, key), false;
|
|
978
1043
|
}
|
|
979
1044
|
}
|
|
1045
|
+
/**
|
|
1046
|
+
* Removes a single key from localStorage.
|
|
1047
|
+
* @param key Storage key.
|
|
1048
|
+
* @returns `true` when removal succeeds, else `false`.
|
|
1049
|
+
*/
|
|
980
1050
|
remove(key) {
|
|
981
1051
|
try {
|
|
982
1052
|
return localStorage.removeItem(key), true;
|
|
@@ -984,6 +1054,10 @@ var LocalStorageAdapter = class extends StorageAdapter {
|
|
|
984
1054
|
return this.warn("removeItem", void 0, key), false;
|
|
985
1055
|
}
|
|
986
1056
|
}
|
|
1057
|
+
/**
|
|
1058
|
+
* Clears all localStorage entries for the current origin.
|
|
1059
|
+
* @returns `true` when clear succeeds, else `false`.
|
|
1060
|
+
*/
|
|
987
1061
|
clear() {
|
|
988
1062
|
try {
|
|
989
1063
|
return localStorage.clear(), true;
|
|
@@ -992,25 +1066,94 @@ var LocalStorageAdapter = class extends StorageAdapter {
|
|
|
992
1066
|
}
|
|
993
1067
|
}
|
|
994
1068
|
};
|
|
995
|
-
var
|
|
1069
|
+
var SessionStorageAdapter = class extends StorageAdapter {
|
|
1070
|
+
name = "SessionStorage";
|
|
1071
|
+
/**
|
|
1072
|
+
* Reads and parses a value from sessionStorage.
|
|
1073
|
+
* @param key Storage key.
|
|
1074
|
+
* @returns Parsed value, or `undefined` when missing/unreadable.
|
|
1075
|
+
*/
|
|
1076
|
+
get(key, reviver = this.config.reviver) {
|
|
1077
|
+
try {
|
|
1078
|
+
const v = sessionStorage.getItem(key);
|
|
1079
|
+
return v ? JSON.parse(v, reviver) : void 0;
|
|
1080
|
+
} catch {
|
|
1081
|
+
return void 0;
|
|
1082
|
+
}
|
|
1083
|
+
}
|
|
1084
|
+
/**
|
|
1085
|
+
* Serializes and writes a value to sessionStorage.
|
|
1086
|
+
* @param key Storage key.
|
|
1087
|
+
* @param value Value to serialize.
|
|
1088
|
+
* @returns `true` when write succeeds, else `false`.
|
|
1089
|
+
*/
|
|
1090
|
+
set(key, value, replacer = this.config.replacer) {
|
|
1091
|
+
try {
|
|
1092
|
+
return sessionStorage.setItem(key, JSON.stringify(value, replacer)), true;
|
|
1093
|
+
} catch (e) {
|
|
1094
|
+
return this.warn("setItem", void 0, key), false;
|
|
1095
|
+
}
|
|
1096
|
+
}
|
|
1097
|
+
/**
|
|
1098
|
+
* Removes a single key from sessionStorage.
|
|
1099
|
+
* @param key Storage key.
|
|
1100
|
+
* @returns `true` when removal succeeds, else `false`.
|
|
1101
|
+
*/
|
|
1102
|
+
remove(key) {
|
|
1103
|
+
try {
|
|
1104
|
+
return sessionStorage.removeItem(key), true;
|
|
1105
|
+
} catch (e) {
|
|
1106
|
+
return this.warn("removeItem", void 0, key), false;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
/**
|
|
1110
|
+
* Clears all sessionStorage entries for the current tab session.
|
|
1111
|
+
* @returns `true` when clear succeeds, else `false`.
|
|
1112
|
+
*/
|
|
1113
|
+
clear() {
|
|
1114
|
+
try {
|
|
1115
|
+
return sessionStorage.clear(), true;
|
|
1116
|
+
} catch (e) {
|
|
1117
|
+
return this.warn("clear", void 0), false;
|
|
1118
|
+
}
|
|
1119
|
+
}
|
|
1120
|
+
};
|
|
1121
|
+
var MemoryAdapter = class extends StorageAdapter {
|
|
1122
|
+
name = "Memory";
|
|
996
1123
|
constructor(build) {
|
|
997
1124
|
super({ store: /* @__PURE__ */ new Map(), ...build });
|
|
998
1125
|
}
|
|
999
|
-
|
|
1126
|
+
/**
|
|
1127
|
+
* Reads and parses a value from memory storage.
|
|
1128
|
+
* @param key Storage key.
|
|
1129
|
+
* @returns Parsed value, or `undefined` when missing/unreadable.
|
|
1130
|
+
*/
|
|
1131
|
+
get(key, reviver = this.config.reviver) {
|
|
1000
1132
|
try {
|
|
1001
1133
|
const v = this.config.store.get(key);
|
|
1002
|
-
return v ? JSON.parse(v) : void 0;
|
|
1134
|
+
return v ? JSON.parse(v, reviver) : void 0;
|
|
1003
1135
|
} catch {
|
|
1004
1136
|
return void 0;
|
|
1005
1137
|
}
|
|
1006
1138
|
}
|
|
1007
|
-
|
|
1139
|
+
/**
|
|
1140
|
+
* Serializes and writes a value to memory storage.
|
|
1141
|
+
* @param key Storage key.
|
|
1142
|
+
* @param value Value to serialize.
|
|
1143
|
+
* @returns `true` when write succeeds, else `false`.
|
|
1144
|
+
*/
|
|
1145
|
+
set(key, value, replacer = this.config.replacer) {
|
|
1008
1146
|
try {
|
|
1009
|
-
return this.config.store.set(key, JSON.stringify(value)), true;
|
|
1147
|
+
return this.config.store.set(key, JSON.stringify(value, replacer)), true;
|
|
1010
1148
|
} catch (e) {
|
|
1011
1149
|
return this.warn("set", void 0, key), false;
|
|
1012
1150
|
}
|
|
1013
1151
|
}
|
|
1152
|
+
/**
|
|
1153
|
+
* Removes a single key from memory storage.
|
|
1154
|
+
* @param key Storage key.
|
|
1155
|
+
* @returns `true` when removal succeeds, else `false`.
|
|
1156
|
+
*/
|
|
1014
1157
|
remove(key) {
|
|
1015
1158
|
try {
|
|
1016
1159
|
return this.config.store.delete(key), true;
|
|
@@ -1018,6 +1161,10 @@ var MemoryStorageAdapter = class extends StorageAdapter {
|
|
|
1018
1161
|
return this.warn("remove", void 0, key), false;
|
|
1019
1162
|
}
|
|
1020
1163
|
}
|
|
1164
|
+
/**
|
|
1165
|
+
* Clears all entries from memory storage.
|
|
1166
|
+
* @returns `true` when clear succeeds, else `false`.
|
|
1167
|
+
*/
|
|
1021
1168
|
clear() {
|
|
1022
1169
|
try {
|
|
1023
1170
|
return this.config.store.clear(), true;
|
|
@@ -1026,52 +1173,147 @@ var MemoryStorageAdapter = class extends StorageAdapter {
|
|
|
1026
1173
|
}
|
|
1027
1174
|
}
|
|
1028
1175
|
};
|
|
1176
|
+
var CookieAdapter = class extends StorageAdapter {
|
|
1177
|
+
name = "Cookie";
|
|
1178
|
+
deets = (opts = NIL, _d = opts.domain ?? this.config.domain, _m = opts.maxAge ?? this.config.maxAge, _e = opts.expires ?? this.config.expires) => `Path=${opts.path ?? this.config.path}; SameSite=${opts.sameSite ?? this.config.sameSite}${_d ? `; Domain=${_d}` : ""}${opts.secure ?? this.config.secure ? "; Secure" : ""}${_m !== void 0 ? `; Max-Age=${_m}` : ""}${_e !== void 0 ? `; Expires=${_e instanceof Date ? _e.toUTCString() : _e}` : ""}`;
|
|
1179
|
+
constructor(build) {
|
|
1180
|
+
super({ secure: "undefined" !== typeof window && location.protocol === "https:", ...COOKIE_ADAPTER_BUILD, ...build });
|
|
1181
|
+
}
|
|
1182
|
+
/**
|
|
1183
|
+
* Reads and parses a cookie visible to the current page scope.
|
|
1184
|
+
* @param key Cookie key.
|
|
1185
|
+
* @returns Parsed value, or `undefined` when missing/unreadable.
|
|
1186
|
+
*/
|
|
1187
|
+
get(key, reviver = this.config.reviver) {
|
|
1188
|
+
try {
|
|
1189
|
+
const k = encodeURIComponent(key) + "=";
|
|
1190
|
+
for (const pair of document.cookie ? document.cookie.split("; ") : []) {
|
|
1191
|
+
if (!pair.startsWith(k)) continue;
|
|
1192
|
+
return JSON.parse(decodeURIComponent(pair.slice(k.length)), reviver);
|
|
1193
|
+
}
|
|
1194
|
+
return void 0;
|
|
1195
|
+
} catch {
|
|
1196
|
+
return void 0;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Writes a cookie with optional per-call scope/lifetime overrides.
|
|
1201
|
+
* @param key Cookie key.
|
|
1202
|
+
* @param value Value to serialize.
|
|
1203
|
+
* @param opts Optional per-call cookie options.
|
|
1204
|
+
* @returns `true` when write succeeds, else `false`.
|
|
1205
|
+
*/
|
|
1206
|
+
set(key, value, opts, replacer = this.config.replacer) {
|
|
1207
|
+
try {
|
|
1208
|
+
return document.cookie = `${encodeURIComponent(key)}=${encodeURIComponent(JSON.stringify(value, replacer))}; ${this.deets(opts)}`, true;
|
|
1209
|
+
} catch {
|
|
1210
|
+
return this.warn("set", void 0, key), false;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
/**
|
|
1214
|
+
* Removes a cookie key using matching scope attributes.
|
|
1215
|
+
* @param key Cookie key.
|
|
1216
|
+
* @param opts Optional per-call scope overrides.
|
|
1217
|
+
* @returns `true` when removal succeeds, else `false`.
|
|
1218
|
+
*/
|
|
1219
|
+
remove(key, opts) {
|
|
1220
|
+
try {
|
|
1221
|
+
return document.cookie = `${encodeURIComponent(key)}=; ${this.deets({ ...opts, maxAge: 0, expires: /* @__PURE__ */ new Date(0) })}`, true;
|
|
1222
|
+
} catch {
|
|
1223
|
+
return this.warn("remove", void 0, key), false;
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Attempts to remove all visible cookie keys for the given scope.
|
|
1228
|
+
* @param opts Optional per-call scope overrides.
|
|
1229
|
+
* @returns `true` when clear succeeds, else `false`.
|
|
1230
|
+
*/
|
|
1231
|
+
clear(opts) {
|
|
1232
|
+
try {
|
|
1233
|
+
for (const pair of document.cookie ? document.cookie.split("; ") : []) {
|
|
1234
|
+
const idx = pair.indexOf("=");
|
|
1235
|
+
document.cookie = `${idx === -1 ? pair : pair.slice(0, idx)}=; ${this.deets({ ...opts, maxAge: 0, expires: /* @__PURE__ */ new Date(0) })}`;
|
|
1236
|
+
}
|
|
1237
|
+
return true;
|
|
1238
|
+
} catch {
|
|
1239
|
+
return this.warn("clear"), false;
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
};
|
|
1029
1243
|
var IndexedDBAdapter = class extends AsyncStorageAdapter {
|
|
1244
|
+
name = "IndexedDB";
|
|
1030
1245
|
db;
|
|
1031
|
-
warn = (act = "", mssg = "Support issue or Private Mode", store = "", key = "") => console.warn(`[IndexedDB \`${act}\`] Failed${store ? ` for ${key} on "${store}"` : ""} at ${this.config.dbName} (${mssg})`);
|
|
1032
1246
|
constructor(build) {
|
|
1033
1247
|
super({ ...INDEXED_DB_ADAPTER_BUILD, ...build });
|
|
1034
1248
|
}
|
|
1249
|
+
/**
|
|
1250
|
+
* Returns a connected IndexedDB instance, opening it when needed.
|
|
1251
|
+
* @returns Connected database handle.
|
|
1252
|
+
*/
|
|
1035
1253
|
async idb() {
|
|
1036
1254
|
const idb = this.config.onidb();
|
|
1037
1255
|
if (idb || this.db) return Promise.resolve(idb || this.db);
|
|
1038
1256
|
return new Promise((res, rej) => {
|
|
1039
1257
|
const req = indexedDB.open(this.config.dbName, this.config.version);
|
|
1040
1258
|
req.onupgradeneeded = (e) => (this.config.onupgradeneeded(req.result, e), this.config.stores.forEach((s) => !req.result.objectStoreNames.contains(s) && req.result.createObjectStore(s)));
|
|
1041
|
-
req.onsuccess = (e) => (this.config.onsuccess(req.result, e), req.result.onversionchange = (e2) => (this.warn("update", "Updated in another tab"),
|
|
1259
|
+
req.onsuccess = (e) => (this.config.onsuccess(req.result, e), req.result.onversionchange = (e2) => (this.config.onversionchange(req.result, e2), this.warn("update", "Updated in another tab"), req.result.close()), res(this.db = req.result));
|
|
1042
1260
|
req.onerror = (e) => (this.config.onerror(req.error, e), this.warn("open", "Something went wrong"), rej(req.error));
|
|
1043
1261
|
req.onblocked = (e) => (this.config.onblocked(e), this.warn("open", "Close other tabs for updates"));
|
|
1044
1262
|
});
|
|
1045
1263
|
}
|
|
1046
|
-
|
|
1264
|
+
/**
|
|
1265
|
+
* Reads a value by key from an object store.
|
|
1266
|
+
* @param key Record key.
|
|
1267
|
+
* @param store Optional object-store override.
|
|
1268
|
+
* @returns Stored value, or `undefined` when missing/unreadable.
|
|
1269
|
+
*/
|
|
1270
|
+
async get(key, store = this.config.stores[0], options = this.config) {
|
|
1047
1271
|
try {
|
|
1048
|
-
const req = (await this.idb()).transaction(store).objectStore(store).get(key);
|
|
1272
|
+
const req = (await this.idb()).transaction(store, "readonly", options).objectStore(store).get(key);
|
|
1049
1273
|
return new Promise((res) => req.onsuccess = () => res(req.result));
|
|
1050
1274
|
} catch {
|
|
1051
1275
|
return this.warn("get", void 0, store), void 0;
|
|
1052
1276
|
}
|
|
1053
1277
|
}
|
|
1054
|
-
|
|
1278
|
+
/**
|
|
1279
|
+
* Writes a value by key into an object store.
|
|
1280
|
+
* @param key Record key.
|
|
1281
|
+
* @param value Value to store.
|
|
1282
|
+
* @param store Optional object-store override.
|
|
1283
|
+
* @returns `true` when write succeeds, else `false`.
|
|
1284
|
+
*/
|
|
1285
|
+
async set(key, value, store = this.config.stores[0], options = this.config) {
|
|
1055
1286
|
try {
|
|
1056
|
-
const req = (await this.idb()).transaction(store, "readwrite").objectStore(store).put(value, key);
|
|
1287
|
+
const req = (await this.idb()).transaction(store, "readwrite", options).objectStore(store).put(value, key);
|
|
1057
1288
|
return new Promise((res) => req.onsuccess = () => res(true));
|
|
1058
1289
|
} catch (e) {
|
|
1059
1290
|
return this.warn("put", void 0, store), false;
|
|
1060
1291
|
}
|
|
1061
1292
|
}
|
|
1062
|
-
|
|
1293
|
+
/**
|
|
1294
|
+
* Deletes a value by key from an object store.
|
|
1295
|
+
* @param key Record key.
|
|
1296
|
+
* @param store Optional object-store override.
|
|
1297
|
+
* @returns `true` when delete succeeds, else `false`.
|
|
1298
|
+
*/
|
|
1299
|
+
async remove(key, store = this.config.stores[0], options = this.config) {
|
|
1063
1300
|
try {
|
|
1064
|
-
const req = (await this.idb()).transaction(store, "readwrite").objectStore(store).delete(key);
|
|
1301
|
+
const req = (await this.idb()).transaction(store, "readwrite", options).objectStore(store).delete(key);
|
|
1065
1302
|
return new Promise((res) => req.onsuccess = () => res(true));
|
|
1066
1303
|
} catch (e) {
|
|
1067
1304
|
return this.warn("delete", void 0, store), false;
|
|
1068
1305
|
}
|
|
1069
1306
|
}
|
|
1070
|
-
|
|
1307
|
+
/**
|
|
1308
|
+
* Clears one or more object stores.
|
|
1309
|
+
* @param stores Store name or list of store names to clear.
|
|
1310
|
+
* @returns `true` when all clears succeed, else `false`.
|
|
1311
|
+
*/
|
|
1312
|
+
async clear(stores = this.config.stores, options = this.config) {
|
|
1071
1313
|
let success = true;
|
|
1072
1314
|
for (const store of Array.isArray(stores) ? stores : [stores])
|
|
1073
1315
|
try {
|
|
1074
|
-
const req = (await this.idb()).transaction(store, "readwrite").objectStore(store).clear();
|
|
1316
|
+
const req = (await this.idb()).transaction(store, "readwrite", options).objectStore(store).clear();
|
|
1075
1317
|
await new Promise((res) => req.onsuccess = () => res(true));
|
|
1076
1318
|
} catch (e) {
|
|
1077
1319
|
this.warn("clear", void 0, store), success = false;
|
|
@@ -1079,6 +1321,7 @@ var IndexedDBAdapter = class extends AsyncStorageAdapter {
|
|
|
1079
1321
|
return success;
|
|
1080
1322
|
}
|
|
1081
1323
|
};
|
|
1324
|
+
var COOKIE_ADAPTER_BUILD = { path: "/", sameSite: "Lax", domain: void 0, debug: false };
|
|
1082
1325
|
var INDEXED_DB_ADAPTER_BUILD = { dbName: "REACTOR_IDB", stores: ["VAULT"], version: 1, onidb: NOOP, onupgradeneeded: NOOP, onversionchange: NOOP, onsuccess: NOOP, onerror: NOOP, onblocked: NOOP };
|
|
1083
1326
|
|
|
1084
1327
|
// src/ts/utils/fn.ts
|
|
@@ -1091,93 +1334,122 @@ function setTimeout2(handler, timeout, ...args) {
|
|
|
1091
1334
|
return sig.addEventListener("abort", kill, { once: true }), id;
|
|
1092
1335
|
}
|
|
1093
1336
|
|
|
1094
|
-
// src/ts/
|
|
1095
|
-
var
|
|
1096
|
-
static
|
|
1337
|
+
// src/ts/modules/persist.ts
|
|
1338
|
+
var PersistModule = class extends BaseReactorModule {
|
|
1339
|
+
static moduleName = "persist";
|
|
1097
1340
|
adapter;
|
|
1341
|
+
hydrateSeq = 0;
|
|
1098
1342
|
saveTimeoutId = 0;
|
|
1099
1343
|
get payload() {
|
|
1100
|
-
|
|
1101
|
-
|
|
1344
|
+
let res = this.rtrs.size > 1 ? {} : void 0;
|
|
1345
|
+
for (const [rid, rtr] of this.rtrs) {
|
|
1346
|
+
const snap = this.config.useSnapshot ? (this.config.useSnapshot === true && (rtr.config.referenceTracking = rtr.config.smartCloning = true), rtr.snapshot()) : rtr.core, val = this.config.paths ? this.config.paths.reduce((acc, p) => (setAny(acc, p, getAny(snap, p)), acc), {}) : snap;
|
|
1347
|
+
this.rtrs.size > 1 ? setAny(res, rid, val) : res = val;
|
|
1348
|
+
}
|
|
1349
|
+
return res;
|
|
1102
1350
|
}
|
|
1103
1351
|
constructor(config, rtr) {
|
|
1104
|
-
super(
|
|
1352
|
+
super(mergeObjs(PERSIST_MODULE_BUILD, config), rtr, { hydrated: false });
|
|
1105
1353
|
}
|
|
1106
1354
|
wire() {
|
|
1107
1355
|
"undefined" !== typeof window && window.addEventListener("pagehide", this.onDestroy, { signal: this.signal });
|
|
1108
1356
|
"undefined" !== typeof document && document.addEventListener("visibilitychange", () => document.visibilityState === "hidden" && this.onDestroy(), { signal: this.signal });
|
|
1109
|
-
this.config.on("adapter", this.
|
|
1110
|
-
this.config.on("disabled", this.
|
|
1111
|
-
this.config.on("paths", this.
|
|
1357
|
+
this.config.on("adapter", this.handleAdapter, { signal: this.signal, immediate: true });
|
|
1358
|
+
this.config.on("disabled", this.handleDisabled, { signal: this.signal, immediate: true });
|
|
1359
|
+
this.config.on("paths", this.handlePaths, { signal: this.signal, immediate: true });
|
|
1112
1360
|
}
|
|
1113
|
-
|
|
1361
|
+
onAttach(rtr) {
|
|
1362
|
+
for (const p of this.config.paths ?? wpArr) !this.config.disabled ? rtr.on(p, this.handleSave, { signal: this.signal, immediate: true }) : rtr.off(p, this.handleSave);
|
|
1363
|
+
}
|
|
1364
|
+
async handleAdapter({ value = LocalStorageAdapter }) {
|
|
1365
|
+
const seq = ++this.hydrateSeq;
|
|
1114
1366
|
if (this.adapter && value === this.adapter.constructor) return;
|
|
1367
|
+
this.state.hydrated = false;
|
|
1115
1368
|
this.adapter?.remove(this.config.key);
|
|
1116
|
-
this.adapter = "function" === typeof value ? new value({ debug: this.
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1369
|
+
this.adapter = "function" === typeof value ? new value({ debug: !!this.rtrs.values().next().value?.canLog }) : value;
|
|
1370
|
+
try {
|
|
1371
|
+
let saved = this.adapter.get(this.config.key);
|
|
1372
|
+
const isAsync = saved instanceof Promise, { depth, merge = true } = parseEvtOpts(this.config.fanout ?? isAsync, fanoutOptsArr, "depth");
|
|
1373
|
+
saved = !isAsync ? saved : await saved;
|
|
1374
|
+
if (seq !== this.hydrateSeq || !saved) return;
|
|
1375
|
+
for (const [rid, rtr] of this.rtrs) {
|
|
1376
|
+
const entry = this.rtrs.size > 1 ? getAny(saved, rid) : saved;
|
|
1377
|
+
if (!entry) continue;
|
|
1378
|
+
const set = (p, news, olds) => (depth ? fanout : setAny)(rtr.core, p, merge ? mergeObjs(news, olds) : olds, depth ? { depth, crossRealms: rtr.config.crossRealms } : void 0);
|
|
1379
|
+
for (const p of this.config.paths ?? wpArr) set(p, getAny(rtr.core, p), getAny(entry, p));
|
|
1380
|
+
}
|
|
1381
|
+
for (const rtr of this.rtrs.values()) rtr.tick(depth ? "*" : this.config.paths ?? "*");
|
|
1382
|
+
} finally {
|
|
1383
|
+
if (seq === this.hydrateSeq) this.state.hydrated = true;
|
|
1384
|
+
}
|
|
1385
|
+
}
|
|
1386
|
+
handleDisabled({ value }) {
|
|
1387
|
+
for (const rtr of this.rtrs.values()) this.onAttach(rtr);
|
|
1126
1388
|
value && this.adapter?.remove(this.config.key);
|
|
1127
1389
|
}
|
|
1128
|
-
|
|
1129
|
-
for (const
|
|
1130
|
-
|
|
1390
|
+
handlePaths({ value: paths = wpArr, oldValue: prevs = wpArr }) {
|
|
1391
|
+
for (const rtr of this.rtrs.values()) {
|
|
1392
|
+
for (const p of prevs) rtr.off(p, this.handleSave);
|
|
1393
|
+
for (const p of paths) rtr.off(p, this.handleSave), !this.config.disabled && rtr.on(p, this.handleSave, { signal: this.signal, immediate: true });
|
|
1394
|
+
}
|
|
1131
1395
|
}
|
|
1132
|
-
|
|
1396
|
+
handleSave(e) {
|
|
1397
|
+
if (!this.state.hydrated) return e.stopImmediatePropagation();
|
|
1133
1398
|
if (!this.saveTimeoutId) this.saveTimeoutId = setTimeout2(() => (this.adapter.set(this.config.key, this.payload), this.saveTimeoutId = 0), this.config.throttle, this.signal);
|
|
1134
1399
|
}
|
|
1135
|
-
/** Clears persisted payload for this
|
|
1400
|
+
/** Clears persisted payload for this module instance and drops any pending save. */
|
|
1136
1401
|
clear() {
|
|
1137
1402
|
clearTimeout(this.saveTimeoutId);
|
|
1138
|
-
this.saveTimeoutId = -1
|
|
1403
|
+
this.saveTimeoutId = -1;
|
|
1404
|
+
for (const rtr of this.rtrs.values()) rtr.stall(() => this.saveTimeoutId = 0);
|
|
1139
1405
|
this.adapter?.remove(this.config.key);
|
|
1140
1406
|
}
|
|
1141
1407
|
onDestroy() {
|
|
1142
|
-
!this.config.disabled && this.adapter?.set(this.config.key, this.payload);
|
|
1408
|
+
this.state.hydrated && !this.config.disabled && this.adapter?.set(this.config.key, this.payload);
|
|
1143
1409
|
}
|
|
1144
1410
|
};
|
|
1145
|
-
var
|
|
1411
|
+
var PERSIST_MODULE_BUILD = { disabled: false, key: "REACTOR_STORE", throttle: 2500, useSnapshot: false };
|
|
1146
1412
|
|
|
1147
1413
|
// src/ts/utils/num.ts
|
|
1148
1414
|
function clamp(min = 0, val, max = Infinity) {
|
|
1149
1415
|
return Math.min(Math.max(val, min), max);
|
|
1150
1416
|
}
|
|
1151
1417
|
|
|
1152
|
-
// src/ts/
|
|
1153
|
-
var
|
|
1154
|
-
static
|
|
1418
|
+
// src/ts/modules/timeTravel.ts
|
|
1419
|
+
var TimeTravelModule = class extends BaseReactorModule {
|
|
1420
|
+
static moduleName = "timeTravel";
|
|
1155
1421
|
lastTimestamp = 0;
|
|
1156
1422
|
playbackTimeoutId = -1;
|
|
1157
1423
|
constructor(config, rtr) {
|
|
1158
|
-
super({ ...
|
|
1424
|
+
super({ ...TIME_TRAVEL_MODULE_BUILD, ...config }, rtr, { initialState: {}, history: [], currentFrame: 0, paused: true });
|
|
1159
1425
|
}
|
|
1160
1426
|
// ===========================================================================
|
|
1161
1427
|
// THE FOUNDATION & WIRETAP (Passive Recording)
|
|
1162
1428
|
// ===========================================================================
|
|
1163
1429
|
wire() {
|
|
1164
|
-
this.rtr.config.referenceTracking = this.rtr.config.smartCloning = this.rtr.config.eventTimeStamps = true;
|
|
1165
|
-
if (!this.state.history.length || this.state.initialState == null) this.state.initialState = this.rtr.snapshot();
|
|
1166
1430
|
this.lastTimestamp = performance.now();
|
|
1167
1431
|
this.state.set("currentFrame", (v = 0) => clamp(0, v, this.state.history.length), { signal: this.signal, immediate: true });
|
|
1168
|
-
this.config.on("paths", this.
|
|
1432
|
+
this.config.on("paths", this.handlePaths, { signal: this.signal, immediate: true });
|
|
1169
1433
|
!this.state.paused && this.play();
|
|
1170
1434
|
}
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1435
|
+
onAttach(rtr, rid) {
|
|
1436
|
+
rtr.config.referenceTracking = rtr.config.smartCloning = rtr.config.eventTimeStamps = true;
|
|
1437
|
+
if (!this.state.history.length || !this.state.initialState[rid]) this.state.initialState[rid] = rtr.snapshot();
|
|
1438
|
+
for (const p of this.config.paths ?? wpArr) rtr.on(p, this.record, { signal: this.signal });
|
|
1439
|
+
}
|
|
1440
|
+
handlePaths({ value: paths = wpArr, oldValue: prevs = wpArr }) {
|
|
1441
|
+
for (const rtr of this.rtrs.values()) {
|
|
1442
|
+
for (const p of prevs) rtr.off(p, this.record);
|
|
1443
|
+
for (const p of paths) rtr.off(p, this.record), rtr.on(p, this.record, { signal: this.signal });
|
|
1444
|
+
}
|
|
1174
1445
|
}
|
|
1175
1446
|
/** Chronicling the lifecycle of the system, Captures the essence of every mutation wave that bubbles up. */
|
|
1176
|
-
record(e) {
|
|
1447
|
+
record(e, rid = this.rids.get(e.reactor)) {
|
|
1177
1448
|
if (!this.state.paused) return;
|
|
1178
|
-
if (this.state.currentFrame < this.state.history.length) this.state
|
|
1179
|
-
if (this.state.history.length >= this.config.maxHistoryLength) this.state
|
|
1180
|
-
|
|
1449
|
+
if (this.state.currentFrame < this.state.history.length) fanout(this.state, "history", this.state.history.slice(0, this.state.currentFrame), { atomic: true });
|
|
1450
|
+
if (this.state.history.length >= this.config.maxHistoryLength) fanout(this.state, "history", this.state.history.slice(1), { atomic: true });
|
|
1451
|
+
const en = { path: e.target.path, value: e.reactor.snapshot(false, e.target.value), oldValue: e.reactor.snapshot(false, e.target.oldValue), type: e.staticType, deltat: e.timestamp - this.lastTimestamp, rid };
|
|
1452
|
+
e.rejected && (en.rejected = e.rejected), !e.target.hadKey && (en.hadKey = false), this.state.history.push(en);
|
|
1181
1453
|
this.state.currentFrame = this.state.history.length;
|
|
1182
1454
|
this.lastTimestamp = e.timestamp;
|
|
1183
1455
|
}
|
|
@@ -1186,7 +1458,7 @@ var TimeTravelPlugin = class extends BaseReactorPlugin {
|
|
|
1186
1458
|
this.pause();
|
|
1187
1459
|
this.playbackTimeoutId = -1;
|
|
1188
1460
|
this.state.history.length = this.state.currentFrame = 0;
|
|
1189
|
-
this.state.initialState = this.rtr.snapshot();
|
|
1461
|
+
this.state.initialState = Object.fromEntries(this.rtrs.entries().map(([rid, rtr]) => [rid, rtr.snapshot()]));
|
|
1190
1462
|
this.lastTimestamp = performance.now();
|
|
1191
1463
|
}
|
|
1192
1464
|
// ===========================================================================
|
|
@@ -1199,12 +1471,13 @@ var TimeTravelPlugin = class extends BaseReactorPlugin {
|
|
|
1199
1471
|
while (this.state.currentFrame !== target) {
|
|
1200
1472
|
const e = this.state.history[forward ? this.state.currentFrame : this.state.currentFrame - 1];
|
|
1201
1473
|
if (!e) break;
|
|
1202
|
-
|
|
1203
|
-
|
|
1474
|
+
const rtr = this.rtrs.get(e.rid) || this.rtrs.values().next().value;
|
|
1475
|
+
if (forward) e.type === "delete" ? deleteAny(rtr.core, e.path) : setAny(rtr.core, e.path, deepClone(e.value, rtr.config));
|
|
1476
|
+
else e.hadKey === false ? deleteAny(rtr.core, e.path) : setAny(rtr.core, e.path, deepClone(e.oldValue, rtr.config));
|
|
1204
1477
|
forward ? this.state.currentFrame++ : this.state.currentFrame--;
|
|
1205
|
-
if (e.rejected)
|
|
1478
|
+
if (e.rejected) rtr.log(`[Reactor ${this.name} Module] ${forward ? "Replaying" : "Reversing"} REJECTED intent at "${e.path}"`);
|
|
1206
1479
|
}
|
|
1207
|
-
this.rtr.tick();
|
|
1480
|
+
for (const rtr of this.rtrs.values()) rtr.tick();
|
|
1208
1481
|
if (!keepShield) this.state.paused = true;
|
|
1209
1482
|
}
|
|
1210
1483
|
/** Step through time, Moves the playhead and teleports the state. */
|
|
@@ -1223,9 +1496,9 @@ var TimeTravelPlugin = class extends BaseReactorPlugin {
|
|
|
1223
1496
|
async automove(forward = true) {
|
|
1224
1497
|
this.state.paused = false;
|
|
1225
1498
|
while ((forward ? this.state.currentFrame < this.state.history.length : this.state.currentFrame > 0) && !this.state.paused) {
|
|
1226
|
-
const
|
|
1499
|
+
const idx = forward ? this.state.currentFrame : this.state.currentFrame - 1, e = this.state.history[forward ? idx + 1 : idx - 1];
|
|
1227
1500
|
this.jumpTo(this.state.currentFrame + (forward ? 1 : -1), true);
|
|
1228
|
-
if (e?.
|
|
1501
|
+
if (e?.deltat > 0) await new Promise((res) => this.playbackTimeoutId = setTimeout2(() => res(0), Math.min(e.deltat, this.config.maxPlaybackDelay), this.signal));
|
|
1229
1502
|
}
|
|
1230
1503
|
this.state.paused = true;
|
|
1231
1504
|
}
|
|
@@ -1240,38 +1513,34 @@ var TimeTravelPlugin = class extends BaseReactorPlugin {
|
|
|
1240
1513
|
// ===========================================================================
|
|
1241
1514
|
/** Exports the current session as a JSON string. */
|
|
1242
1515
|
export(replacer, space) {
|
|
1243
|
-
|
|
1244
|
-
return JSON.stringify(this.state, replacer, space);
|
|
1245
|
-
} catch (e) {
|
|
1246
|
-
return this.rtr.log(`[Reactor ${this.name} Plug] Failed to export session`), "";
|
|
1247
|
-
}
|
|
1516
|
+
return JSON.stringify(this.state, replacer, space);
|
|
1248
1517
|
}
|
|
1249
1518
|
/** Imports a session from a JSON string, allowing you to replay or analyze past states. */
|
|
1250
|
-
import(json) {
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
this.state.currentFrame = 0, this.jumpTo(target), resume && this.play();
|
|
1258
|
-
} catch (e) {
|
|
1259
|
-
this.rtr.log(`[Reactor ${this.name} Plug] Failed to load session`);
|
|
1260
|
-
}
|
|
1519
|
+
import(json, reviver) {
|
|
1520
|
+
setAny(this.state, "*", JSON.parse(json, reviver));
|
|
1521
|
+
this.lastTimestamp = performance.now();
|
|
1522
|
+
const resume = !this.state.paused, target = this.state.currentFrame;
|
|
1523
|
+
this.state.paused = false;
|
|
1524
|
+
for (const [rid, rtr] of this.rtrs) setAny(rtr.core, "*", deepClone(this.state.initialState[rid], rtr.config)), rtr.tick();
|
|
1525
|
+
this.state.currentFrame = 0, this.jumpTo(target), resume && this.play();
|
|
1261
1526
|
}
|
|
1262
1527
|
};
|
|
1263
|
-
var
|
|
1528
|
+
var TIME_TRAVEL_MODULE_BUILD = { maxPlaybackDelay: 2e3 };
|
|
1264
1529
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1265
1530
|
0 && (module.exports = {
|
|
1266
|
-
|
|
1531
|
+
AsyncStorageAdapter,
|
|
1532
|
+
BaseReactorModule,
|
|
1267
1533
|
BaseStorageAdapter,
|
|
1534
|
+
COOKIE_ADAPTER_BUILD,
|
|
1535
|
+
CookieAdapter,
|
|
1268
1536
|
INDEXED_DB_ADAPTER_BUILD,
|
|
1269
1537
|
IndexedDBAdapter,
|
|
1270
1538
|
LocalStorageAdapter,
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1539
|
+
MemoryAdapter,
|
|
1540
|
+
PERSIST_MODULE_BUILD,
|
|
1541
|
+
PersistModule,
|
|
1542
|
+
SessionStorageAdapter,
|
|
1274
1543
|
StorageAdapter,
|
|
1275
|
-
|
|
1276
|
-
|
|
1544
|
+
TIME_TRAVEL_MODULE_BUILD,
|
|
1545
|
+
TimeTravelModule
|
|
1277
1546
|
});
|