@but212/atom-effect 0.3.1 → 0.3.3
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 +7 -6
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +17 -267
- package/dist/index.mjs +362 -825
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const
|
|
1
|
+
const O = {
|
|
2
2
|
IDLE: "idle",
|
|
3
3
|
PENDING: "pending",
|
|
4
4
|
RESOLVED: "resolved",
|
|
@@ -8,7 +8,7 @@ const T = {
|
|
|
8
8
|
// 0001 - Effect has been disposed
|
|
9
9
|
EXECUTING: 2
|
|
10
10
|
// 0010 - Effect is currently executing
|
|
11
|
-
},
|
|
11
|
+
}, o = {
|
|
12
12
|
DIRTY: 1,
|
|
13
13
|
// 0001 - Needs recomputation
|
|
14
14
|
IDLE: 2,
|
|
@@ -23,12 +23,12 @@ const T = {
|
|
|
23
23
|
// 100000 - Currently recomputing
|
|
24
24
|
HAS_ERROR: 64
|
|
25
25
|
// 1000000 - Has error state
|
|
26
|
-
},
|
|
26
|
+
}, le = {
|
|
27
27
|
/** Maximum number of pooled objects to prevent memory bloat */
|
|
28
28
|
MAX_SIZE: 1e3,
|
|
29
29
|
/** Number of objects to pre-allocate for performance-critical paths */
|
|
30
30
|
WARMUP_SIZE: 100
|
|
31
|
-
},
|
|
31
|
+
}, P = {
|
|
32
32
|
/** Maximum effect executions per second to detect infinite loops (Legacy/Fallback) */
|
|
33
33
|
MAX_EXECUTIONS_PER_SECOND: 100,
|
|
34
34
|
/** Threshold for cleaning up old execution timestamps */
|
|
@@ -43,13 +43,13 @@ const T = {
|
|
|
43
43
|
* Increased from 1000 to 5000 based on evaluation report
|
|
44
44
|
*/
|
|
45
45
|
MAX_EXECUTIONS_PER_FLUSH: 5e3
|
|
46
|
-
},
|
|
46
|
+
}, j = {
|
|
47
47
|
/** Maximum dependencies before warning about large dependency graphs */
|
|
48
48
|
MAX_DEPENDENCIES: 1e3,
|
|
49
49
|
/** Enable infinite loop detection warnings */
|
|
50
50
|
WARN_INFINITE_LOOP: !0
|
|
51
|
-
},
|
|
52
|
-
class
|
|
51
|
+
}, T = 1073741823, d = typeof process < "u" && process.env && process.env.NODE_ENV !== "production";
|
|
52
|
+
class E extends Error {
|
|
53
53
|
/**
|
|
54
54
|
* Creates a new AtomError
|
|
55
55
|
* @param message - Error message describing what went wrong
|
|
@@ -60,7 +60,7 @@ class d extends Error {
|
|
|
60
60
|
super(e), this.name = "AtomError", this.cause = t, this.recoverable = s, this.timestamp = /* @__PURE__ */ new Date();
|
|
61
61
|
}
|
|
62
62
|
}
|
|
63
|
-
class
|
|
63
|
+
class C extends E {
|
|
64
64
|
/**
|
|
65
65
|
* Creates a new ComputedError
|
|
66
66
|
* @param message - Error message
|
|
@@ -70,7 +70,7 @@ class D extends d {
|
|
|
70
70
|
super(e, t, !0), this.name = "ComputedError";
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
class
|
|
73
|
+
class g extends E {
|
|
74
74
|
/**
|
|
75
75
|
* Creates a new EffectError
|
|
76
76
|
* @param message - Error message
|
|
@@ -80,7 +80,7 @@ class S extends d {
|
|
|
80
80
|
super(e, t, !1), this.name = "EffectError";
|
|
81
81
|
}
|
|
82
82
|
}
|
|
83
|
-
class
|
|
83
|
+
class A extends E {
|
|
84
84
|
/**
|
|
85
85
|
* Creates a new SchedulerError
|
|
86
86
|
* @param message - Error message
|
|
@@ -90,20 +90,20 @@ class C extends d {
|
|
|
90
90
|
super(e, t, !1), this.name = "SchedulerError";
|
|
91
91
|
}
|
|
92
92
|
}
|
|
93
|
-
function
|
|
93
|
+
function N(i, e, t) {
|
|
94
94
|
if (i instanceof TypeError)
|
|
95
95
|
return new e(`Type error (${t}): ${i.message}`, i);
|
|
96
96
|
if (i instanceof ReferenceError)
|
|
97
97
|
return new e(`Reference error (${t}): ${i.message}`, i);
|
|
98
|
-
if (i instanceof
|
|
98
|
+
if (i instanceof E)
|
|
99
99
|
return i;
|
|
100
100
|
const s = i instanceof Error ? i.message : String(i), n = i instanceof Error ? i : null;
|
|
101
101
|
return new e(`Unexpected error (${t}): ${s}`, n);
|
|
102
102
|
}
|
|
103
|
-
function
|
|
103
|
+
function Q(i) {
|
|
104
104
|
return i != null && typeof i.then == "function";
|
|
105
105
|
}
|
|
106
|
-
const
|
|
106
|
+
const l = {
|
|
107
107
|
// ─────────────────────────────────────────────────────────────────
|
|
108
108
|
// Computed errors
|
|
109
109
|
// ─────────────────────────────────────────────────────────────────
|
|
@@ -187,101 +187,150 @@ const a = {
|
|
|
187
187
|
* @remarks This prevents cascading failures from masking the original error.
|
|
188
188
|
*/
|
|
189
189
|
CALLBACK_ERROR_IN_ERROR_HANDLER: "Error occurred during onError callback execution"
|
|
190
|
+
}, w = /* @__PURE__ */ Symbol("debugName"), ee = /* @__PURE__ */ Symbol("id"), V = /* @__PURE__ */ Symbol("type"), X = /* @__PURE__ */ Symbol("noDefaultValue");
|
|
191
|
+
function te(i) {
|
|
192
|
+
return i !== null && typeof i == "object" && "dependencies" in i && Array.isArray(i.dependencies);
|
|
193
|
+
}
|
|
194
|
+
let G = 0;
|
|
195
|
+
function H(i, e, t) {
|
|
196
|
+
const s = i;
|
|
197
|
+
if (s._visitedEpoch !== t) {
|
|
198
|
+
if (s._visitedEpoch = t, i === e)
|
|
199
|
+
throw new C("Indirect circular dependency detected");
|
|
200
|
+
if (te(i)) {
|
|
201
|
+
const n = i.dependencies;
|
|
202
|
+
for (let r = 0; r < n.length; r++)
|
|
203
|
+
H(n[r], e, t);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
const S = {
|
|
208
|
+
enabled: typeof process < "u" && process.env?.NODE_ENV === "development",
|
|
209
|
+
maxDependencies: j.MAX_DEPENDENCIES,
|
|
210
|
+
warnInfiniteLoop: j.WARN_INFINITE_LOOP,
|
|
211
|
+
warn(i, e) {
|
|
212
|
+
this.enabled && i && console.warn(`[Atom Effect] ${e}`);
|
|
213
|
+
},
|
|
214
|
+
/**
|
|
215
|
+
* Checks for circular dependencies.
|
|
216
|
+
* Direct check runs always; indirect check only in dev mode.
|
|
217
|
+
* @throws {ComputedError} When circular dependency detected
|
|
218
|
+
*/
|
|
219
|
+
checkCircular(i, e, t) {
|
|
220
|
+
if (i === e)
|
|
221
|
+
throw new C("Direct circular dependency detected");
|
|
222
|
+
this.enabled && (G++, H(i, e, G));
|
|
223
|
+
},
|
|
224
|
+
attachDebugInfo(i, e, t) {
|
|
225
|
+
if (!this.enabled)
|
|
226
|
+
return;
|
|
227
|
+
const s = i;
|
|
228
|
+
s[w] = `${e}_${t}`, s[ee] = t, s[V] = e;
|
|
229
|
+
},
|
|
230
|
+
getDebugName(i) {
|
|
231
|
+
if (i !== null && typeof i == "object" && w in i)
|
|
232
|
+
return i[w];
|
|
233
|
+
},
|
|
234
|
+
getDebugType(i) {
|
|
235
|
+
if (i !== null && typeof i == "object" && V in i)
|
|
236
|
+
return i[V];
|
|
237
|
+
}
|
|
190
238
|
};
|
|
191
|
-
let
|
|
192
|
-
|
|
193
|
-
|
|
239
|
+
let se = 1;
|
|
240
|
+
const ie = () => se++;
|
|
241
|
+
class J {
|
|
242
|
+
constructor() {
|
|
243
|
+
this.id = ie() & T, this.flags = 0;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
class W extends J {
|
|
247
|
+
constructor() {
|
|
248
|
+
super(), this.version = 0, this._lastSeenEpoch = -1;
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Subscribes a listener function or Subscriber object to value changes.
|
|
252
|
+
*
|
|
253
|
+
* @param listener - Function or Subscriber object to call when the value changes
|
|
254
|
+
* @returns An unsubscribe function
|
|
255
|
+
* @throws {AtomError} If listener is not a function or Subscriber
|
|
256
|
+
*/
|
|
257
|
+
subscribe(e) {
|
|
258
|
+
if (typeof e == "object" && e !== null && "execute" in e)
|
|
259
|
+
return this._objectSubscribers.add(e);
|
|
260
|
+
if (typeof e != "function")
|
|
261
|
+
throw new E(l.ATOM_SUBSCRIBER_MUST_BE_FUNCTION);
|
|
262
|
+
return this._functionSubscribers.add(e);
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Gets the total number of active subscribers.
|
|
266
|
+
*/
|
|
267
|
+
subscriberCount() {
|
|
268
|
+
return this._functionSubscribers.size + this._objectSubscribers.size;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Notifies all subscribers of a change.
|
|
272
|
+
*
|
|
273
|
+
* @param newValue - The new value
|
|
274
|
+
* @param oldValue - The old value
|
|
275
|
+
*/
|
|
276
|
+
_notifySubscribers(e, t) {
|
|
277
|
+
this._functionSubscribers.forEachSafe(
|
|
278
|
+
(s) => s(e, t),
|
|
279
|
+
(s) => console.error(new E(l.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED, s))
|
|
280
|
+
), this._objectSubscribers.forEachSafe(
|
|
281
|
+
(s) => s.execute(),
|
|
282
|
+
(s) => console.error(new E(l.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED, s))
|
|
283
|
+
);
|
|
284
|
+
}
|
|
194
285
|
}
|
|
195
|
-
let
|
|
196
|
-
function
|
|
197
|
-
return
|
|
286
|
+
let B = 0;
|
|
287
|
+
function K() {
|
|
288
|
+
return B = (B + 1 | 0) & T, B;
|
|
289
|
+
}
|
|
290
|
+
let v = 0, k = 0, L = !1;
|
|
291
|
+
function Y() {
|
|
292
|
+
return L ? (d && console.warn(
|
|
198
293
|
"Warning: startFlush() called during flush - ignored to prevent infinite loop detection bypass"
|
|
199
|
-
), !1) : (
|
|
294
|
+
), !1) : (L = !0, v = v + 1 & T, k = 0, !0);
|
|
200
295
|
}
|
|
201
|
-
function
|
|
202
|
-
|
|
296
|
+
function $() {
|
|
297
|
+
L = !1;
|
|
203
298
|
}
|
|
204
|
-
function
|
|
205
|
-
return
|
|
299
|
+
function ne() {
|
|
300
|
+
return L ? ++k : 0;
|
|
206
301
|
}
|
|
207
|
-
class
|
|
302
|
+
class re {
|
|
208
303
|
constructor() {
|
|
209
304
|
this.queueA = [], this.queueB = [], this.queue = this.queueA, this.queueSize = 0, this._epoch = 0, this.isProcessing = !1, this.isBatching = !1, this.batchDepth = 0, this.batchQueue = [], this.batchQueueSize = 0, this.isFlushingSync = !1, this.maxFlushIterations = 1e3;
|
|
210
305
|
}
|
|
211
|
-
/**
|
|
212
|
-
* Gets the current phase of the scheduler.
|
|
213
|
-
*/
|
|
214
306
|
get phase() {
|
|
215
307
|
return this.isProcessing || this.isFlushingSync ? 2 : this.isBatching ? 1 : 0;
|
|
216
308
|
}
|
|
217
|
-
/**
|
|
218
|
-
* Schedules a callback for execution.
|
|
219
|
-
*
|
|
220
|
-
* If batching is active or a sync flush is in progress, the callback
|
|
221
|
-
* is added to the batch queue. Otherwise, it's added to the main queue
|
|
222
|
-
* and a flush is triggered via microtask.
|
|
223
|
-
*
|
|
224
|
-
* @param callback - The function to schedule for execution
|
|
225
|
-
* @throws {SchedulerError} If callback is not a function
|
|
226
|
-
*
|
|
227
|
-
* @example
|
|
228
|
-
* ```typescript
|
|
229
|
-
* scheduler.schedule(() => {
|
|
230
|
-
* // This runs in the next microtask (or sync if batching)
|
|
231
|
-
* updateUI();
|
|
232
|
-
* });
|
|
233
|
-
* ```
|
|
234
|
-
*/
|
|
235
309
|
schedule(e) {
|
|
236
310
|
if (typeof e != "function")
|
|
237
|
-
throw new
|
|
311
|
+
throw new A("Scheduler callback must be a function");
|
|
238
312
|
e._nextEpoch !== this._epoch && (e._nextEpoch = this._epoch, this.isBatching || this.isFlushingSync ? this.batchQueue[this.batchQueueSize++] = e : (this.queue[this.queueSize++] = e, this.isProcessing || this.flush()));
|
|
239
313
|
}
|
|
240
|
-
/**
|
|
241
|
-
* Flushes the queue asynchronously via microtask.
|
|
242
|
-
*
|
|
243
|
-
* Executes all queued callbacks in a microtask, allowing the current
|
|
244
|
-
* synchronous execution to complete first. Errors in individual
|
|
245
|
-
* callbacks are caught and logged without interrupting others.
|
|
246
|
-
*
|
|
247
|
-
* @private
|
|
248
|
-
* @remarks
|
|
249
|
-
* This method is idempotent - calling it multiple times while
|
|
250
|
-
* processing is active has no effect.
|
|
251
|
-
*/
|
|
252
314
|
flush() {
|
|
253
315
|
if (this.isProcessing || this.queueSize === 0) return;
|
|
254
316
|
this.isProcessing = !0;
|
|
255
317
|
const e = this.queue, t = this.queueSize;
|
|
256
318
|
this.queue = this.queue === this.queueA ? this.queueB : this.queueA, this.queueSize = 0, this._epoch++, queueMicrotask(() => {
|
|
257
|
-
const s =
|
|
319
|
+
const s = Y();
|
|
258
320
|
for (let n = 0; n < t; n++)
|
|
259
321
|
try {
|
|
260
322
|
e[n]?.();
|
|
261
323
|
} catch (r) {
|
|
262
324
|
console.error(
|
|
263
|
-
new
|
|
325
|
+
new A("Error occurred during scheduler execution", r)
|
|
264
326
|
);
|
|
265
327
|
}
|
|
266
|
-
e.length = 0, this.isProcessing = !1, s &&
|
|
328
|
+
e.length = 0, this.isProcessing = !1, s && $(), this.queueSize > 0 && !this.isBatching && this.flush();
|
|
267
329
|
});
|
|
268
330
|
}
|
|
269
|
-
/**
|
|
270
|
-
* Flushes all queued callbacks synchronously.
|
|
271
|
-
*
|
|
272
|
-
* This method is called when a batch ends. It processes all callbacks
|
|
273
|
-
* in the batch queue and main queue synchronously, allowing callbacks
|
|
274
|
-
* to schedule additional callbacks that are processed in the same flush.
|
|
275
|
-
*
|
|
276
|
-
* @private
|
|
277
|
-
* @remarks
|
|
278
|
-
* - Includes infinite loop protection via maxFlushIterations
|
|
279
|
-
* - Errors in callbacks are caught and logged individually
|
|
280
|
-
* - The isFlushingSync flag prevents re-entrancy issues
|
|
281
|
-
*/
|
|
282
331
|
flushSync() {
|
|
283
332
|
this.isFlushingSync = !0;
|
|
284
|
-
const e =
|
|
333
|
+
const e = Y();
|
|
285
334
|
try {
|
|
286
335
|
if (this._epoch++, this.batchQueueSize > 0) {
|
|
287
336
|
for (let s = 0; s < this.batchQueueSize; s++) {
|
|
@@ -294,8 +343,8 @@ class J {
|
|
|
294
343
|
for (; this.queueSize > 0; ) {
|
|
295
344
|
if (++t > this.maxFlushIterations) {
|
|
296
345
|
console.error(
|
|
297
|
-
new
|
|
298
|
-
`Maximum flush iterations (${this.maxFlushIterations}) exceeded. Possible infinite loop
|
|
346
|
+
new A(
|
|
347
|
+
`Maximum flush iterations (${this.maxFlushIterations}) exceeded. Possible infinite loop.`
|
|
299
348
|
)
|
|
300
349
|
), this.queueSize = 0, this.queue.length = 0, this.batchQueueSize = 0;
|
|
301
350
|
break;
|
|
@@ -307,7 +356,7 @@ class J {
|
|
|
307
356
|
s[r]?.();
|
|
308
357
|
} catch (c) {
|
|
309
358
|
console.error(
|
|
310
|
-
new
|
|
359
|
+
new A("Error occurred during batch execution", c)
|
|
311
360
|
);
|
|
312
361
|
}
|
|
313
362
|
if (s.length = 0, this.batchQueueSize > 0) {
|
|
@@ -317,94 +366,36 @@ class J {
|
|
|
317
366
|
}
|
|
318
367
|
}
|
|
319
368
|
} finally {
|
|
320
|
-
this.isFlushingSync = !1, e &&
|
|
369
|
+
this.isFlushingSync = !1, e && $();
|
|
321
370
|
}
|
|
322
371
|
}
|
|
323
|
-
/**
|
|
324
|
-
* Starts a new batch operation.
|
|
325
|
-
*
|
|
326
|
-
* While batching is active, all scheduled callbacks are deferred
|
|
327
|
-
* until endBatch() is called. Batches can be nested - only the
|
|
328
|
-
* outermost endBatch() triggers execution.
|
|
329
|
-
*
|
|
330
|
-
* @example
|
|
331
|
-
* ```typescript
|
|
332
|
-
* scheduler.startBatch();
|
|
333
|
-
* // All updates here are deferred
|
|
334
|
-
* atom1.value = 'a';
|
|
335
|
-
* atom2.value = 'b';
|
|
336
|
-
* scheduler.endBatch(); // Both updates processed together
|
|
337
|
-
* ```
|
|
338
|
-
*/
|
|
339
372
|
startBatch() {
|
|
340
373
|
this.batchDepth++, this.isBatching = !0;
|
|
341
374
|
}
|
|
342
|
-
/**
|
|
343
|
-
* Ends a batch operation.
|
|
344
|
-
*
|
|
345
|
-
* Decrements the batch depth counter. When depth reaches zero,
|
|
346
|
-
* all queued callbacks are flushed synchronously and batching
|
|
347
|
-
* is disabled.
|
|
348
|
-
*
|
|
349
|
-
* @remarks
|
|
350
|
-
* Safe to call even if startBatch() wasn't called - depth is
|
|
351
|
-
* clamped to zero minimum.
|
|
352
|
-
*
|
|
353
|
-
* @example
|
|
354
|
-
* ```typescript
|
|
355
|
-
* scheduler.startBatch();
|
|
356
|
-
* try {
|
|
357
|
-
* // ... batched operations
|
|
358
|
-
* } finally {
|
|
359
|
-
* scheduler.endBatch(); // Always end batch, even on error
|
|
360
|
-
* }
|
|
361
|
-
* ```
|
|
362
|
-
*/
|
|
363
375
|
endBatch() {
|
|
364
376
|
this.batchDepth = Math.max(0, this.batchDepth - 1), this.batchDepth === 0 && (this.flushSync(), this.isBatching = !1);
|
|
365
377
|
}
|
|
366
|
-
/**
|
|
367
|
-
* Sets the maximum number of flush iterations allowed.
|
|
368
|
-
*
|
|
369
|
-
* This limit prevents infinite loops when reactive dependencies
|
|
370
|
-
* form cycles. If exceeded, the queue is cleared and an error
|
|
371
|
-
* is logged.
|
|
372
|
-
*
|
|
373
|
-
* @param max - Maximum iterations (must be at least 10)
|
|
374
|
-
* @throws {SchedulerError} If max is less than 10
|
|
375
|
-
*
|
|
376
|
-
* @example
|
|
377
|
-
* ```typescript
|
|
378
|
-
* // Increase limit for complex dependency graphs
|
|
379
|
-
* scheduler.setMaxFlushIterations(5000);
|
|
380
|
-
* ```
|
|
381
|
-
*/
|
|
382
378
|
setMaxFlushIterations(e) {
|
|
383
379
|
if (e < 10)
|
|
384
|
-
throw new
|
|
380
|
+
throw new A("Max flush iterations must be at least 10");
|
|
385
381
|
this.maxFlushIterations = e;
|
|
386
382
|
}
|
|
387
383
|
}
|
|
388
|
-
const
|
|
389
|
-
function
|
|
384
|
+
const U = new re();
|
|
385
|
+
function ae(i) {
|
|
390
386
|
if (typeof i != "function")
|
|
391
|
-
throw new
|
|
392
|
-
|
|
387
|
+
throw new E("Batch callback must be a function");
|
|
388
|
+
U.startBatch();
|
|
393
389
|
try {
|
|
394
390
|
return i();
|
|
395
391
|
} catch (e) {
|
|
396
|
-
throw new
|
|
392
|
+
throw new E("Error occurred during batch execution", e);
|
|
397
393
|
} finally {
|
|
398
|
-
|
|
394
|
+
U.endBatch();
|
|
399
395
|
}
|
|
400
396
|
}
|
|
401
|
-
const
|
|
402
|
-
/** @inheritdoc */
|
|
397
|
+
const m = {
|
|
403
398
|
current: null,
|
|
404
|
-
/**
|
|
405
|
-
* @inheritdoc
|
|
406
|
-
* @throws Re-throws any error from the executed function after restoring context
|
|
407
|
-
*/
|
|
408
399
|
run(i, e) {
|
|
409
400
|
const t = this.current;
|
|
410
401
|
this.current = i;
|
|
@@ -414,192 +405,28 @@ const y = {
|
|
|
414
405
|
this.current = t;
|
|
415
406
|
}
|
|
416
407
|
},
|
|
417
|
-
/** @inheritdoc */
|
|
418
408
|
getCurrent() {
|
|
419
409
|
return this.current;
|
|
420
410
|
}
|
|
421
411
|
};
|
|
422
|
-
function
|
|
412
|
+
function ce(i) {
|
|
423
413
|
if (typeof i != "function")
|
|
424
|
-
throw new
|
|
425
|
-
const e =
|
|
426
|
-
|
|
414
|
+
throw new E("Untracked callback must be a function");
|
|
415
|
+
const e = m.current;
|
|
416
|
+
m.current = null;
|
|
427
417
|
try {
|
|
428
418
|
return i();
|
|
429
419
|
} catch (t) {
|
|
430
|
-
throw new
|
|
420
|
+
throw new E("Error occurred during untracked execution", t);
|
|
431
421
|
} finally {
|
|
432
|
-
|
|
433
|
-
}
|
|
434
|
-
}
|
|
435
|
-
const L = /* @__PURE__ */ Symbol("debugName"), W = /* @__PURE__ */ Symbol("id"), M = /* @__PURE__ */ Symbol("type"), j = /* @__PURE__ */ Symbol("noDefaultValue");
|
|
436
|
-
function K(i) {
|
|
437
|
-
return i !== null && typeof i == "object" && "dependencies" in i && Array.isArray(i.dependencies);
|
|
438
|
-
}
|
|
439
|
-
let V = 0;
|
|
440
|
-
function Y(i, e, t) {
|
|
441
|
-
const s = i;
|
|
442
|
-
if (s._visitedEpoch !== t) {
|
|
443
|
-
if (s._visitedEpoch = t, i === e)
|
|
444
|
-
throw new D("Indirect circular dependency detected");
|
|
445
|
-
if (K(i)) {
|
|
446
|
-
const n = i.dependencies;
|
|
447
|
-
for (let r = 0; r < n.length; r++)
|
|
448
|
-
Y(n[r], e, t);
|
|
449
|
-
}
|
|
422
|
+
m.current = e;
|
|
450
423
|
}
|
|
451
424
|
}
|
|
452
|
-
|
|
453
|
-
/**
|
|
454
|
-
* Whether debug mode is enabled.
|
|
455
|
-
*
|
|
456
|
-
* @remarks
|
|
457
|
-
* Automatically set based on `NODE_ENV` environment variable.
|
|
458
|
-
* Only `'development'` enables debug features.
|
|
459
|
-
*/
|
|
460
|
-
enabled: typeof process < "u" && process.env?.NODE_ENV === "development",
|
|
461
|
-
/**
|
|
462
|
-
* Maximum number of dependencies before warning.
|
|
463
|
-
*
|
|
464
|
-
* @see {@link DEBUG_CONFIG.MAX_DEPENDENCIES}
|
|
465
|
-
*/
|
|
466
|
-
maxDependencies: k.MAX_DEPENDENCIES,
|
|
467
|
-
/**
|
|
468
|
-
* Whether to warn about potential infinite loops.
|
|
469
|
-
*
|
|
470
|
-
* @see {@link DEBUG_CONFIG.WARN_INFINITE_LOOP}
|
|
471
|
-
*/
|
|
472
|
-
warnInfiniteLoop: k.WARN_INFINITE_LOOP,
|
|
473
|
-
/**
|
|
474
|
-
* Logs a warning message when condition is true and debug is enabled.
|
|
475
|
-
*
|
|
476
|
-
* @param condition - When true, the warning is logged
|
|
477
|
-
* @param message - The warning message to display
|
|
478
|
-
*
|
|
479
|
-
* @example
|
|
480
|
-
* ```typescript
|
|
481
|
-
* debug.warn(deps.length > 100, 'Large dependency graph detected');
|
|
482
|
-
* ```
|
|
483
|
-
*/
|
|
484
|
-
warn(i, e) {
|
|
485
|
-
this.enabled && i && console.warn(`[Atom Effect] ${e}`);
|
|
486
|
-
},
|
|
487
|
-
/**
|
|
488
|
-
* Checks for circular dependencies in the dependency graph.
|
|
489
|
-
*
|
|
490
|
-
* Detects two types of circular references:
|
|
491
|
-
* 1. **Direct**: A depends on itself (A → A)
|
|
492
|
-
* 2. **Indirect**: A depends on B which depends on A (A → B → A)
|
|
493
|
-
*
|
|
494
|
-
* @param dep - The dependency being added
|
|
495
|
-
* @param current - The current reactive object adding the dependency
|
|
496
|
-
* @param visited - Set of already visited nodes (for recursion)
|
|
497
|
-
*
|
|
498
|
-
* @throws {ComputedError} When a circular dependency is detected
|
|
499
|
-
*
|
|
500
|
-
* @remarks
|
|
501
|
-
* - Direct circular detection runs in all environments
|
|
502
|
-
* - Indirect circular detection only runs in development mode
|
|
503
|
-
* - Uses depth-first traversal with O(n) time complexity
|
|
504
|
-
*
|
|
505
|
-
* @example
|
|
506
|
-
* ```typescript
|
|
507
|
-
* // This will throw for direct circular reference
|
|
508
|
-
* debug.checkCircular(computedA, computedA);
|
|
509
|
-
*
|
|
510
|
-
* // This will throw for indirect circular reference (dev only)
|
|
511
|
-
* // Given: A → B → C → A
|
|
512
|
-
* debug.checkCircular(computedC, computedA);
|
|
513
|
-
* ```
|
|
514
|
-
*/
|
|
515
|
-
checkCircular(i, e, t) {
|
|
516
|
-
if (i === e)
|
|
517
|
-
throw new D("Direct circular dependency detected");
|
|
518
|
-
this.enabled && (V++, Y(i, e, V));
|
|
519
|
-
},
|
|
520
|
-
/**
|
|
521
|
-
* Attaches debug metadata to a reactive object.
|
|
522
|
-
*
|
|
523
|
-
* @param obj - The object to attach metadata to
|
|
524
|
-
* @param type - The type of reactive object ('atom' | 'computed' | 'effect')
|
|
525
|
-
* @param id - The unique identifier for this object
|
|
526
|
-
*
|
|
527
|
-
* @remarks
|
|
528
|
-
* Only attaches metadata when debug mode is enabled.
|
|
529
|
-
* Uses symbol keys to avoid property name collisions.
|
|
530
|
-
*
|
|
531
|
-
* @example
|
|
532
|
-
* ```typescript
|
|
533
|
-
* const atom = createAtomInternal(0);
|
|
534
|
-
* debug.attachDebugInfo(atom, 'atom', 1);
|
|
535
|
-
* // atom[DEBUG_NAME] === 'atom_1'
|
|
536
|
-
* // atom[DEBUG_ID] === 1
|
|
537
|
-
* // atom[DEBUG_TYPE] === 'atom'
|
|
538
|
-
* ```
|
|
539
|
-
*/
|
|
540
|
-
attachDebugInfo(i, e, t) {
|
|
541
|
-
if (!this.enabled)
|
|
542
|
-
return;
|
|
543
|
-
const s = i;
|
|
544
|
-
s[L] = `${e}_${t}`, s[W] = t, s[M] = e;
|
|
545
|
-
},
|
|
546
|
-
/**
|
|
547
|
-
* Retrieves the debug display name from a reactive object.
|
|
548
|
-
*
|
|
549
|
-
* @param obj - The object to get the name from
|
|
550
|
-
* @returns The debug name (e.g., 'atom_1') or undefined if not set
|
|
551
|
-
*
|
|
552
|
-
* @example
|
|
553
|
-
* ```typescript
|
|
554
|
-
* const name = debug.getDebugName(myAtom);
|
|
555
|
-
* console.log(`Updating ${name ?? 'unknown'}`);
|
|
556
|
-
* ```
|
|
557
|
-
*/
|
|
558
|
-
getDebugName(i) {
|
|
559
|
-
if (i !== null && typeof i == "object" && L in i)
|
|
560
|
-
return i[L];
|
|
561
|
-
},
|
|
562
|
-
/**
|
|
563
|
-
* Retrieves the debug type from a reactive object.
|
|
564
|
-
*
|
|
565
|
-
* @param obj - The object to get the type from
|
|
566
|
-
* @returns The type ('atom' | 'computed' | 'effect') or undefined if not set
|
|
567
|
-
*
|
|
568
|
-
* @example
|
|
569
|
-
* ```typescript
|
|
570
|
-
* const type = debug.getDebugType(reactiveObj);
|
|
571
|
-
* if (type === 'computed') {
|
|
572
|
-
* // Handle computed-specific logic
|
|
573
|
-
* }
|
|
574
|
-
* ```
|
|
575
|
-
*/
|
|
576
|
-
getDebugType(i) {
|
|
577
|
-
if (i !== null && typeof i == "object" && M in i)
|
|
578
|
-
return i[M];
|
|
579
|
-
}
|
|
580
|
-
};
|
|
581
|
-
let Z = 1;
|
|
582
|
-
const B = () => Z++;
|
|
583
|
-
class x {
|
|
425
|
+
class M {
|
|
584
426
|
constructor() {
|
|
585
427
|
this.subscribers = null;
|
|
586
428
|
}
|
|
587
|
-
/**
|
|
588
|
-
* Adds a subscriber and returns an unsubscribe function
|
|
589
|
-
*
|
|
590
|
-
* Performs lazy initialization on first subscriber.
|
|
591
|
-
* Duplicate subscribers are ignored (idempotent).
|
|
592
|
-
*
|
|
593
|
-
* @param subscriber - Function to add as subscriber
|
|
594
|
-
* @returns Unsubscribe function
|
|
595
|
-
*
|
|
596
|
-
* @example
|
|
597
|
-
* ```ts
|
|
598
|
-
* const unsub = manager.add((value) => console.log(value));
|
|
599
|
-
* // Later...
|
|
600
|
-
* unsub(); // Remove this subscriber
|
|
601
|
-
* ```
|
|
602
|
-
*/
|
|
429
|
+
/** Adds subscriber and returns unsubscribe function (idempotent) */
|
|
603
430
|
add(e) {
|
|
604
431
|
if (this.subscribers || (this.subscribers = []), this.subscribers.indexOf(e) !== -1)
|
|
605
432
|
return () => {
|
|
@@ -610,16 +437,7 @@ class x {
|
|
|
610
437
|
t || (t = !0, this.remove(e));
|
|
611
438
|
};
|
|
612
439
|
}
|
|
613
|
-
/**
|
|
614
|
-
* Removes a subscriber using swap-and-pop optimization
|
|
615
|
-
*
|
|
616
|
-
* Linear search + O(1) swap-and-pop removal.
|
|
617
|
-
* For small arrays, this is faster than hash-based approaches
|
|
618
|
-
* due to cache locality.
|
|
619
|
-
*
|
|
620
|
-
* @param subscriber - Subscriber to remove
|
|
621
|
-
* @returns True if removed, false if not found
|
|
622
|
-
*/
|
|
440
|
+
/** Removes subscriber using swap-and-pop */
|
|
623
441
|
remove(e) {
|
|
624
442
|
if (!this.subscribers)
|
|
625
443
|
return !1;
|
|
@@ -629,44 +447,15 @@ class x {
|
|
|
629
447
|
const s = this.subscribers.length - 1;
|
|
630
448
|
return t !== s && (this.subscribers[t] = this.subscribers[s]), this.subscribers.pop(), !0;
|
|
631
449
|
}
|
|
632
|
-
/**
|
|
633
|
-
* Checks if a subscriber is registered
|
|
634
|
-
*
|
|
635
|
-
* @param subscriber - Subscriber to check
|
|
636
|
-
* @returns True if registered
|
|
637
|
-
*/
|
|
638
450
|
has(e) {
|
|
639
451
|
return this.subscribers ? this.subscribers.indexOf(e) !== -1 : !1;
|
|
640
452
|
}
|
|
641
|
-
/**
|
|
642
|
-
* Iterates over all subscribers with a callback
|
|
643
|
-
*
|
|
644
|
-
* Optimized for cache-friendly sequential access.
|
|
645
|
-
* Errors in callbacks are propagated to the caller.
|
|
646
|
-
*
|
|
647
|
-
* @param fn - Callback to execute for each subscriber
|
|
648
|
-
*
|
|
649
|
-
* @example
|
|
650
|
-
* ```ts
|
|
651
|
-
* manager.forEach((subscriber) => {
|
|
652
|
-
* subscriber(newValue, oldValue);
|
|
653
|
-
* });
|
|
654
|
-
* ```
|
|
655
|
-
*/
|
|
656
453
|
forEach(e) {
|
|
657
454
|
if (this.subscribers)
|
|
658
455
|
for (let t = 0; t < this.subscribers.length; t++)
|
|
659
456
|
e(this.subscribers[t], t);
|
|
660
457
|
}
|
|
661
|
-
/**
|
|
662
|
-
* Safely iterates over subscribers with error handling
|
|
663
|
-
*
|
|
664
|
-
* Catches and logs errors from individual callbacks to prevent
|
|
665
|
-
* one failing subscriber from breaking the entire notification chain.
|
|
666
|
-
*
|
|
667
|
-
* @param fn - Callback to execute for each subscriber
|
|
668
|
-
* @param onError - Optional error handler for each callback error
|
|
669
|
-
*/
|
|
458
|
+
/** Iterates with error handling to prevent one failure from breaking the chain */
|
|
670
459
|
forEachSafe(e, t) {
|
|
671
460
|
if (this.subscribers)
|
|
672
461
|
for (let s = 0; s < this.subscribers.length; s++)
|
|
@@ -676,224 +465,101 @@ class x {
|
|
|
676
465
|
t ? t(n) : console.error("[SubscriberManager] Error in subscriber callback:", n);
|
|
677
466
|
}
|
|
678
467
|
}
|
|
679
|
-
/**
|
|
680
|
-
* Gets the current number of subscribers
|
|
681
|
-
*
|
|
682
|
-
* @returns Number of active subscribers
|
|
683
|
-
*/
|
|
684
468
|
get size() {
|
|
685
469
|
return this.subscribers?.length ?? 0;
|
|
686
470
|
}
|
|
687
|
-
/**
|
|
688
|
-
* Checks if there are any subscribers
|
|
689
|
-
*
|
|
690
|
-
* @returns True if at least one subscriber exists
|
|
691
|
-
*/
|
|
692
471
|
get hasSubscribers() {
|
|
693
472
|
return this.size > 0;
|
|
694
473
|
}
|
|
695
|
-
/**
|
|
696
|
-
* Clears all subscribers
|
|
697
|
-
*
|
|
698
|
-
* Removes all subscribers and releases memory.
|
|
699
|
-
* Subsequent operations will re-initialize lazily.
|
|
700
|
-
*/
|
|
701
474
|
clear() {
|
|
702
475
|
this.subscribers = null;
|
|
703
476
|
}
|
|
704
|
-
/**
|
|
705
|
-
* Gets a copy of all subscribers as an array
|
|
706
|
-
*
|
|
707
|
-
* Useful for debugging or manual iteration.
|
|
708
|
-
* Returns empty array if no subscribers.
|
|
709
|
-
*
|
|
710
|
-
* @returns Array of all subscribers
|
|
711
|
-
*/
|
|
712
477
|
toArray() {
|
|
713
478
|
return this.subscribers ? [...this.subscribers] : [];
|
|
714
479
|
}
|
|
715
480
|
}
|
|
716
|
-
class
|
|
717
|
-
/**
|
|
718
|
-
* Creates a new AtomImpl instance.
|
|
719
|
-
*
|
|
720
|
-
* @param initialValue - The initial value of the atom
|
|
721
|
-
* @param sync - Whether to notify subscribers synchronously
|
|
722
|
-
*/
|
|
481
|
+
class ue extends W {
|
|
723
482
|
constructor(e, t) {
|
|
724
|
-
|
|
483
|
+
super(), this._isNotificationScheduled = !1, this._value = e, this._functionSubscribersStore = new M(), this._objectSubscribersStore = new M(), this._sync = t, this._notifyTask = this._flushNotifications.bind(this), S.attachDebugInfo(this, "atom", this.id);
|
|
725
484
|
}
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
* This getter automatically tracks dependencies when accessed within
|
|
734
|
-
* a computed or effect context.
|
|
735
|
-
*/
|
|
485
|
+
get _functionSubscribers() {
|
|
486
|
+
return this._functionSubscribersStore;
|
|
487
|
+
}
|
|
488
|
+
get _objectSubscribers() {
|
|
489
|
+
return this._objectSubscribersStore;
|
|
490
|
+
}
|
|
491
|
+
/** Gets value and registers as dependency in current tracking context */
|
|
736
492
|
get value() {
|
|
737
|
-
const e =
|
|
493
|
+
const e = m.getCurrent();
|
|
738
494
|
return e != null && this._track(e), this._value;
|
|
739
495
|
}
|
|
740
|
-
/**
|
|
741
|
-
* Sets a new value and notifies all subscribers if the value changed.
|
|
742
|
-
*
|
|
743
|
-
* @param newValue - The new value to set
|
|
744
|
-
*
|
|
745
|
-
* @remarks
|
|
746
|
-
* Uses Object.is for equality comparison. If the value is unchanged,
|
|
747
|
-
* no notifications are sent. Notifications may be batched unless
|
|
748
|
-
* sync mode is enabled.
|
|
749
|
-
*/
|
|
496
|
+
/** Sets value and notifies subscribers if changed (uses Object.is) */
|
|
750
497
|
set value(e) {
|
|
751
498
|
if (Object.is(this._value, e)) return;
|
|
752
499
|
const t = this._value;
|
|
753
|
-
this.version = this.version + 1 &
|
|
500
|
+
this.version = this.version + 1 & T;
|
|
754
501
|
const s = this.version;
|
|
755
|
-
this._value = e, !(!this.
|
|
502
|
+
this._value = e, !(!this._functionSubscribersStore.hasSubscribers && !this._objectSubscribersStore.hasSubscribers) && this._notify(e, t, s);
|
|
756
503
|
}
|
|
757
|
-
/**
|
|
758
|
-
* Tracks the current context as a dependency of this atom.
|
|
759
|
-
*
|
|
760
|
-
* @param current - The current tracking context (function or object)
|
|
761
|
-
*
|
|
762
|
-
* @remarks
|
|
763
|
-
* Handles both function-based trackers (with optional addDependency method)
|
|
764
|
-
* and object-based trackers (with execute or addDependency methods).
|
|
765
|
-
*/
|
|
766
504
|
_track(e) {
|
|
767
505
|
if (typeof e == "function") {
|
|
768
506
|
const t = e;
|
|
769
|
-
t.addDependency !== void 0 ? t.addDependency(this) : this.
|
|
507
|
+
t.addDependency !== void 0 ? t.addDependency(this) : this._functionSubscribersStore.add(e);
|
|
770
508
|
} else {
|
|
771
509
|
const t = e;
|
|
772
|
-
t.addDependency !== void 0 ? t.addDependency(this) : t.execute !== void 0 && this.
|
|
510
|
+
t.addDependency !== void 0 ? t.addDependency(this) : t.execute !== void 0 && this._objectSubscribersStore.add(t);
|
|
773
511
|
}
|
|
774
512
|
}
|
|
775
|
-
/**
|
|
776
|
-
* Notifies all subscribers of a value change.
|
|
777
|
-
*
|
|
778
|
-
* @param newValue - The new value
|
|
779
|
-
* @param oldValue - The previous value
|
|
780
|
-
* @param currentVersion - The version at the time of change
|
|
781
|
-
*
|
|
782
|
-
* @remarks
|
|
783
|
-
* Notifications are skipped if the version has changed (stale update).
|
|
784
|
-
* Errors from individual subscribers are caught and logged without
|
|
785
|
-
* interrupting other subscribers.
|
|
786
|
-
*/
|
|
787
|
-
/**
|
|
788
|
-
* Schedules a notification.
|
|
789
|
-
* Uses coalescing: if a notification is already scheduled, we update the state
|
|
790
|
-
* but don't schedule a new task. The pending task will see the latest value.
|
|
791
|
-
*/
|
|
792
513
|
_notify(e, t, s) {
|
|
793
|
-
this._isNotificationScheduled || (this._pendingOldValue = t, this._isNotificationScheduled = !0), this._sync && !
|
|
514
|
+
this._isNotificationScheduled || (this._pendingOldValue = t, this._isNotificationScheduled = !0), this._sync && !U.isBatching ? this._flushNotifications() : U.schedule(this._notifyTask);
|
|
794
515
|
}
|
|
795
|
-
/**
|
|
796
|
-
* Executes the pending notifications.
|
|
797
|
-
* Bound to 'this' in constructor to avoid closure allocation.
|
|
798
|
-
*/
|
|
799
516
|
_flushNotifications() {
|
|
800
517
|
if (!this._isNotificationScheduled) return;
|
|
801
518
|
const e = this._pendingOldValue, t = this._value;
|
|
802
|
-
this._pendingOldValue = void 0, this._isNotificationScheduled = !1, this.
|
|
803
|
-
(s) => s(t, e),
|
|
804
|
-
(s) => console.error(new d(a.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED, s))
|
|
805
|
-
), this._objectSubscribers.forEachSafe(
|
|
806
|
-
(s) => s.execute(),
|
|
807
|
-
(s) => console.error(new d(a.ATOM_INDIVIDUAL_SUBSCRIBER_FAILED, s))
|
|
808
|
-
);
|
|
809
|
-
}
|
|
810
|
-
/**
|
|
811
|
-
* Subscribes a listener function or Subscriber object to value changes.
|
|
812
|
-
*
|
|
813
|
-
* @param listener - Function or Subscriber object to call when the value changes
|
|
814
|
-
* @returns An unsubscribe function
|
|
815
|
-
* @throws {AtomError} If listener is not a function or Subscriber
|
|
816
|
-
*
|
|
817
|
-
* @example
|
|
818
|
-
* ```ts
|
|
819
|
-
* const unsub = myAtom.subscribe((newVal, oldVal) => {
|
|
820
|
-
* console.log(`Changed from ${oldVal} to ${newVal}`);
|
|
821
|
-
* });
|
|
822
|
-
* // Later: unsub();
|
|
823
|
-
* ```
|
|
824
|
-
*/
|
|
825
|
-
subscribe(e) {
|
|
826
|
-
if (typeof e == "object" && e !== null && "execute" in e)
|
|
827
|
-
return this._objectSubscribers.add(e);
|
|
828
|
-
if (typeof e != "function")
|
|
829
|
-
throw new d(a.ATOM_SUBSCRIBER_MUST_BE_FUNCTION);
|
|
830
|
-
return this._functionSubscribers.add(e);
|
|
519
|
+
this._pendingOldValue = void 0, this._isNotificationScheduled = !1, this._notifySubscribers(t, e);
|
|
831
520
|
}
|
|
832
|
-
/**
|
|
833
|
-
* Gets the current value without registering as a dependency.
|
|
834
|
-
*
|
|
835
|
-
* @returns The current value
|
|
836
|
-
*
|
|
837
|
-
* @remarks
|
|
838
|
-
* Use this method when you need to read the value without
|
|
839
|
-
* creating a reactive dependency (e.g., in event handlers).
|
|
840
|
-
*/
|
|
521
|
+
/** Gets value without registering as dependency */
|
|
841
522
|
peek() {
|
|
842
523
|
return this._value;
|
|
843
524
|
}
|
|
844
|
-
/**
|
|
845
|
-
* Disposes the atom, clearing all subscribers and releasing resources.
|
|
846
|
-
*
|
|
847
|
-
* @remarks
|
|
848
|
-
* After disposal, the atom should not be used. The value is set to
|
|
849
|
-
* undefined to help with garbage collection.
|
|
850
|
-
*/
|
|
851
525
|
dispose() {
|
|
852
|
-
this.
|
|
853
|
-
}
|
|
854
|
-
/**
|
|
855
|
-
* Gets the total number of active subscribers.
|
|
856
|
-
*
|
|
857
|
-
* @returns The count of function and object subscribers combined
|
|
858
|
-
*/
|
|
859
|
-
subscriberCount() {
|
|
860
|
-
return this._functionSubscribers.size + this._objectSubscribers.size;
|
|
526
|
+
this._functionSubscribersStore.clear(), this._objectSubscribersStore.clear(), this._value = void 0;
|
|
861
527
|
}
|
|
862
528
|
}
|
|
863
|
-
function
|
|
864
|
-
return new
|
|
529
|
+
function _e(i, e = {}) {
|
|
530
|
+
return new ue(i, e.sync ?? !1);
|
|
865
531
|
}
|
|
866
|
-
const
|
|
867
|
-
class
|
|
532
|
+
const _ = Object.freeze([]), b = Object.freeze([]), f = Object.freeze([]);
|
|
533
|
+
class z {
|
|
868
534
|
constructor() {
|
|
869
|
-
this.pool = [], this.maxPoolSize = 50, this.maxReusableCapacity = 256, this.stats =
|
|
535
|
+
this.pool = [], this.maxPoolSize = 50, this.maxReusableCapacity = 256, this.stats = d ? {
|
|
870
536
|
acquired: 0,
|
|
871
537
|
released: 0,
|
|
872
538
|
rejected: { frozen: 0, tooLarge: 0, poolFull: 0 }
|
|
873
539
|
} : null;
|
|
874
540
|
}
|
|
875
541
|
acquire() {
|
|
876
|
-
return
|
|
542
|
+
return d && this.stats && this.stats.acquired++, this.pool.pop() ?? [];
|
|
877
543
|
}
|
|
878
544
|
release(e, t) {
|
|
879
545
|
if (!(t && e === t)) {
|
|
880
546
|
if (Object.isFrozen(e)) {
|
|
881
|
-
|
|
547
|
+
d && this.stats && this.stats.rejected.frozen++;
|
|
882
548
|
return;
|
|
883
549
|
}
|
|
884
550
|
if (e.length > this.maxReusableCapacity) {
|
|
885
|
-
|
|
551
|
+
d && this.stats && this.stats.rejected.tooLarge++;
|
|
886
552
|
return;
|
|
887
553
|
}
|
|
888
554
|
if (this.pool.length >= this.maxPoolSize) {
|
|
889
|
-
|
|
555
|
+
d && this.stats && this.stats.rejected.poolFull++;
|
|
890
556
|
return;
|
|
891
557
|
}
|
|
892
|
-
e.length = 0, this.pool.push(e),
|
|
558
|
+
e.length = 0, this.pool.push(e), d && this.stats && this.stats.released++;
|
|
893
559
|
}
|
|
894
560
|
}
|
|
895
561
|
getStats() {
|
|
896
|
-
if (!
|
|
562
|
+
if (!d || !this.stats) return null;
|
|
897
563
|
const { acquired: e, released: t, rejected: s } = this.stats, n = s.frozen + s.tooLarge + s.poolFull;
|
|
898
564
|
return {
|
|
899
565
|
acquired: e,
|
|
@@ -904,34 +570,47 @@ class $ {
|
|
|
904
570
|
};
|
|
905
571
|
}
|
|
906
572
|
reset() {
|
|
907
|
-
this.pool.length = 0,
|
|
573
|
+
this.pool.length = 0, d && this.stats && (this.stats.acquired = 0, this.stats.released = 0, this.stats.rejected = { frozen: 0, tooLarge: 0, poolFull: 0 });
|
|
908
574
|
}
|
|
909
575
|
}
|
|
910
|
-
const
|
|
911
|
-
|
|
576
|
+
const y = new z(), I = new z(), p = new z();
|
|
577
|
+
function q(i, e, t, s) {
|
|
578
|
+
if (e !== _ && t !== b)
|
|
579
|
+
for (let r = 0; r < e.length; r++) {
|
|
580
|
+
const c = e[r];
|
|
581
|
+
c && (c._tempUnsub = t[r]);
|
|
582
|
+
}
|
|
583
|
+
const n = I.acquire();
|
|
584
|
+
n.length = i.length;
|
|
585
|
+
for (let r = 0; r < i.length; r++) {
|
|
586
|
+
const c = i[r];
|
|
587
|
+
c && (c._tempUnsub ? (n[r] = c._tempUnsub, c._tempUnsub = void 0) : (S.checkCircular(c, s), n[r] = c.subscribe(s)));
|
|
588
|
+
}
|
|
589
|
+
if (e !== _)
|
|
590
|
+
for (let r = 0; r < e.length; r++) {
|
|
591
|
+
const c = e[r];
|
|
592
|
+
c?._tempUnsub && (c._tempUnsub(), c._tempUnsub = void 0);
|
|
593
|
+
}
|
|
594
|
+
return t !== b && I.release(t), n;
|
|
595
|
+
}
|
|
596
|
+
class Z extends W {
|
|
912
597
|
constructor(e, t = {}) {
|
|
913
598
|
if (typeof e != "function")
|
|
914
|
-
throw new
|
|
915
|
-
if (
|
|
916
|
-
|
|
917
|
-
try {
|
|
918
|
-
this._recompute();
|
|
919
|
-
} catch {
|
|
920
|
-
}
|
|
921
|
-
}, this._notifyJob = () => {
|
|
922
|
-
this._functionSubscribers.forEachSafe(
|
|
599
|
+
throw new C(l.COMPUTED_MUST_BE_FUNCTION);
|
|
600
|
+
if (super(), this._value = void 0, this.flags = o.DIRTY | o.IDLE, this._error = null, this._promiseId = 0, this._equal = t.equal ?? Object.is, this._fn = e, this._defaultValue = "defaultValue" in t ? t.defaultValue : X, this._hasDefaultValue = this._defaultValue !== X, this._onError = t.onError ?? null, this.MAX_PROMISE_ID = Number.MAX_SAFE_INTEGER - 1, this._functionSubscribersStore = new M(), this._objectSubscribersStore = new M(), this._dependencies = _, this._dependencyVersions = f, this._unsubscribes = b, this._notifyJob = () => {
|
|
601
|
+
this._functionSubscribersStore.forEachSafe(
|
|
923
602
|
(s) => s(),
|
|
924
603
|
(s) => console.error(s)
|
|
925
|
-
), this.
|
|
604
|
+
), this._objectSubscribersStore.forEachSafe(
|
|
926
605
|
(s) => s.execute(),
|
|
927
606
|
(s) => console.error(s)
|
|
928
607
|
);
|
|
929
608
|
}, this._trackable = Object.assign(() => this._markDirty(), {
|
|
930
609
|
addDependency: (s) => {
|
|
931
610
|
}
|
|
932
|
-
}),
|
|
611
|
+
}), S.attachDebugInfo(this, "computed", this.id), S.enabled) {
|
|
933
612
|
const s = this;
|
|
934
|
-
s.subscriberCount = () => this.
|
|
613
|
+
s.subscriberCount = () => this._functionSubscribersStore.size + this._objectSubscribersStore.size, s.isDirty = () => this._isDirty(), s.dependencies = this._dependencies, s.stateFlags = this._getFlagsAsString();
|
|
935
614
|
}
|
|
936
615
|
if (t.lazy === !1)
|
|
937
616
|
try {
|
|
@@ -939,19 +618,15 @@ class Q {
|
|
|
939
618
|
} catch {
|
|
940
619
|
}
|
|
941
620
|
}
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
if ((this._stateFlags & (h.RESOLVED | h.DIRTY)) === h.RESOLVED)
|
|
945
|
-
return this._registerTracking(), this._value;
|
|
946
|
-
const t = this._computeValue();
|
|
947
|
-
return this._registerTracking(), t;
|
|
621
|
+
get _functionSubscribers() {
|
|
622
|
+
return this._functionSubscribersStore;
|
|
948
623
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
return this.
|
|
624
|
+
get _objectSubscribers() {
|
|
625
|
+
return this._objectSubscribersStore;
|
|
626
|
+
}
|
|
627
|
+
get value() {
|
|
628
|
+
const e = this._computeValue();
|
|
629
|
+
return this._registerTracking(), e;
|
|
955
630
|
}
|
|
956
631
|
peek() {
|
|
957
632
|
return this._value;
|
|
@@ -972,127 +647,97 @@ class Q {
|
|
|
972
647
|
return this._isResolved();
|
|
973
648
|
}
|
|
974
649
|
invalidate() {
|
|
975
|
-
this._markDirty();
|
|
650
|
+
this._markDirty(), this._dependencyVersions !== f && (p.release(this._dependencyVersions), this._dependencyVersions = f);
|
|
976
651
|
}
|
|
977
652
|
dispose() {
|
|
978
|
-
if (this._unsubscribes !==
|
|
653
|
+
if (this._unsubscribes !== b) {
|
|
979
654
|
for (let e = 0; e < this._unsubscribes.length; e++) {
|
|
980
655
|
const t = this._unsubscribes[e];
|
|
981
656
|
t && t();
|
|
982
657
|
}
|
|
983
|
-
I.release(this._unsubscribes), this._unsubscribes =
|
|
658
|
+
I.release(this._unsubscribes), this._unsubscribes = b;
|
|
984
659
|
}
|
|
985
|
-
this._dependencies !==
|
|
660
|
+
this._dependencies !== _ && (y.release(this._dependencies), this._dependencies = _), this._dependencyVersions !== f && (p.release(this._dependencyVersions), this._dependencyVersions = f), this._functionSubscribersStore.clear(), this._objectSubscribersStore.clear(), this.flags = o.DIRTY | o.IDLE, this._error = null, this._value = void 0, this._promiseId = (this._promiseId + 1) % this.MAX_PROMISE_ID;
|
|
986
661
|
}
|
|
987
|
-
//
|
|
662
|
+
// State flag operations
|
|
988
663
|
_isDirty() {
|
|
989
|
-
return (this.
|
|
664
|
+
return (this.flags & o.DIRTY) !== 0;
|
|
990
665
|
}
|
|
991
666
|
_setDirty() {
|
|
992
|
-
this.
|
|
667
|
+
this.flags |= o.DIRTY;
|
|
993
668
|
}
|
|
994
669
|
_clearDirty() {
|
|
995
|
-
this.
|
|
670
|
+
this.flags &= -2;
|
|
996
671
|
}
|
|
997
672
|
_isIdle() {
|
|
998
|
-
return (this.
|
|
673
|
+
return (this.flags & o.IDLE) !== 0;
|
|
999
674
|
}
|
|
1000
675
|
_setIdle() {
|
|
1001
|
-
this.
|
|
676
|
+
this.flags |= o.IDLE, this.flags &= -29;
|
|
1002
677
|
}
|
|
1003
678
|
_isPending() {
|
|
1004
|
-
return (this.
|
|
679
|
+
return (this.flags & o.PENDING) !== 0;
|
|
1005
680
|
}
|
|
1006
681
|
_setPending() {
|
|
1007
|
-
this.
|
|
682
|
+
this.flags |= o.PENDING, this.flags &= -27;
|
|
1008
683
|
}
|
|
1009
684
|
_isResolved() {
|
|
1010
|
-
return (this.
|
|
685
|
+
return (this.flags & o.RESOLVED) !== 0;
|
|
1011
686
|
}
|
|
1012
687
|
_setResolved() {
|
|
1013
|
-
this.
|
|
688
|
+
this.flags |= o.RESOLVED, this.flags &= -87;
|
|
1014
689
|
}
|
|
1015
690
|
_isRejected() {
|
|
1016
|
-
return (this.
|
|
691
|
+
return (this.flags & o.REJECTED) !== 0;
|
|
1017
692
|
}
|
|
1018
693
|
_setRejected() {
|
|
1019
|
-
this.
|
|
694
|
+
this.flags |= o.REJECTED | o.HAS_ERROR, this.flags &= -15;
|
|
1020
695
|
}
|
|
1021
696
|
_isRecomputing() {
|
|
1022
|
-
return (this.
|
|
697
|
+
return (this.flags & o.RECOMPUTING) !== 0;
|
|
1023
698
|
}
|
|
1024
699
|
_setRecomputing(e) {
|
|
1025
|
-
const t =
|
|
1026
|
-
this.
|
|
700
|
+
const t = o.RECOMPUTING;
|
|
701
|
+
this.flags = this.flags & ~t | -Number(e) & t;
|
|
1027
702
|
}
|
|
1028
703
|
_getAsyncState() {
|
|
1029
|
-
return this._isPending() ?
|
|
704
|
+
return this._isPending() ? O.PENDING : this._isResolved() ? O.RESOLVED : this._isRejected() ? O.REJECTED : O.IDLE;
|
|
1030
705
|
}
|
|
1031
706
|
_getFlagsAsString() {
|
|
1032
707
|
const e = [];
|
|
1033
708
|
return this._isDirty() && e.push("DIRTY"), this._isIdle() && e.push("IDLE"), this._isPending() && e.push("PENDING"), this._isResolved() && e.push("RESOLVED"), this._isRejected() && e.push("REJECTED"), this._isRecomputing() && e.push("RECOMPUTING"), e.join(" | ");
|
|
1034
709
|
}
|
|
1035
|
-
// === PRIVATE: Core Computation Logic ===
|
|
1036
710
|
_computeValue() {
|
|
1037
|
-
return this._isRecomputing() ? this._value :
|
|
711
|
+
return this._isRecomputing() ? this._value : ((this._isDirty() || this._isIdle()) && this._recompute(), this._isPending() ? this._handlePending() : this._isRejected() ? this._handleRejected() : this._value);
|
|
1038
712
|
}
|
|
1039
713
|
_recompute() {
|
|
1040
|
-
if (
|
|
1041
|
-
return;
|
|
714
|
+
if (this._isRecomputing()) return;
|
|
1042
715
|
this._setRecomputing(!0);
|
|
1043
|
-
const e = this._dependencies, t =
|
|
1044
|
-
let
|
|
1045
|
-
const
|
|
1046
|
-
|
|
1047
|
-
},
|
|
1048
|
-
this._trackable.addDependency =
|
|
1049
|
-
let
|
|
716
|
+
const e = this._dependencies, t = this._dependencyVersions, s = y.acquire(), n = p.acquire(), r = K();
|
|
717
|
+
let c = 0;
|
|
718
|
+
const x = (h) => {
|
|
719
|
+
h._lastSeenEpoch !== r && (h._lastSeenEpoch = r, c < s.length ? (s[c] = h, n[c] = h.version) : (s.push(h), n.push(h.version)), c++);
|
|
720
|
+
}, D = this._trackable.addDependency;
|
|
721
|
+
this._trackable.addDependency = x;
|
|
722
|
+
let R = !1;
|
|
1050
723
|
try {
|
|
1051
|
-
const
|
|
1052
|
-
if (
|
|
1053
|
-
this.
|
|
724
|
+
const h = m.run(this._trackable, this._fn);
|
|
725
|
+
if (s.length = c, n.length = c, Q(h)) {
|
|
726
|
+
this._unsubscribes = q(s, e, this._unsubscribes, this), this._dependencies = s, this._dependencyVersions = n, R = !0, this._handleAsyncComputation(h), this._setRecomputing(!1);
|
|
1054
727
|
return;
|
|
1055
728
|
}
|
|
1056
|
-
this.
|
|
1057
|
-
} catch (
|
|
1058
|
-
|
|
729
|
+
this._unsubscribes = q(s, e, this._unsubscribes, this), this._dependencies = s, this._dependencyVersions = n, R = !0, this._handleSyncResult(h);
|
|
730
|
+
} catch (h) {
|
|
731
|
+
s.length = c, n.length = c, this._unsubscribes = q(s, e, this._unsubscribes, this), this._dependencies = s, this._dependencyVersions = n, R = !0, this._handleComputationError(h);
|
|
1059
732
|
} finally {
|
|
1060
|
-
this._trackable.addDependency =
|
|
1061
|
-
}
|
|
1062
|
-
}
|
|
1063
|
-
/**
|
|
1064
|
-
* Synchronizes subscriptions based on dependency changes.
|
|
1065
|
-
* O(N) Diff using Epoch.
|
|
1066
|
-
*/
|
|
1067
|
-
/**
|
|
1068
|
-
* Synchronizes subscriptions based on dependency changes using O(N) strategy.
|
|
1069
|
-
* Maps unsubs 1:1 with dependencies array.
|
|
1070
|
-
*/
|
|
1071
|
-
_syncDependencies(e, t, s, n) {
|
|
1072
|
-
if (e !== f && s !== E)
|
|
1073
|
-
for (let c = 0; c < e.length; c++) {
|
|
1074
|
-
const o = e[c];
|
|
1075
|
-
o && (o._tempUnsub = s[c]);
|
|
1076
|
-
}
|
|
1077
|
-
const r = I.acquire();
|
|
1078
|
-
r.length = t.length;
|
|
1079
|
-
for (let c = 0; c < t.length; c++) {
|
|
1080
|
-
const o = t[c];
|
|
1081
|
-
o && (o._tempUnsub ? (r[c] = o._tempUnsub, o._tempUnsub = void 0) : (b.checkCircular(o, this), r[c] = o.subscribe(this)));
|
|
733
|
+
this._trackable.addDependency = D, R ? (e !== _ && y.release(e), t !== f && p.release(t)) : (y.release(s), p.release(n));
|
|
1082
734
|
}
|
|
1083
|
-
if (e !== f)
|
|
1084
|
-
for (let c = 0; c < e.length; c++) {
|
|
1085
|
-
const o = e[c];
|
|
1086
|
-
o?._tempUnsub && (o._tempUnsub(), o._tempUnsub = void 0);
|
|
1087
|
-
}
|
|
1088
|
-
s !== E && I.release(s), this._unsubscribes = r;
|
|
1089
735
|
}
|
|
1090
736
|
_handleSyncResult(e) {
|
|
1091
|
-
|
|
1092
|
-
this._value = e, this._clearDirty(), this._setResolved(), this._error = null, this._setRecomputing(!1), t && this._notifySubscribers();
|
|
737
|
+
(!this._isResolved() || !this._equal(this._value, e)) && (this.version = this.version + 1 & T), this._value = e, this._clearDirty(), this._setResolved(), this._error = null, this._setRecomputing(!1);
|
|
1093
738
|
}
|
|
1094
739
|
_handleAsyncComputation(e) {
|
|
1095
|
-
this._setPending(), this._promiseId = this._promiseId >= this.MAX_PROMISE_ID ? 1 : this._promiseId + 1;
|
|
740
|
+
this._setPending(), this._clearDirty(), this._promiseId = this._promiseId >= this.MAX_PROMISE_ID ? 1 : this._promiseId + 1;
|
|
1096
741
|
const t = this._promiseId;
|
|
1097
742
|
e.then((s) => {
|
|
1098
743
|
t === this._promiseId && this._handleAsyncResolution(s);
|
|
@@ -1101,279 +746,167 @@ class Q {
|
|
|
1101
746
|
});
|
|
1102
747
|
}
|
|
1103
748
|
_handleAsyncResolution(e) {
|
|
1104
|
-
|
|
1105
|
-
this._value = e, this._clearDirty(), this._setResolved(), this._error = null, this._setRecomputing(!1), t && this._notifySubscribers();
|
|
749
|
+
(!this._isResolved() || !this._equal(this._value, e)) && (this.version = this.version + 1 & T), this._value = e, this._clearDirty(), this._setResolved(), this._error = null, this._setRecomputing(!1);
|
|
1106
750
|
}
|
|
1107
751
|
_handleAsyncRejection(e) {
|
|
1108
|
-
const t =
|
|
752
|
+
const t = N(e, C, l.COMPUTED_ASYNC_COMPUTATION_FAILED);
|
|
1109
753
|
if (this._error = t, this._setRejected(), this._clearDirty(), this._setRecomputing(!1), this._onError && typeof this._onError == "function")
|
|
1110
754
|
try {
|
|
1111
755
|
this._onError(t);
|
|
1112
756
|
} catch (s) {
|
|
1113
|
-
console.error(
|
|
757
|
+
console.error(l.CALLBACK_ERROR_IN_ERROR_HANDLER, s);
|
|
1114
758
|
}
|
|
1115
|
-
this._notifySubscribers();
|
|
759
|
+
this._notifySubscribers(void 0, void 0);
|
|
1116
760
|
}
|
|
1117
761
|
_handleComputationError(e) {
|
|
1118
|
-
const t =
|
|
762
|
+
const t = N(e, C, l.COMPUTED_COMPUTATION_FAILED);
|
|
1119
763
|
if (this._error = t, this._setRejected(), this._clearDirty(), this._setRecomputing(!1), this._onError && typeof this._onError == "function")
|
|
1120
764
|
try {
|
|
1121
765
|
this._onError(t);
|
|
1122
766
|
} catch (s) {
|
|
1123
|
-
console.error(
|
|
767
|
+
console.error(l.CALLBACK_ERROR_IN_ERROR_HANDLER, s);
|
|
1124
768
|
}
|
|
1125
769
|
throw t;
|
|
1126
770
|
}
|
|
1127
771
|
_handlePending() {
|
|
1128
772
|
if (this._hasDefaultValue)
|
|
1129
773
|
return this._defaultValue;
|
|
1130
|
-
throw new
|
|
774
|
+
throw new C(l.COMPUTED_ASYNC_PENDING_NO_DEFAULT);
|
|
1131
775
|
}
|
|
1132
776
|
_handleRejected() {
|
|
1133
777
|
if (this._error?.recoverable && this._hasDefaultValue)
|
|
1134
778
|
return this._defaultValue;
|
|
1135
779
|
throw this._error;
|
|
1136
780
|
}
|
|
1137
|
-
|
|
1138
|
-
// (Replaced by _syncDependencies and inline pool logic)
|
|
1139
|
-
// === PRIVATE: Subscriber Management ===
|
|
1140
|
-
/**
|
|
1141
|
-
* Subscriber interface implementation (Zero-Allocation pattern)
|
|
1142
|
-
* Called by dependencies when they change - delegates to _markDirty
|
|
1143
|
-
*/
|
|
781
|
+
/** Subscriber interface - marks dirty on dependency change */
|
|
1144
782
|
execute() {
|
|
1145
783
|
this._markDirty();
|
|
1146
784
|
}
|
|
1147
785
|
_markDirty() {
|
|
1148
|
-
this._isRecomputing() || this._isDirty() || (this._setDirty(), this.
|
|
1149
|
-
}
|
|
1150
|
-
_notifySubscribers() {
|
|
1151
|
-
!this._functionSubscribers.hasSubscribers && !this._objectSubscribers.hasSubscribers || m.schedule(this._notifyJob);
|
|
786
|
+
this._isRecomputing() || this._isDirty() || (this._setDirty(), this._notifyJob());
|
|
1152
787
|
}
|
|
1153
788
|
_registerTracking() {
|
|
1154
|
-
const e =
|
|
789
|
+
const e = m.getCurrent();
|
|
1155
790
|
if (e)
|
|
1156
791
|
if (typeof e == "object" && e !== null && e.addDependency)
|
|
1157
792
|
e.addDependency(this);
|
|
1158
793
|
else if (typeof e == "function") {
|
|
1159
794
|
const t = e;
|
|
1160
|
-
t.addDependency ? t.addDependency(this) : this.
|
|
1161
|
-
} else e.execute && this.
|
|
795
|
+
t.addDependency ? t.addDependency(this) : this._functionSubscribersStore.add(e);
|
|
796
|
+
} else e.execute && this._objectSubscribersStore.add(e);
|
|
1162
797
|
}
|
|
1163
798
|
}
|
|
1164
|
-
Object.freeze(
|
|
1165
|
-
function
|
|
1166
|
-
return new
|
|
799
|
+
Object.freeze(Z.prototype);
|
|
800
|
+
function fe(i, e = {}) {
|
|
801
|
+
return new Z(i, e);
|
|
1167
802
|
}
|
|
1168
|
-
class
|
|
803
|
+
class oe extends J {
|
|
1169
804
|
constructor(e, t = {}) {
|
|
1170
|
-
this.run = () => {
|
|
805
|
+
super(), this.run = () => {
|
|
1171
806
|
if (this.isDisposed)
|
|
1172
|
-
throw new
|
|
1173
|
-
this.execute();
|
|
807
|
+
throw new g(l.EFFECT_MUST_BE_FUNCTION);
|
|
808
|
+
this._dependencyVersions !== f && (p.release(this._dependencyVersions), this._dependencyVersions = f), this.execute();
|
|
1174
809
|
}, this.dispose = () => {
|
|
1175
810
|
if (!this.isDisposed) {
|
|
1176
|
-
if (this._setDisposed(), this._safeCleanup(), this._unsubscribes !==
|
|
811
|
+
if (this._setDisposed(), this._safeCleanup(), this._unsubscribes !== b) {
|
|
1177
812
|
for (let s = 0; s < this._unsubscribes.length; s++) {
|
|
1178
813
|
const n = this._unsubscribes[s];
|
|
1179
814
|
n && n();
|
|
1180
815
|
}
|
|
1181
|
-
I.release(this._unsubscribes), this._unsubscribes =
|
|
816
|
+
I.release(this._unsubscribes), this._unsubscribes = b;
|
|
1182
817
|
}
|
|
1183
|
-
this._dependencies !==
|
|
818
|
+
this._dependencies !== _ && (y.release(this._dependencies), this._dependencies = _), this._dependencyVersions !== f && (p.release(this._dependencyVersions), this._dependencyVersions = f);
|
|
1184
819
|
}
|
|
1185
820
|
}, this.addDependency = (s) => {
|
|
1186
|
-
if (this.isExecuting && this._nextDeps && this._nextUnsubs) {
|
|
821
|
+
if (this.isExecuting && this._nextDeps && this._nextUnsubs && this._nextVersions) {
|
|
1187
822
|
const n = s, r = this._currentEpoch;
|
|
1188
823
|
if (n._lastSeenEpoch === r) return;
|
|
1189
|
-
n._lastSeenEpoch = r, this._nextDeps.push(n), n._tempUnsub ? (this._nextUnsubs.push(n._tempUnsub), n._tempUnsub = void 0) : this._subscribeTo(n);
|
|
824
|
+
n._lastSeenEpoch = r, this._nextDeps.push(n), this._nextVersions.push(n.version), n._tempUnsub ? (this._nextUnsubs.push(n._tempUnsub), n._tempUnsub = void 0) : this._subscribeTo(n);
|
|
1190
825
|
}
|
|
1191
826
|
}, this.execute = () => {
|
|
1192
|
-
if (this.isDisposed || this.isExecuting) return;
|
|
827
|
+
if (this.isDisposed || this.isExecuting || !this._shouldExecute()) return;
|
|
1193
828
|
this._checkInfiniteLoop(), this._setExecuting(!0), this._safeCleanup();
|
|
1194
|
-
const s = this._dependencies, n = this.
|
|
1195
|
-
if (s !==
|
|
829
|
+
const s = this._dependencies, n = this._dependencyVersions, r = this._unsubscribes, c = y.acquire(), x = p.acquire(), D = I.acquire(), R = K();
|
|
830
|
+
if (s !== _ && r !== b)
|
|
1196
831
|
for (let u = 0; u < s.length; u++) {
|
|
1197
|
-
const
|
|
1198
|
-
|
|
832
|
+
const a = s[u];
|
|
833
|
+
a && (a._tempUnsub = r[u]);
|
|
1199
834
|
}
|
|
1200
|
-
this._nextDeps =
|
|
1201
|
-
let
|
|
835
|
+
this._nextDeps = c, this._nextVersions = x, this._nextUnsubs = D, this._currentEpoch = R;
|
|
836
|
+
let h = !1;
|
|
1202
837
|
try {
|
|
1203
|
-
const u =
|
|
1204
|
-
this._dependencies =
|
|
1205
|
-
!this.isDisposed && typeof
|
|
1206
|
-
}).catch((
|
|
1207
|
-
console.error(
|
|
838
|
+
const u = m.run(this, this._fn);
|
|
839
|
+
this._dependencies = c, this._dependencyVersions = x, this._unsubscribes = D, h = !0, this._checkLoopWarnings(), Q(u) ? u.then((a) => {
|
|
840
|
+
!this.isDisposed && typeof a == "function" && (this._cleanup = a);
|
|
841
|
+
}).catch((a) => {
|
|
842
|
+
console.error(N(a, g, l.EFFECT_EXECUTION_FAILED));
|
|
1208
843
|
}) : this._cleanup = typeof u == "function" ? u : null;
|
|
1209
844
|
} catch (u) {
|
|
1210
|
-
|
|
845
|
+
h = !0, console.error(N(u, g, l.EFFECT_EXECUTION_FAILED)), this._cleanup = null;
|
|
1211
846
|
} finally {
|
|
1212
|
-
if (this._setExecuting(!1), this._nextDeps = null, this._nextUnsubs = null,
|
|
1213
|
-
if (s !==
|
|
847
|
+
if (this._setExecuting(!1), this._nextDeps = null, this._nextVersions = null, this._nextUnsubs = null, h) {
|
|
848
|
+
if (s !== _) {
|
|
1214
849
|
for (let u = 0; u < s.length; u++) {
|
|
1215
|
-
const
|
|
1216
|
-
|
|
850
|
+
const a = s[u];
|
|
851
|
+
a?._tempUnsub && (a._tempUnsub(), a._tempUnsub = void 0);
|
|
1217
852
|
}
|
|
1218
|
-
|
|
853
|
+
y.release(s);
|
|
1219
854
|
}
|
|
1220
|
-
|
|
855
|
+
r !== b && I.release(r), n !== f && p.release(n);
|
|
1221
856
|
} else {
|
|
1222
|
-
|
|
1223
|
-
for (let u = 0; u <
|
|
1224
|
-
|
|
1225
|
-
if (I.release(
|
|
857
|
+
y.release(c), p.release(x);
|
|
858
|
+
for (let u = 0; u < D.length; u++)
|
|
859
|
+
D[u]?.();
|
|
860
|
+
if (I.release(D), s !== _)
|
|
1226
861
|
for (let u = 0; u < s.length; u++) {
|
|
1227
|
-
const
|
|
1228
|
-
|
|
862
|
+
const a = s[u];
|
|
863
|
+
a && (a._tempUnsub = void 0);
|
|
1229
864
|
}
|
|
1230
865
|
}
|
|
1231
866
|
}
|
|
1232
|
-
}, this.
|
|
867
|
+
}, this._currentEpoch = -1, this._lastFlushEpoch = -1, this._executionsInEpoch = 0, this._fn = e, this._sync = t.sync ?? !1, this._maxExecutions = t.maxExecutionsPerSecond ?? P.MAX_EXECUTIONS_PER_SECOND, this._maxExecutionsPerFlush = t.maxExecutionsPerFlush ?? P.MAX_EXECUTIONS_PER_EFFECT, this._trackModifications = t.trackModifications ?? !1, this._cleanup = null, this._dependencies = _, this._dependencyVersions = f, this._unsubscribes = b, this._nextDeps = null, this._nextVersions = null, this._nextUnsubs = null, this._history = d ? [] : null, this._executionCount = 0, S.attachDebugInfo(this, "effect", this.id);
|
|
1233
868
|
}
|
|
1234
|
-
/**
|
|
1235
|
-
* Synchronizes subscriptions by unsubscribing from removed dependencies.
|
|
1236
|
-
* Uses epoch-based O(N) diff to identify stale dependencies.
|
|
1237
|
-
*
|
|
1238
|
-
* @param prevDeps - Previous dependency array
|
|
1239
|
-
* @param epoch - Current execution epoch for staleness detection
|
|
1240
|
-
*/
|
|
1241
|
-
// _syncDependencies removed (inline logic in execute)
|
|
1242
869
|
_subscribeTo(e) {
|
|
1243
870
|
try {
|
|
1244
871
|
const t = e.subscribe(() => {
|
|
1245
|
-
this._trackModifications && this.isExecuting && (e._modifiedAtEpoch = this._currentEpoch), this._sync ? this.execute() :
|
|
872
|
+
this._trackModifications && this.isExecuting && (e._modifiedAtEpoch = this._currentEpoch), this._sync ? this.execute() : U.schedule(this.execute);
|
|
1246
873
|
});
|
|
1247
874
|
this._nextUnsubs && this._nextUnsubs.push(t);
|
|
1248
875
|
} catch (t) {
|
|
1249
|
-
console.error(
|
|
876
|
+
console.error(N(t, g, l.EFFECT_EXECUTION_FAILED)), this._nextUnsubs && this._nextUnsubs.push(() => {
|
|
1250
877
|
});
|
|
1251
878
|
}
|
|
1252
879
|
}
|
|
1253
|
-
/**
|
|
1254
|
-
* Indicates whether this effect has been disposed.
|
|
1255
|
-
*
|
|
1256
|
-
* @returns `true` if the effect has been disposed, `false` otherwise
|
|
1257
|
-
*
|
|
1258
|
-
* @remarks
|
|
1259
|
-
* A disposed effect will not execute and cannot be reactivated.
|
|
1260
|
-
* Use this property to check if the effect is still active before
|
|
1261
|
-
* performing operations that depend on it.
|
|
1262
|
-
*
|
|
1263
|
-
* @example
|
|
1264
|
-
* ```typescript
|
|
1265
|
-
* const fx = effect(() => console.log(counter.value));
|
|
1266
|
-
* console.log(fx.isDisposed); // false
|
|
1267
|
-
* fx.dispose();
|
|
1268
|
-
* console.log(fx.isDisposed); // true
|
|
1269
|
-
* ```
|
|
1270
|
-
*/
|
|
1271
880
|
get isDisposed() {
|
|
1272
|
-
return (this.
|
|
881
|
+
return (this.flags & F.DISPOSED) !== 0;
|
|
1273
882
|
}
|
|
1274
|
-
/**
|
|
1275
|
-
* Returns the total number of times this effect has been executed.
|
|
1276
|
-
*
|
|
1277
|
-
* @returns The cumulative execution count since the effect was created
|
|
1278
|
-
*
|
|
1279
|
-
* @remarks
|
|
1280
|
-
* This counter is useful for debugging, testing, and monitoring
|
|
1281
|
-
* effect behavior. It increments on every execution, regardless
|
|
1282
|
-
* of whether the execution succeeds or fails.
|
|
1283
|
-
*
|
|
1284
|
-
* @example
|
|
1285
|
-
* ```typescript
|
|
1286
|
-
* const fx = effect(() => console.log(counter.value));
|
|
1287
|
-
* console.log(fx.executionCount); // 1 (initial execution)
|
|
1288
|
-
* counter.value = 10;
|
|
1289
|
-
* console.log(fx.executionCount); // 2
|
|
1290
|
-
* ```
|
|
1291
|
-
*/
|
|
1292
883
|
get executionCount() {
|
|
1293
884
|
return this._executionCount;
|
|
1294
885
|
}
|
|
1295
|
-
/**
|
|
1296
|
-
* Indicates whether this effect is currently executing.
|
|
1297
|
-
*
|
|
1298
|
-
* @returns `true` if the effect is mid-execution, `false` otherwise
|
|
1299
|
-
*
|
|
1300
|
-
* @remarks
|
|
1301
|
-
* This property is used internally to prevent re-entrant execution
|
|
1302
|
-
* (an effect triggering itself during its own execution). It can
|
|
1303
|
-
* also be useful for debugging to understand the effect's state.
|
|
1304
|
-
*
|
|
1305
|
-
* @example
|
|
1306
|
-
* ```typescript
|
|
1307
|
-
* const fx = effect(() => {
|
|
1308
|
-
* console.log('executing:', fx.isExecuting); // true
|
|
1309
|
-
* });
|
|
1310
|
-
* console.log(fx.isExecuting); // false (after execution completes)
|
|
1311
|
-
* ```
|
|
1312
|
-
*/
|
|
1313
886
|
get isExecuting() {
|
|
1314
|
-
return (this.
|
|
887
|
+
return (this.flags & F.EXECUTING) !== 0;
|
|
1315
888
|
}
|
|
1316
|
-
/**
|
|
1317
|
-
* Sets the disposed flag on this effect.
|
|
1318
|
-
*
|
|
1319
|
-
* @remarks
|
|
1320
|
-
* This is a low-level method that only sets the bit flag.
|
|
1321
|
-
* Use the public `dispose()` method for proper cleanup.
|
|
1322
|
-
*
|
|
1323
|
-
* @internal
|
|
1324
|
-
*/
|
|
1325
889
|
_setDisposed() {
|
|
1326
|
-
this.
|
|
890
|
+
this.flags |= F.DISPOSED;
|
|
1327
891
|
}
|
|
1328
|
-
/**
|
|
1329
|
-
* Sets or clears the executing flag on this effect.
|
|
1330
|
-
*
|
|
1331
|
-
* @param value - `true` to mark as executing, `false` to clear
|
|
1332
|
-
*
|
|
1333
|
-
* @remarks
|
|
1334
|
-
* Uses bitwise operations for efficient flag manipulation.
|
|
1335
|
-
* This flag prevents re-entrant execution of the effect.
|
|
1336
|
-
*
|
|
1337
|
-
* @internal
|
|
1338
|
-
*/
|
|
1339
892
|
_setExecuting(e) {
|
|
1340
893
|
const t = F.EXECUTING;
|
|
1341
|
-
this.
|
|
894
|
+
this.flags = this.flags & ~t | -Number(e) & t;
|
|
1342
895
|
}
|
|
1343
|
-
/**
|
|
1344
|
-
* Safely executes the cleanup function if one exists.
|
|
1345
|
-
*
|
|
1346
|
-
* @remarks
|
|
1347
|
-
* This method:
|
|
1348
|
-
* - Checks if a cleanup function exists and is callable
|
|
1349
|
-
* - Wraps the cleanup call in a try-catch to prevent cleanup errors
|
|
1350
|
-
* from breaking the effect lifecycle
|
|
1351
|
-
* - Logs any cleanup errors to the console
|
|
1352
|
-
* - Clears the cleanup reference after execution
|
|
1353
|
-
*
|
|
1354
|
-
* @internal
|
|
1355
|
-
*/
|
|
1356
896
|
_safeCleanup() {
|
|
1357
897
|
if (this._cleanup && typeof this._cleanup == "function") {
|
|
1358
898
|
try {
|
|
1359
899
|
this._cleanup();
|
|
1360
900
|
} catch (e) {
|
|
1361
|
-
console.error(
|
|
901
|
+
console.error(N(e, g, l.EFFECT_CLEANUP_FAILED));
|
|
1362
902
|
}
|
|
1363
903
|
this._cleanup = null;
|
|
1364
904
|
}
|
|
1365
905
|
}
|
|
1366
|
-
/**
|
|
1367
|
-
* Checks for infinite loop conditions using epoch-based detection.
|
|
1368
|
-
* Falls back to timestamp-based detection in development mode.
|
|
1369
|
-
*
|
|
1370
|
-
* @throws {EffectError} When infinite loop is detected
|
|
1371
|
-
* @internal
|
|
1372
|
-
*/
|
|
1373
906
|
_checkInfiniteLoop() {
|
|
1374
|
-
if (this._lastFlushEpoch !==
|
|
907
|
+
if (this._lastFlushEpoch !== v && (this._lastFlushEpoch = v, this._executionsInEpoch = 0), this._executionsInEpoch++, this._executionsInEpoch > this._maxExecutionsPerFlush && this._throwInfiniteLoopError("per-effect"), ne() > P.MAX_EXECUTIONS_PER_FLUSH && this._throwInfiniteLoopError("global"), this._executionCount++, this._history) {
|
|
1375
908
|
const e = Date.now();
|
|
1376
|
-
this._history.push(e), this._history.length >
|
|
909
|
+
this._history.push(e), this._history.length > P.MAX_EXECUTIONS_PER_SECOND + 10 && this._history.shift(), this._checkTimestampLoop(e);
|
|
1377
910
|
}
|
|
1378
911
|
}
|
|
1379
912
|
_checkTimestampLoop(e) {
|
|
@@ -1384,83 +917,87 @@ class te {
|
|
|
1384
917
|
for (let r = t.length - 1; r >= 0 && !(t[r] < s); r--)
|
|
1385
918
|
n++;
|
|
1386
919
|
if (n > this._maxExecutions) {
|
|
1387
|
-
const r = new
|
|
920
|
+
const r = new g(
|
|
1388
921
|
`Effect executed ${n} times within 1 second. Infinite loop suspected`
|
|
1389
922
|
);
|
|
1390
|
-
if (this.dispose(), console.error(r),
|
|
923
|
+
if (this.dispose(), console.error(r), d)
|
|
1391
924
|
throw r;
|
|
1392
925
|
}
|
|
1393
926
|
}
|
|
1394
927
|
_throwInfiniteLoopError(e) {
|
|
1395
|
-
const t = new
|
|
1396
|
-
`Infinite loop detected (${e}): effect executed ${this._executionsInEpoch} times in current flush. Total executions in flush: ${
|
|
928
|
+
const t = new g(
|
|
929
|
+
`Infinite loop detected (${e}): effect executed ${this._executionsInEpoch} times in current flush. Total executions in flush: ${k}`
|
|
1397
930
|
);
|
|
1398
931
|
throw this.dispose(), console.error(t), t;
|
|
1399
932
|
}
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
933
|
+
_shouldExecute() {
|
|
934
|
+
if (this._dependencies === _ || this._dependencyVersions === f) return !0;
|
|
935
|
+
for (let e = 0; e < this._dependencies.length; e++) {
|
|
936
|
+
const t = this._dependencies[e];
|
|
937
|
+
if (t) {
|
|
938
|
+
if ("value" in t)
|
|
939
|
+
try {
|
|
940
|
+
ce(() => t.value);
|
|
941
|
+
} catch {
|
|
942
|
+
return !0;
|
|
943
|
+
}
|
|
944
|
+
if (t.version !== this._dependencyVersions[e])
|
|
945
|
+
return !0;
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
return !1;
|
|
949
|
+
}
|
|
1413
950
|
_checkLoopWarnings() {
|
|
1414
|
-
if (this._trackModifications &&
|
|
951
|
+
if (this._trackModifications && S.enabled) {
|
|
1415
952
|
const e = this._dependencies;
|
|
1416
953
|
for (let t = 0; t < e.length; t++) {
|
|
1417
954
|
const s = e[t];
|
|
1418
|
-
s && s._modifiedAtEpoch === this._currentEpoch &&
|
|
955
|
+
s && s._modifiedAtEpoch === this._currentEpoch && S.warn(
|
|
1419
956
|
!0,
|
|
1420
|
-
`Effect is reading a dependency (${
|
|
957
|
+
`Effect is reading a dependency (${S.getDebugName(s) || "unknown"}) that it just modified. Infinite loop may occur`
|
|
1421
958
|
);
|
|
1422
959
|
}
|
|
1423
960
|
}
|
|
1424
961
|
}
|
|
1425
962
|
}
|
|
1426
|
-
function
|
|
963
|
+
function de(i, e = {}) {
|
|
1427
964
|
if (typeof i != "function")
|
|
1428
|
-
throw new
|
|
1429
|
-
const t = new
|
|
965
|
+
throw new g(l.EFFECT_MUST_BE_FUNCTION);
|
|
966
|
+
const t = new oe(i, e);
|
|
1430
967
|
return t.execute(), t;
|
|
1431
968
|
}
|
|
1432
|
-
function
|
|
969
|
+
function he(i) {
|
|
1433
970
|
return i !== null && typeof i == "object" && "value" in i && "subscribe" in i && typeof i.subscribe == "function";
|
|
1434
971
|
}
|
|
1435
|
-
function
|
|
1436
|
-
if (
|
|
1437
|
-
const e =
|
|
972
|
+
function Ee(i) {
|
|
973
|
+
if (S.enabled) {
|
|
974
|
+
const e = S.getDebugType(i);
|
|
1438
975
|
if (e)
|
|
1439
976
|
return e === "computed";
|
|
1440
977
|
}
|
|
1441
|
-
return
|
|
978
|
+
return he(i) && "invalidate" in i && typeof i.invalidate == "function";
|
|
1442
979
|
}
|
|
1443
|
-
function
|
|
980
|
+
function be(i) {
|
|
1444
981
|
return i !== null && typeof i == "object" && "dispose" in i && "run" in i && typeof i.dispose == "function" && typeof i.run == "function";
|
|
1445
982
|
}
|
|
1446
983
|
export {
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
984
|
+
O as AsyncState,
|
|
985
|
+
E as AtomError,
|
|
986
|
+
C as ComputedError,
|
|
987
|
+
j as DEBUG_CONFIG,
|
|
988
|
+
S as DEBUG_RUNTIME,
|
|
989
|
+
g as EffectError,
|
|
990
|
+
le as POOL_CONFIG,
|
|
991
|
+
P as SCHEDULER_CONFIG,
|
|
992
|
+
A as SchedulerError,
|
|
993
|
+
_e as atom,
|
|
994
|
+
ae as batch,
|
|
995
|
+
fe as computed,
|
|
996
|
+
de as effect,
|
|
997
|
+
he as isAtom,
|
|
998
|
+
Ee as isComputed,
|
|
999
|
+
be as isEffect,
|
|
1000
|
+
U as scheduler,
|
|
1001
|
+
ce as untracked
|
|
1465
1002
|
};
|
|
1466
1003
|
//# sourceMappingURL=index.mjs.map
|