@but212/atom-effect 0.3.2 → 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 +8 -8
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +17 -267
- package/dist/index.mjs +352 -822
- 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 I extends d {
|
|
|
70
70
|
super(e, t, !0), this.name = "ComputedError";
|
|
71
71
|
}
|
|
72
72
|
}
|
|
73
|
-
class g extends
|
|
73
|
+
class g extends E {
|
|
74
74
|
/**
|
|
75
75
|
* Creates a new EffectError
|
|
76
76
|
* @param message - Error message
|
|
@@ -80,7 +80,7 @@ class g 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
|
+
}
|
|
194
245
|
}
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
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
|
+
}
|
|
285
|
+
}
|
|
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
397
|
const m = {
|
|
402
|
-
/** @inheritdoc */
|
|
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 m = {
|
|
|
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
|
|
414
|
+
throw new E("Untracked callback must be a function");
|
|
425
415
|
const e = m.current;
|
|
426
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
422
|
m.current = e;
|
|
433
423
|
}
|
|
434
424
|
}
|
|
435
|
-
|
|
436
|
-
function K(i) {
|
|
437
|
-
return i !== null && typeof i == "object" && "dependencies" in i && Array.isArray(i.dependencies);
|
|
438
|
-
}
|
|
439
|
-
let j = 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 I("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
|
-
}
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
const b = {
|
|
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 I("Direct circular dependency detected");
|
|
518
|
-
this.enabled && (j++, Y(i, e, j));
|
|
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[v] = `${e}_${t}`, s[W] = t, s[L] = 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" && v in i)
|
|
560
|
-
return i[v];
|
|
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" && L in i)
|
|
578
|
-
return i[L];
|
|
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
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,28 +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
|
-
this.
|
|
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(
|
|
917
602
|
(s) => s(),
|
|
918
603
|
(s) => console.error(s)
|
|
919
|
-
), this.
|
|
604
|
+
), this._objectSubscribersStore.forEachSafe(
|
|
920
605
|
(s) => s.execute(),
|
|
921
606
|
(s) => console.error(s)
|
|
922
607
|
);
|
|
923
608
|
}, this._trackable = Object.assign(() => this._markDirty(), {
|
|
924
609
|
addDependency: (s) => {
|
|
925
610
|
}
|
|
926
|
-
}),
|
|
611
|
+
}), S.attachDebugInfo(this, "computed", this.id), S.enabled) {
|
|
927
612
|
const s = this;
|
|
928
|
-
s.subscriberCount = () => this.
|
|
613
|
+
s.subscriberCount = () => this._functionSubscribersStore.size + this._objectSubscribersStore.size, s.isDirty = () => this._isDirty(), s.dependencies = this._dependencies, s.stateFlags = this._getFlagsAsString();
|
|
929
614
|
}
|
|
930
615
|
if (t.lazy === !1)
|
|
931
616
|
try {
|
|
@@ -933,19 +618,15 @@ class Q {
|
|
|
933
618
|
} catch {
|
|
934
619
|
}
|
|
935
620
|
}
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
if ((this._stateFlags & (h.RESOLVED | h.DIRTY)) === h.RESOLVED)
|
|
939
|
-
return this._registerTracking(), this._value;
|
|
940
|
-
const t = this._computeValue();
|
|
941
|
-
return this._registerTracking(), t;
|
|
621
|
+
get _functionSubscribers() {
|
|
622
|
+
return this._functionSubscribersStore;
|
|
942
623
|
}
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
return this.
|
|
624
|
+
get _objectSubscribers() {
|
|
625
|
+
return this._objectSubscribersStore;
|
|
626
|
+
}
|
|
627
|
+
get value() {
|
|
628
|
+
const e = this._computeValue();
|
|
629
|
+
return this._registerTracking(), e;
|
|
949
630
|
}
|
|
950
631
|
peek() {
|
|
951
632
|
return this._value;
|
|
@@ -966,126 +647,97 @@ class Q {
|
|
|
966
647
|
return this._isResolved();
|
|
967
648
|
}
|
|
968
649
|
invalidate() {
|
|
969
|
-
this._markDirty();
|
|
650
|
+
this._markDirty(), this._dependencyVersions !== f && (p.release(this._dependencyVersions), this._dependencyVersions = f);
|
|
970
651
|
}
|
|
971
652
|
dispose() {
|
|
972
|
-
if (this._unsubscribes !==
|
|
653
|
+
if (this._unsubscribes !== b) {
|
|
973
654
|
for (let e = 0; e < this._unsubscribes.length; e++) {
|
|
974
655
|
const t = this._unsubscribes[e];
|
|
975
656
|
t && t();
|
|
976
657
|
}
|
|
977
|
-
|
|
658
|
+
I.release(this._unsubscribes), this._unsubscribes = b;
|
|
978
659
|
}
|
|
979
|
-
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;
|
|
980
661
|
}
|
|
981
|
-
//
|
|
662
|
+
// State flag operations
|
|
982
663
|
_isDirty() {
|
|
983
|
-
return (this.
|
|
664
|
+
return (this.flags & o.DIRTY) !== 0;
|
|
984
665
|
}
|
|
985
666
|
_setDirty() {
|
|
986
|
-
this.
|
|
667
|
+
this.flags |= o.DIRTY;
|
|
987
668
|
}
|
|
988
669
|
_clearDirty() {
|
|
989
|
-
this.
|
|
670
|
+
this.flags &= -2;
|
|
990
671
|
}
|
|
991
672
|
_isIdle() {
|
|
992
|
-
return (this.
|
|
673
|
+
return (this.flags & o.IDLE) !== 0;
|
|
993
674
|
}
|
|
994
675
|
_setIdle() {
|
|
995
|
-
this.
|
|
676
|
+
this.flags |= o.IDLE, this.flags &= -29;
|
|
996
677
|
}
|
|
997
678
|
_isPending() {
|
|
998
|
-
return (this.
|
|
679
|
+
return (this.flags & o.PENDING) !== 0;
|
|
999
680
|
}
|
|
1000
681
|
_setPending() {
|
|
1001
|
-
this.
|
|
682
|
+
this.flags |= o.PENDING, this.flags &= -27;
|
|
1002
683
|
}
|
|
1003
684
|
_isResolved() {
|
|
1004
|
-
return (this.
|
|
685
|
+
return (this.flags & o.RESOLVED) !== 0;
|
|
1005
686
|
}
|
|
1006
687
|
_setResolved() {
|
|
1007
|
-
this.
|
|
688
|
+
this.flags |= o.RESOLVED, this.flags &= -87;
|
|
1008
689
|
}
|
|
1009
690
|
_isRejected() {
|
|
1010
|
-
return (this.
|
|
691
|
+
return (this.flags & o.REJECTED) !== 0;
|
|
1011
692
|
}
|
|
1012
693
|
_setRejected() {
|
|
1013
|
-
this.
|
|
694
|
+
this.flags |= o.REJECTED | o.HAS_ERROR, this.flags &= -15;
|
|
1014
695
|
}
|
|
1015
696
|
_isRecomputing() {
|
|
1016
|
-
return (this.
|
|
697
|
+
return (this.flags & o.RECOMPUTING) !== 0;
|
|
1017
698
|
}
|
|
1018
699
|
_setRecomputing(e) {
|
|
1019
|
-
const t =
|
|
1020
|
-
this.
|
|
700
|
+
const t = o.RECOMPUTING;
|
|
701
|
+
this.flags = this.flags & ~t | -Number(e) & t;
|
|
1021
702
|
}
|
|
1022
703
|
_getAsyncState() {
|
|
1023
|
-
return this._isPending() ?
|
|
704
|
+
return this._isPending() ? O.PENDING : this._isResolved() ? O.RESOLVED : this._isRejected() ? O.REJECTED : O.IDLE;
|
|
1024
705
|
}
|
|
1025
706
|
_getFlagsAsString() {
|
|
1026
707
|
const e = [];
|
|
1027
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(" | ");
|
|
1028
709
|
}
|
|
1029
|
-
// === PRIVATE: Core Computation Logic ===
|
|
1030
710
|
_computeValue() {
|
|
1031
|
-
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);
|
|
1032
712
|
}
|
|
1033
713
|
_recompute() {
|
|
1034
|
-
if (
|
|
1035
|
-
return;
|
|
714
|
+
if (this._isRecomputing()) return;
|
|
1036
715
|
this._setRecomputing(!0);
|
|
1037
|
-
const e = this._dependencies, t =
|
|
1038
|
-
let
|
|
1039
|
-
const
|
|
1040
|
-
|
|
1041
|
-
},
|
|
1042
|
-
this._trackable.addDependency =
|
|
1043
|
-
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;
|
|
1044
723
|
try {
|
|
1045
|
-
const
|
|
1046
|
-
if (
|
|
1047
|
-
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);
|
|
1048
727
|
return;
|
|
1049
728
|
}
|
|
1050
|
-
this.
|
|
1051
|
-
} catch (
|
|
1052
|
-
|
|
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);
|
|
1053
732
|
} finally {
|
|
1054
|
-
this._trackable.addDependency =
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
/**
|
|
1058
|
-
* Synchronizes subscriptions based on dependency changes.
|
|
1059
|
-
* O(N) Diff using Epoch.
|
|
1060
|
-
*/
|
|
1061
|
-
/**
|
|
1062
|
-
* Synchronizes subscriptions based on dependency changes using O(N) strategy.
|
|
1063
|
-
* Maps unsubs 1:1 with dependencies array.
|
|
1064
|
-
*/
|
|
1065
|
-
_syncDependencies(e, t, s, n) {
|
|
1066
|
-
if (e !== f && s !== E)
|
|
1067
|
-
for (let c = 0; c < e.length; c++) {
|
|
1068
|
-
const o = e[c];
|
|
1069
|
-
o && (o._tempUnsub = s[c]);
|
|
1070
|
-
}
|
|
1071
|
-
const r = y.acquire();
|
|
1072
|
-
r.length = t.length;
|
|
1073
|
-
for (let c = 0; c < t.length; c++) {
|
|
1074
|
-
const o = t[c];
|
|
1075
|
-
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));
|
|
1076
734
|
}
|
|
1077
|
-
if (e !== f)
|
|
1078
|
-
for (let c = 0; c < e.length; c++) {
|
|
1079
|
-
const o = e[c];
|
|
1080
|
-
o?._tempUnsub && (o._tempUnsub(), o._tempUnsub = void 0);
|
|
1081
|
-
}
|
|
1082
|
-
s !== E && y.release(s), this._unsubscribes = r;
|
|
1083
735
|
}
|
|
1084
736
|
_handleSyncResult(e) {
|
|
1085
|
-
(!this._isResolved() || !this._equal(this._value, e)) && (this.version = this.version + 1 &
|
|
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);
|
|
1086
738
|
}
|
|
1087
739
|
_handleAsyncComputation(e) {
|
|
1088
|
-
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;
|
|
1089
741
|
const t = this._promiseId;
|
|
1090
742
|
e.then((s) => {
|
|
1091
743
|
t === this._promiseId && this._handleAsyncResolution(s);
|
|
@@ -1094,68 +746,44 @@ class Q {
|
|
|
1094
746
|
});
|
|
1095
747
|
}
|
|
1096
748
|
_handleAsyncResolution(e) {
|
|
1097
|
-
(!this._isResolved() || !this._equal(this._value, e)) && (this.version = this.version + 1 &
|
|
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);
|
|
1098
750
|
}
|
|
1099
751
|
_handleAsyncRejection(e) {
|
|
1100
|
-
const t =
|
|
752
|
+
const t = N(e, C, l.COMPUTED_ASYNC_COMPUTATION_FAILED);
|
|
1101
753
|
if (this._error = t, this._setRejected(), this._clearDirty(), this._setRecomputing(!1), this._onError && typeof this._onError == "function")
|
|
1102
754
|
try {
|
|
1103
755
|
this._onError(t);
|
|
1104
756
|
} catch (s) {
|
|
1105
|
-
console.error(
|
|
757
|
+
console.error(l.CALLBACK_ERROR_IN_ERROR_HANDLER, s);
|
|
1106
758
|
}
|
|
1107
|
-
this._notifySubscribers();
|
|
759
|
+
this._notifySubscribers(void 0, void 0);
|
|
1108
760
|
}
|
|
1109
761
|
_handleComputationError(e) {
|
|
1110
|
-
const t =
|
|
762
|
+
const t = N(e, C, l.COMPUTED_COMPUTATION_FAILED);
|
|
1111
763
|
if (this._error = t, this._setRejected(), this._clearDirty(), this._setRecomputing(!1), this._onError && typeof this._onError == "function")
|
|
1112
764
|
try {
|
|
1113
765
|
this._onError(t);
|
|
1114
766
|
} catch (s) {
|
|
1115
|
-
console.error(
|
|
767
|
+
console.error(l.CALLBACK_ERROR_IN_ERROR_HANDLER, s);
|
|
1116
768
|
}
|
|
1117
769
|
throw t;
|
|
1118
770
|
}
|
|
1119
771
|
_handlePending() {
|
|
1120
772
|
if (this._hasDefaultValue)
|
|
1121
773
|
return this._defaultValue;
|
|
1122
|
-
throw new
|
|
774
|
+
throw new C(l.COMPUTED_ASYNC_PENDING_NO_DEFAULT);
|
|
1123
775
|
}
|
|
1124
776
|
_handleRejected() {
|
|
1125
777
|
if (this._error?.recoverable && this._hasDefaultValue)
|
|
1126
778
|
return this._defaultValue;
|
|
1127
779
|
throw this._error;
|
|
1128
780
|
}
|
|
1129
|
-
|
|
1130
|
-
// (Replaced by _syncDependencies and inline pool logic)
|
|
1131
|
-
// === PRIVATE: Subscriber Management ===
|
|
1132
|
-
/**
|
|
1133
|
-
* Subscriber interface implementation (Zero-Allocation pattern)
|
|
1134
|
-
* Called by dependencies when they change - delegates to _markDirty
|
|
1135
|
-
*/
|
|
781
|
+
/** Subscriber interface - marks dirty on dependency change */
|
|
1136
782
|
execute() {
|
|
1137
783
|
this._markDirty();
|
|
1138
784
|
}
|
|
1139
|
-
/**
|
|
1140
|
-
* Push-State, Pull-Value pattern:
|
|
1141
|
-
* Marks this computed as dirty and propagates to all subscribers.
|
|
1142
|
-
* - Object subscribers (Computed atoms): will mark themselves dirty
|
|
1143
|
-
* - Function subscribers (Effects): will schedule their execution
|
|
1144
|
-
* Actual recomputation happens lazily when .value is accessed (Pull).
|
|
1145
|
-
*/
|
|
1146
785
|
_markDirty() {
|
|
1147
|
-
this._isRecomputing() || this._isDirty() || (this._setDirty(), this.
|
|
1148
|
-
}
|
|
1149
|
-
/**
|
|
1150
|
-
* Notifies function subscribers (Effects) of state changes.
|
|
1151
|
-
* Currently only called from _handleAsyncRejection to notify Effects of errors.
|
|
1152
|
-
* In normal operation, Effects are notified via _markDirty during dirty propagation.
|
|
1153
|
-
*/
|
|
1154
|
-
_notifySubscribers() {
|
|
1155
|
-
this._functionSubscribers.hasSubscribers && this._functionSubscribers.forEachSafe(
|
|
1156
|
-
(e) => e(),
|
|
1157
|
-
(e) => console.error(e)
|
|
1158
|
-
);
|
|
786
|
+
this._isRecomputing() || this._isDirty() || (this._setDirty(), this._notifyJob());
|
|
1159
787
|
}
|
|
1160
788
|
_registerTracking() {
|
|
1161
789
|
const e = m.getCurrent();
|
|
@@ -1164,223 +792,121 @@ class Q {
|
|
|
1164
792
|
e.addDependency(this);
|
|
1165
793
|
else if (typeof e == "function") {
|
|
1166
794
|
const t = e;
|
|
1167
|
-
t.addDependency ? t.addDependency(this) : this.
|
|
1168
|
-
} else e.execute && this.
|
|
795
|
+
t.addDependency ? t.addDependency(this) : this._functionSubscribersStore.add(e);
|
|
796
|
+
} else e.execute && this._objectSubscribersStore.add(e);
|
|
1169
797
|
}
|
|
1170
798
|
}
|
|
1171
|
-
Object.freeze(
|
|
1172
|
-
function
|
|
1173
|
-
return new
|
|
799
|
+
Object.freeze(Z.prototype);
|
|
800
|
+
function fe(i, e = {}) {
|
|
801
|
+
return new Z(i, e);
|
|
1174
802
|
}
|
|
1175
|
-
class
|
|
803
|
+
class oe extends J {
|
|
1176
804
|
constructor(e, t = {}) {
|
|
1177
|
-
this.run = () => {
|
|
805
|
+
super(), this.run = () => {
|
|
1178
806
|
if (this.isDisposed)
|
|
1179
|
-
throw new g(
|
|
1180
|
-
this.execute();
|
|
807
|
+
throw new g(l.EFFECT_MUST_BE_FUNCTION);
|
|
808
|
+
this._dependencyVersions !== f && (p.release(this._dependencyVersions), this._dependencyVersions = f), this.execute();
|
|
1181
809
|
}, this.dispose = () => {
|
|
1182
810
|
if (!this.isDisposed) {
|
|
1183
|
-
if (this._setDisposed(), this._safeCleanup(), this._unsubscribes !==
|
|
811
|
+
if (this._setDisposed(), this._safeCleanup(), this._unsubscribes !== b) {
|
|
1184
812
|
for (let s = 0; s < this._unsubscribes.length; s++) {
|
|
1185
813
|
const n = this._unsubscribes[s];
|
|
1186
814
|
n && n();
|
|
1187
815
|
}
|
|
1188
|
-
|
|
816
|
+
I.release(this._unsubscribes), this._unsubscribes = b;
|
|
1189
817
|
}
|
|
1190
|
-
this._dependencies !==
|
|
818
|
+
this._dependencies !== _ && (y.release(this._dependencies), this._dependencies = _), this._dependencyVersions !== f && (p.release(this._dependencyVersions), this._dependencyVersions = f);
|
|
1191
819
|
}
|
|
1192
820
|
}, this.addDependency = (s) => {
|
|
1193
|
-
if (this.isExecuting && this._nextDeps && this._nextUnsubs) {
|
|
821
|
+
if (this.isExecuting && this._nextDeps && this._nextUnsubs && this._nextVersions) {
|
|
1194
822
|
const n = s, r = this._currentEpoch;
|
|
1195
823
|
if (n._lastSeenEpoch === r) return;
|
|
1196
|
-
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);
|
|
1197
825
|
}
|
|
1198
826
|
}, this.execute = () => {
|
|
1199
|
-
if (this.isDisposed || this.isExecuting) return;
|
|
827
|
+
if (this.isDisposed || this.isExecuting || !this._shouldExecute()) return;
|
|
1200
828
|
this._checkInfiniteLoop(), this._setExecuting(!0), this._safeCleanup();
|
|
1201
|
-
const s = this._dependencies, n = this.
|
|
1202
|
-
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)
|
|
1203
831
|
for (let u = 0; u < s.length; u++) {
|
|
1204
|
-
const
|
|
1205
|
-
|
|
832
|
+
const a = s[u];
|
|
833
|
+
a && (a._tempUnsub = r[u]);
|
|
1206
834
|
}
|
|
1207
|
-
this._nextDeps =
|
|
1208
|
-
let
|
|
835
|
+
this._nextDeps = c, this._nextVersions = x, this._nextUnsubs = D, this._currentEpoch = R;
|
|
836
|
+
let h = !1;
|
|
1209
837
|
try {
|
|
1210
838
|
const u = m.run(this, this._fn);
|
|
1211
|
-
this._dependencies =
|
|
1212
|
-
!this.isDisposed && typeof
|
|
1213
|
-
}).catch((
|
|
1214
|
-
console.error(
|
|
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));
|
|
1215
843
|
}) : this._cleanup = typeof u == "function" ? u : null;
|
|
1216
844
|
} catch (u) {
|
|
1217
|
-
|
|
845
|
+
h = !0, console.error(N(u, g, l.EFFECT_EXECUTION_FAILED)), this._cleanup = null;
|
|
1218
846
|
} finally {
|
|
1219
|
-
if (this._setExecuting(!1), this._nextDeps = null, this._nextUnsubs = null,
|
|
1220
|
-
if (s !==
|
|
847
|
+
if (this._setExecuting(!1), this._nextDeps = null, this._nextVersions = null, this._nextUnsubs = null, h) {
|
|
848
|
+
if (s !== _) {
|
|
1221
849
|
for (let u = 0; u < s.length; u++) {
|
|
1222
|
-
const
|
|
1223
|
-
|
|
850
|
+
const a = s[u];
|
|
851
|
+
a?._tempUnsub && (a._tempUnsub(), a._tempUnsub = void 0);
|
|
1224
852
|
}
|
|
1225
|
-
|
|
853
|
+
y.release(s);
|
|
1226
854
|
}
|
|
1227
|
-
n !==
|
|
855
|
+
r !== b && I.release(r), n !== f && p.release(n);
|
|
1228
856
|
} else {
|
|
1229
|
-
|
|
1230
|
-
for (let u = 0; u <
|
|
1231
|
-
|
|
1232
|
-
if (
|
|
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 !== _)
|
|
1233
861
|
for (let u = 0; u < s.length; u++) {
|
|
1234
|
-
const
|
|
1235
|
-
|
|
862
|
+
const a = s[u];
|
|
863
|
+
a && (a._tempUnsub = void 0);
|
|
1236
864
|
}
|
|
1237
865
|
}
|
|
1238
866
|
}
|
|
1239
|
-
}, 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);
|
|
1240
868
|
}
|
|
1241
|
-
/**
|
|
1242
|
-
* Synchronizes subscriptions by unsubscribing from removed dependencies.
|
|
1243
|
-
* Uses epoch-based O(N) diff to identify stale dependencies.
|
|
1244
|
-
*
|
|
1245
|
-
* @param prevDeps - Previous dependency array
|
|
1246
|
-
* @param epoch - Current execution epoch for staleness detection
|
|
1247
|
-
*/
|
|
1248
|
-
// _syncDependencies removed (inline logic in execute)
|
|
1249
869
|
_subscribeTo(e) {
|
|
1250
870
|
try {
|
|
1251
871
|
const t = e.subscribe(() => {
|
|
1252
|
-
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);
|
|
1253
873
|
});
|
|
1254
874
|
this._nextUnsubs && this._nextUnsubs.push(t);
|
|
1255
875
|
} catch (t) {
|
|
1256
|
-
console.error(
|
|
876
|
+
console.error(N(t, g, l.EFFECT_EXECUTION_FAILED)), this._nextUnsubs && this._nextUnsubs.push(() => {
|
|
1257
877
|
});
|
|
1258
878
|
}
|
|
1259
879
|
}
|
|
1260
|
-
/**
|
|
1261
|
-
* Indicates whether this effect has been disposed.
|
|
1262
|
-
*
|
|
1263
|
-
* @returns `true` if the effect has been disposed, `false` otherwise
|
|
1264
|
-
*
|
|
1265
|
-
* @remarks
|
|
1266
|
-
* A disposed effect will not execute and cannot be reactivated.
|
|
1267
|
-
* Use this property to check if the effect is still active before
|
|
1268
|
-
* performing operations that depend on it.
|
|
1269
|
-
*
|
|
1270
|
-
* @example
|
|
1271
|
-
* ```typescript
|
|
1272
|
-
* const fx = effect(() => console.log(counter.value));
|
|
1273
|
-
* console.log(fx.isDisposed); // false
|
|
1274
|
-
* fx.dispose();
|
|
1275
|
-
* console.log(fx.isDisposed); // true
|
|
1276
|
-
* ```
|
|
1277
|
-
*/
|
|
1278
880
|
get isDisposed() {
|
|
1279
|
-
return (this.
|
|
881
|
+
return (this.flags & F.DISPOSED) !== 0;
|
|
1280
882
|
}
|
|
1281
|
-
/**
|
|
1282
|
-
* Returns the total number of times this effect has been executed.
|
|
1283
|
-
*
|
|
1284
|
-
* @returns The cumulative execution count since the effect was created
|
|
1285
|
-
*
|
|
1286
|
-
* @remarks
|
|
1287
|
-
* This counter is useful for debugging, testing, and monitoring
|
|
1288
|
-
* effect behavior. It increments on every execution, regardless
|
|
1289
|
-
* of whether the execution succeeds or fails.
|
|
1290
|
-
*
|
|
1291
|
-
* @example
|
|
1292
|
-
* ```typescript
|
|
1293
|
-
* const fx = effect(() => console.log(counter.value));
|
|
1294
|
-
* console.log(fx.executionCount); // 1 (initial execution)
|
|
1295
|
-
* counter.value = 10;
|
|
1296
|
-
* console.log(fx.executionCount); // 2
|
|
1297
|
-
* ```
|
|
1298
|
-
*/
|
|
1299
883
|
get executionCount() {
|
|
1300
884
|
return this._executionCount;
|
|
1301
885
|
}
|
|
1302
|
-
/**
|
|
1303
|
-
* Indicates whether this effect is currently executing.
|
|
1304
|
-
*
|
|
1305
|
-
* @returns `true` if the effect is mid-execution, `false` otherwise
|
|
1306
|
-
*
|
|
1307
|
-
* @remarks
|
|
1308
|
-
* This property is used internally to prevent re-entrant execution
|
|
1309
|
-
* (an effect triggering itself during its own execution). It can
|
|
1310
|
-
* also be useful for debugging to understand the effect's state.
|
|
1311
|
-
*
|
|
1312
|
-
* @example
|
|
1313
|
-
* ```typescript
|
|
1314
|
-
* const fx = effect(() => {
|
|
1315
|
-
* console.log('executing:', fx.isExecuting); // true
|
|
1316
|
-
* });
|
|
1317
|
-
* console.log(fx.isExecuting); // false (after execution completes)
|
|
1318
|
-
* ```
|
|
1319
|
-
*/
|
|
1320
886
|
get isExecuting() {
|
|
1321
|
-
return (this.
|
|
887
|
+
return (this.flags & F.EXECUTING) !== 0;
|
|
1322
888
|
}
|
|
1323
|
-
/**
|
|
1324
|
-
* Sets the disposed flag on this effect.
|
|
1325
|
-
*
|
|
1326
|
-
* @remarks
|
|
1327
|
-
* This is a low-level method that only sets the bit flag.
|
|
1328
|
-
* Use the public `dispose()` method for proper cleanup.
|
|
1329
|
-
*
|
|
1330
|
-
* @internal
|
|
1331
|
-
*/
|
|
1332
889
|
_setDisposed() {
|
|
1333
|
-
this.
|
|
890
|
+
this.flags |= F.DISPOSED;
|
|
1334
891
|
}
|
|
1335
|
-
/**
|
|
1336
|
-
* Sets or clears the executing flag on this effect.
|
|
1337
|
-
*
|
|
1338
|
-
* @param value - `true` to mark as executing, `false` to clear
|
|
1339
|
-
*
|
|
1340
|
-
* @remarks
|
|
1341
|
-
* Uses bitwise operations for efficient flag manipulation.
|
|
1342
|
-
* This flag prevents re-entrant execution of the effect.
|
|
1343
|
-
*
|
|
1344
|
-
* @internal
|
|
1345
|
-
*/
|
|
1346
892
|
_setExecuting(e) {
|
|
1347
893
|
const t = F.EXECUTING;
|
|
1348
|
-
this.
|
|
894
|
+
this.flags = this.flags & ~t | -Number(e) & t;
|
|
1349
895
|
}
|
|
1350
|
-
/**
|
|
1351
|
-
* Safely executes the cleanup function if one exists.
|
|
1352
|
-
*
|
|
1353
|
-
* @remarks
|
|
1354
|
-
* This method:
|
|
1355
|
-
* - Checks if a cleanup function exists and is callable
|
|
1356
|
-
* - Wraps the cleanup call in a try-catch to prevent cleanup errors
|
|
1357
|
-
* from breaking the effect lifecycle
|
|
1358
|
-
* - Logs any cleanup errors to the console
|
|
1359
|
-
* - Clears the cleanup reference after execution
|
|
1360
|
-
*
|
|
1361
|
-
* @internal
|
|
1362
|
-
*/
|
|
1363
896
|
_safeCleanup() {
|
|
1364
897
|
if (this._cleanup && typeof this._cleanup == "function") {
|
|
1365
898
|
try {
|
|
1366
899
|
this._cleanup();
|
|
1367
900
|
} catch (e) {
|
|
1368
|
-
console.error(
|
|
901
|
+
console.error(N(e, g, l.EFFECT_CLEANUP_FAILED));
|
|
1369
902
|
}
|
|
1370
903
|
this._cleanup = null;
|
|
1371
904
|
}
|
|
1372
905
|
}
|
|
1373
|
-
/**
|
|
1374
|
-
* Checks for infinite loop conditions using epoch-based detection.
|
|
1375
|
-
* Falls back to timestamp-based detection in development mode.
|
|
1376
|
-
*
|
|
1377
|
-
* @throws {EffectError} When infinite loop is detected
|
|
1378
|
-
* @internal
|
|
1379
|
-
*/
|
|
1380
906
|
_checkInfiniteLoop() {
|
|
1381
|
-
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) {
|
|
1382
908
|
const e = Date.now();
|
|
1383
|
-
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);
|
|
1384
910
|
}
|
|
1385
911
|
}
|
|
1386
912
|
_checkTimestampLoop(e) {
|
|
@@ -1394,80 +920,84 @@ class te {
|
|
|
1394
920
|
const r = new g(
|
|
1395
921
|
`Effect executed ${n} times within 1 second. Infinite loop suspected`
|
|
1396
922
|
);
|
|
1397
|
-
if (this.dispose(), console.error(r),
|
|
923
|
+
if (this.dispose(), console.error(r), d)
|
|
1398
924
|
throw r;
|
|
1399
925
|
}
|
|
1400
926
|
}
|
|
1401
927
|
_throwInfiniteLoopError(e) {
|
|
1402
928
|
const t = new g(
|
|
1403
|
-
`Infinite loop detected (${e}): effect executed ${this._executionsInEpoch} times in current flush. Total executions in flush: ${
|
|
929
|
+
`Infinite loop detected (${e}): effect executed ${this._executionsInEpoch} times in current flush. Total executions in flush: ${k}`
|
|
1404
930
|
);
|
|
1405
931
|
throw this.dispose(), console.error(t), t;
|
|
1406
932
|
}
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
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
|
+
}
|
|
1420
950
|
_checkLoopWarnings() {
|
|
1421
|
-
if (this._trackModifications &&
|
|
951
|
+
if (this._trackModifications && S.enabled) {
|
|
1422
952
|
const e = this._dependencies;
|
|
1423
953
|
for (let t = 0; t < e.length; t++) {
|
|
1424
954
|
const s = e[t];
|
|
1425
|
-
s && s._modifiedAtEpoch === this._currentEpoch &&
|
|
955
|
+
s && s._modifiedAtEpoch === this._currentEpoch && S.warn(
|
|
1426
956
|
!0,
|
|
1427
|
-
`Effect is reading a dependency (${
|
|
957
|
+
`Effect is reading a dependency (${S.getDebugName(s) || "unknown"}) that it just modified. Infinite loop may occur`
|
|
1428
958
|
);
|
|
1429
959
|
}
|
|
1430
960
|
}
|
|
1431
961
|
}
|
|
1432
962
|
}
|
|
1433
|
-
function
|
|
963
|
+
function de(i, e = {}) {
|
|
1434
964
|
if (typeof i != "function")
|
|
1435
|
-
throw new g(
|
|
1436
|
-
const t = new
|
|
965
|
+
throw new g(l.EFFECT_MUST_BE_FUNCTION);
|
|
966
|
+
const t = new oe(i, e);
|
|
1437
967
|
return t.execute(), t;
|
|
1438
968
|
}
|
|
1439
|
-
function
|
|
969
|
+
function he(i) {
|
|
1440
970
|
return i !== null && typeof i == "object" && "value" in i && "subscribe" in i && typeof i.subscribe == "function";
|
|
1441
971
|
}
|
|
1442
|
-
function
|
|
1443
|
-
if (
|
|
1444
|
-
const e =
|
|
972
|
+
function Ee(i) {
|
|
973
|
+
if (S.enabled) {
|
|
974
|
+
const e = S.getDebugType(i);
|
|
1445
975
|
if (e)
|
|
1446
976
|
return e === "computed";
|
|
1447
977
|
}
|
|
1448
|
-
return
|
|
978
|
+
return he(i) && "invalidate" in i && typeof i.invalidate == "function";
|
|
1449
979
|
}
|
|
1450
|
-
function
|
|
980
|
+
function be(i) {
|
|
1451
981
|
return i !== null && typeof i == "object" && "dispose" in i && "run" in i && typeof i.dispose == "function" && typeof i.run == "function";
|
|
1452
982
|
}
|
|
1453
983
|
export {
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
984
|
+
O as AsyncState,
|
|
985
|
+
E as AtomError,
|
|
986
|
+
C as ComputedError,
|
|
987
|
+
j as DEBUG_CONFIG,
|
|
988
|
+
S as DEBUG_RUNTIME,
|
|
1459
989
|
g as EffectError,
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
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
|
|
1472
1002
|
};
|
|
1473
1003
|
//# sourceMappingURL=index.mjs.map
|