@asaidimu/utils-sync 2.2.3 → 2.3.1

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/index.d.mts DELETED
@@ -1,718 +0,0 @@
1
- interface DebouncerOptions {
2
- /**
3
- * Quiet period in milliseconds. The last-enqueued function runs after
4
- * no new calls have arrived for this duration.
5
- * @default 300
6
- */
7
- delay?: number;
8
- /**
9
- * If true, also fires immediately on the leading edge (first call in a
10
- * quiet period), then debounces subsequent calls normally.
11
- *
12
- * Leading-edge semantics: the leading call fires immediately and clears
13
- * _pendingFn. Any calls arriving *while* the leading execution is in flight
14
- * register as a new trailing call and will be resolved by the trailing timer
15
- * when the quiet period expires. Calls arriving during the leading execution
16
- * are never lost.
17
- *
18
- * @default false
19
- */
20
- leading?: boolean;
21
- }
22
- /**
23
- * Result when the debounced function successfully executed.
24
- */
25
- type DebouncerOk<T> = {
26
- status: "ok";
27
- value: T;
28
- };
29
- /**
30
- * Result when the debounced function threw an error.
31
- */
32
- type DebouncerError = {
33
- status: "error";
34
- error: unknown;
35
- };
36
- /**
37
- * Result when the debounced call was cancelled before execution.
38
- */
39
- type DebouncerCancelled = {
40
- status: "cancelled";
41
- };
42
- /**
43
- * Discriminated union of all possible Debouncer outcomes.
44
- *
45
- * - `DebouncerOk<T>`: function ran and returned a value.
46
- * - `DebouncerError`: function ran and threw an error.
47
- * - `DebouncerCancelled`: call was cancelled before it ran.
48
- */
49
- type DebouncerResult<T> = DebouncerOk<T> | DebouncerError | DebouncerCancelled;
50
- /**
51
- * Collapses rapid successive calls into a single execution.
52
- *
53
- * Each call to `do()` returns a promise that resolves with the result of the
54
- * debounced execution — i.e. all callers within the same quiet window share
55
- * the same result. The function that actually runs is always the *last* one
56
- * enqueued before the delay expires.
57
- *
58
- * @example
59
- * const debounced = new Debouncer({ delay: 200 });
60
- * // Called rapidly three times — only the last fn runs.
61
- * const [a, b, c] = await Promise.all([
62
- * debounced.do(() => fetch("/api/search?q=h")),
63
- * debounced.do(() => fetch("/api/search?q=he")),
64
- * debounced.do(() => fetch("/api/search?q=hel")),
65
- * ]);
66
- * // a.status === "ok" and a.value is the result of the third fetch.
67
- * // b and c share the same result as a.
68
- */
69
- declare class Debouncer<T = void> {
70
- private _delay;
71
- private _leading;
72
- private _timer;
73
- private _pendingFn;
74
- private _pendingResolvers;
75
- private _leadingFired;
76
- constructor(options?: DebouncerOptions);
77
- /**
78
- * Enqueues a function and returns a promise that resolves with its result.
79
- *
80
- * All callers within the same quiet window share the same result — the
81
- * function that actually runs is the *last* one enqueued before the delay
82
- * expires. Use this when you need the return value of the debounced call.
83
- *
84
- * For fire-and-forget use (void fns, event handlers), prefer `fire()` to
85
- * avoid unhandled-promise-rejection warnings and make intent explicit.
86
- *
87
- * @param fn - The function to debounce.
88
- * @returns A promise resolving with a DebouncerResult discriminated union.
89
- */
90
- do(fn: () => Promise<T> | T): Promise<DebouncerResult<T>>;
91
- /**
92
- * Enqueues a function without returning a promise (fire-and-forget).
93
- *
94
- * Identical debounce semantics to `do()` — the last-enqueued function runs
95
- * after the quiet period. Use this for void callbacks, DOM event handlers,
96
- * or any caller that doesn't care about the result. No dangling promise,
97
- * no unhandled-rejection risk.
98
- *
99
- * @param fn - The function to debounce.
100
- */
101
- fire(fn: () => Promise<T> | T): void;
102
- /**
103
- * Shared enqueue logic for both `do()` and `fire()`.
104
- *
105
- */
106
- private _enqueue;
107
- /**
108
- * Immediately cancels any pending debounced execution.
109
- * All waiting callers resolve with `{ status: "cancelled" }`.
110
- */
111
- cancel(): void;
112
- /**
113
- * Immediately executes the pending function (if any), bypassing the remaining delay.
114
- * All waiting callers receive the result.
115
- */
116
- flush(): Promise<DebouncerResult<T> | null>;
117
- /** Returns true if a debounced call is currently pending. */
118
- pending(): boolean;
119
- /**
120
- * Executes the latest pending function and resolves all waiting callers.
121
- */
122
- private _fire;
123
- }
124
-
125
- /**
126
- * Severity levels for structured issues and errors.
127
- */
128
- type Severity = "error" | "warning" | "info";
129
- /**
130
- * Represents a detailed validation or operational problem.
131
- * Designed to be machine-readable while remaining human-friendly.
132
- */
133
- interface Issue {
134
- /** Machine-readable identifier (e.g., "REQUIRED_FIELD_MISSING"). */
135
- readonly code: string;
136
- /** Human-readable description of the problem. */
137
- readonly message: string;
138
- /** Field path in a document or state (e.g., "users.0.email"). */
139
- readonly path?: string;
140
- /** Optional array index when the issue relates to a specific element. */
141
- readonly index?: number;
142
- /** Seriousness of the issue. Defaults to "error". */
143
- readonly severity?: Severity;
144
- /** Optional detailed explanation, can be multi-line. */
145
- readonly description?: string;
146
- /** Nested issues that caused this one. */
147
- readonly cause?: readonly Issue[];
148
- }
149
- /**
150
- * Standardized error code format: CATEGORY-XXX[-SUFFIX]
151
- * Examples:
152
- * - VAL-001 (Validation: required field missing)
153
- * - DB-002-NF (Database: not found)
154
- * - AUTH-003-DENIED (Auth: permission denied)
155
- */
156
- interface ErrorCodeMetadata {
157
- /** The formal error code (e.g., "VAL-001") */
158
- readonly code: string;
159
- /** Human-readable name for the error type */
160
- readonly name: string;
161
- /** Detailed description of when this error occurs */
162
- readonly description: string;
163
- /** Suggested action for handling or resolving the error */
164
- readonly action?: string;
165
- /** HTTP status code mapping (if applicable) */
166
- readonly httpStatus?: number;
167
- /** Category of the error */
168
- readonly category: ErrorCategory;
169
- /** Whether this error should be logged as warning vs error */
170
- readonly logLevel?: "debug" | "info" | "warn" | "error";
171
- }
172
- type ErrorCategory = "validation" | "database" | "auth" | "business" | "system" | "network" | "concurrency" | "custom";
173
- /**
174
- * SystemError is the primary error type for all operational and validation errors.
175
- * Supports both predefined and custom error codes with full metadata.
176
- */
177
- declare class SystemError extends Error {
178
- readonly code: string;
179
- readonly codeMetadata: ErrorCodeMetadata;
180
- readonly severity: Severity;
181
- readonly path?: string;
182
- readonly operation?: string;
183
- readonly issues: readonly Issue[];
184
- readonly cause?: unknown;
185
- constructor(params: {
186
- code: string;
187
- message?: string;
188
- severity?: Severity;
189
- path?: string;
190
- operation?: string;
191
- issues?: readonly Issue[];
192
- cause?: unknown;
193
- metadata?: Partial<Omit<ErrorCodeMetadata, "code">>;
194
- });
195
- /**
196
- * Returns a new SystemError with the specified path.
197
- */
198
- withPath(path: string): SystemError;
199
- /**
200
- * Returns a new SystemError with the specified operation name.
201
- */
202
- withOperation(operation: string): SystemError;
203
- /**
204
- * Returns a new SystemError with the specified issue appended.
205
- */
206
- withIssue(issue: Issue): SystemError;
207
- /**
208
- * Returns a new SystemError with multiple issues appended.
209
- */
210
- withIssues(issues: readonly Issue[]): SystemError;
211
- /**
212
- * Returns a new SystemError wrapping the specified cause.
213
- */
214
- withCause(cause: unknown): SystemError;
215
- /**
216
- * Returns the HTTP status code for this error (if applicable).
217
- */
218
- getHttpStatus(): number | undefined;
219
- /**
220
- * Formats the error for logging with structured metadata.
221
- */
222
- toLogEntry(): Record<string, unknown>;
223
- /**
224
- * Produces a human-readable representation suitable for logging.
225
- */
226
- toString(): string;
227
- }
228
-
229
- /** Represents all errors within the sync system */
230
- declare class SyncError extends SystemError {
231
- constructor(message: string, cause?: unknown);
232
- }
233
- declare class TimeoutError extends SyncError {
234
- constructor(message?: string);
235
- }
236
- declare class OnceExecutionConflict extends SyncError {
237
- constructor(cause?: unknown);
238
- }
239
- declare class SerializerExecutionDone extends SyncError {
240
- constructor(cause?: unknown);
241
- }
242
-
243
- /**
244
- * A one-shot gate that starts closed and opens exactly once.
245
- *
246
- * All current and future `wait()` callers resolve immediately once `open()` is
247
- * called. Unlike Once, Latch carries no return value and has no retry logic —
248
- * it is a pure signalling primitive.
249
- *
250
- * Typical use: coordinate startup, signal that an initialisation phase is done,
251
- * or gate downstream work on a single event.
252
- *
253
- * @example
254
- * const ready = new Latch();
255
- * // Consumer
256
- * await ready.wait();
257
- * // Producer (elsewhere)
258
- * ready.open();
259
- */
260
- declare class Latch {
261
- private _open;
262
- private _resolve;
263
- private _promise;
264
- constructor();
265
- /**
266
- * Opens the latch. All current and future waiters resolve immediately.
267
- * Calling open() more than once is a no-op.
268
- */
269
- open(): void;
270
- /**
271
- * Returns a promise that resolves when the latch is opened.
272
- * If already open, resolves on the next microtask checkpoint.
273
- *
274
- * @param timeout - Optional maximum wait time in milliseconds.
275
- * @throws {TimeoutError} If the latch does not open within the timeout.
276
- */
277
- wait(timeout?: number): Promise<void>;
278
- /**
279
- * Synchronously checks whether the latch has been opened.
280
- */
281
- isOpen(): boolean;
282
- }
283
-
284
- interface MutexOptions {
285
- /**
286
- * Maximum number of pending requests allowed in the queue.
287
- * If exceeded, tryLock/lock will fail.
288
- * @default Infinity
289
- */
290
- capacity?: number;
291
- /**
292
- * Controls how lock handoff is scheduled when a waiter is unblocked.
293
- *
294
- * - `"macrotask"` (default): Uses setTimeout(fn, 0) to yield to the event
295
- * loop between handoffs. Prevents microtask starvation under heavy
296
- * contention — I/O, rendering, and other macrotasks can run between
297
- * lock acquisitions. Use for Serializer and other coarse-grained
298
- * serializers.
299
- *
300
- * - `"microtask"`: Uses queueMicrotask(fn) for handoff. Near-zero latency
301
- * between acquisitions — no macrotask delay. Safe when you need
302
- * back-to-back operations to complete as fast as possible and starvation
303
- * is not a concern (e.g. Once, Semaphore where builds are infrequent
304
- * and latency matters more than fairness).
305
- */
306
- yieldMode?: "macrotask" | "microtask";
307
- }
308
- /**
309
- * A mutual exclusion lock.
310
- * Allows only one execution context to access a resource at a time.
311
- *
312
- * Yield mode is configurable per instance:
313
- * - "macrotask" (default): yields between handoffs, preventing microtask starvation.
314
- * - "microtask": zero-delay handoff for latency-sensitive paths.
315
- */
316
- declare class Mutex {
317
- private _locked;
318
- private _capacity;
319
- private _yieldMode;
320
- private waiters;
321
- constructor(options?: MutexOptions);
322
- /**
323
- * Acquires the lock. If already held, waits until released or timeout reached.
324
- *
325
- * @param timeout - Optional maximum wait time in milliseconds.
326
- * @throws {TimeoutError} If the lock cannot be acquired within the timeout.
327
- * @throws {Error} If the wait queue is full (backpressure).
328
- */
329
- lock(timeout?: number): Promise<void>;
330
- /**
331
- * Attempts to acquire the lock without waiting.
332
- * @returns `true` if the lock was acquired, `false` otherwise.
333
- */
334
- tryLock(): boolean;
335
- /**
336
- * Releases the lock, scheduling the next waiter according to yieldMode.
337
- *
338
- * When a waiter exists, `_locked` intentionally remains `true` — ownership
339
- * transfers directly to the next waiter without ever clearing the flag.
340
- * Only when the queue is empty is `_locked` set to false.
341
- *
342
- * @throws {Error} If the mutex is not currently locked.
343
- */
344
- unlock(): void;
345
- /** Returns true if the mutex is currently locked. */
346
- locked(): boolean;
347
- /** Returns the number of operations waiting for the lock. */
348
- pending(): number;
349
- }
350
-
351
- type OnceResult<T> = {
352
- value: T | null;
353
- error?: unknown;
354
- };
355
- /**
356
- * Ensures a specific task is executed exactly once, regardless of concurrent callers.
357
- * Handles race conditions, caching, and optional retries on failure.
358
- *
359
- * Uses microtask yield mode for its internal mutex — builds are latency-sensitive
360
- * and starvation is not a concern (only one build runs at a time by design).
361
- *
362
- * @template T - The type of value returned by the execution.
363
- */
364
- declare class Once<T = void> {
365
- private mutex;
366
- private promise;
367
- private _value;
368
- private _error;
369
- private _done;
370
- private retry;
371
- private throws;
372
- constructor({ retry, throws }?: {
373
- retry?: boolean;
374
- throws?: boolean;
375
- });
376
- /**
377
- * Manually sets a value, marking the operation as done.
378
- * Throws if the operation is already done or currently running.
379
- *
380
- * @param value - The value to resolve to.
381
- */
382
- resolve(value: T): void;
383
- /**
384
- * Execute the function if it hasn't been executed yet.
385
- * Subsequent calls return the result of the first execution.
386
- *
387
- * @param fn - The function to execute.
388
- * @param timeout - Max wait time in ms (includes lock wait + execution time).
389
- */
390
- do(fn: () => Promise<T> | T, timeout?: number): Promise<OnceResult<T>>;
391
- /**
392
- * Executes the function synchronously if it hasn't been executed yet.
393
- * If an async operation is pending or the lock is contended, it will fail immediately.
394
- * The failure is returned as an error state, OR thrown if `throws: true` is configured.
395
- *
396
- * @param fn - The synchronous function to execute.
397
- * @returns The result of the execution.
398
- */
399
- doSync(fn: () => T): OnceResult<T>;
400
- /**
401
- * Returns true if the operation is currently executing.
402
- *
403
- * Uses ready() as the canonical check: running is its logical complement
404
- * when a promise is in flight. This correctly handles the brief window where
405
- * _done=true but the promise hasn't been cleared yet in finally.
406
- */
407
- running(): boolean;
408
- /**
409
- * Returns the current state without waiting.
410
- */
411
- peek(): OnceResult<T>;
412
- /**
413
- * Returns the stored value if successful, otherwise throws the stored error.
414
- * Throws if the operation is not yet complete.
415
- */
416
- get(): T | null;
417
- /**
418
- * Resets the instance, allowing the action to run again on the next call.
419
- *
420
- * @throws {Error} If called while an operation is currently executing,
421
- * as this would leave the in-flight promise in an inconsistent state.
422
- */
423
- reset(): void;
424
- /**
425
- * Returns true if the operation has finished (success or final failure).
426
- */
427
- done(): boolean;
428
- /**
429
- * Returns the in-flight execution promise if one is currently running, null otherwise.
430
- *
431
- * Use this to join an in-progress operation without triggering a new one.
432
- */
433
- current(): Promise<OnceResult<T>> | null;
434
- /**
435
- * Awaits a promise with an optional timeout.
436
- *
437
- * We clear the timer on the winning branch, consistent with the
438
- * Mutex/Semaphore/Latch timeout pattern throughout this module.
439
- */
440
- private _awaitWithTimeout;
441
- }
442
-
443
- interface RWMutexOptions {
444
- /**
445
- * Controls how lock handoff is scheduled when a waiter is unblocked.
446
- *
447
- * - `"microtask"` (default): Uses queueMicrotask(fn). Near-zero latency
448
- * between handoffs. Appropriate for RWMutex because readers are woken in
449
- * bulk and writers are rarely contended enough to cause starvation.
450
- *
451
- * - `"macrotask"`: Uses setTimeout(fn, 0) to yield to the event loop between
452
- * handoffs. Use if you observe microtask starvation under extreme write
453
- * contention on this specific lock.
454
- */
455
- yieldMode?: "macrotask" | "microtask";
456
- }
457
- /**
458
- * A read-write mutex with writer preference.
459
- *
460
- * - Multiple readers can hold the lock concurrently.
461
- * - Writers get exclusive access — no readers or other writers.
462
- * - Writer preference: once a writer is waiting, new readers queue behind it.
463
- * This prevents writer starvation under read-heavy loads.
464
- *
465
- * Readers should call `rlock()` / `runlock()`.
466
- * Writers should call `lock()` / `unlock()`.
467
- * Prefer the `read()` and `write()` convenience wrappers to avoid lock leaks.
468
- */
469
- declare class RWMutex {
470
- private _readers;
471
- private _writeLocked;
472
- private _pendingWriters;
473
- private _yieldMode;
474
- private readerWaiters;
475
- private writerWaiters;
476
- constructor(options?: RWMutexOptions);
477
- /**
478
- * Acquires a read lock. Blocks if a writer holds or is waiting for the lock.
479
- *
480
- * @param timeout - Optional maximum wait time in milliseconds.
481
- * @throws {TimeoutError} If the read lock cannot be acquired within the timeout.
482
- */
483
- rlock(timeout?: number): Promise<void>;
484
- /**
485
- * Releases a read lock.
486
- * @throws {Error} If no read lock is currently held.
487
- */
488
- runlock(): void;
489
- /**
490
- * Acquires the write lock. Blocks until all current readers and any prior
491
- * writers have finished.
492
- *
493
- * @param timeout - Optional maximum wait time in milliseconds.
494
- * @throws {TimeoutError} If the write lock cannot be acquired within the timeout.
495
- */
496
- lock(timeout?: number): Promise<void>;
497
- /**
498
- * Releases the write lock.
499
- * Wakes the next pending writer if one exists; otherwise wakes all pending readers.
500
- *
501
- * @throws {Error} If no write lock is currently held.
502
- */
503
- unlock(): void;
504
- /**
505
- * Runs a function under a read lock, releasing it when done.
506
- * Prefer this over manual rlock/runlock to avoid lock leaks.
507
- */
508
- read<T>(fn: () => Promise<T> | T, timeout?: number): Promise<T>;
509
- /**
510
- * Runs a function under the write lock, releasing it when done.
511
- * Prefer this over manual lock/unlock to avoid lock leaks.
512
- */
513
- write<T>(fn: () => Promise<T> | T, timeout?: number): Promise<T>;
514
- /** Returns true if the write lock is currently held. */
515
- writeLocked(): boolean;
516
- /** Returns the number of active read lock holders. */
517
- readers(): number;
518
- /** Returns the number of writers currently waiting for the lock. */
519
- pendingWriters(): number;
520
- /** Returns the number of readers currently waiting for the lock. */
521
- pendingReaders(): number;
522
- /**
523
- * Wakes the next writer if the lock is free and a writer is waiting.
524
- * Returns true if a writer was woken, false otherwise.
525
- */
526
- private _tryWakeWriter;
527
- /**
528
- * Wakes all pending readers (called when a writer releases and no writers are queued).
529
- */
530
- private _wakeAllReaders;
531
- /**
532
- * Schedules a waiter callback according to the configured yieldMode.
533
- */
534
- private _schedule;
535
- }
536
-
537
- interface SemaphoreOptions extends MutexOptions {
538
- /**
539
- * Number of concurrent holders allowed.
540
- * Inherits `capacity` and `yieldMode` from MutexOptions.
541
- * @default 1 (equivalent to a Mutex)
542
- */
543
- slots?: number;
544
- }
545
- /**
546
- * A counting semaphore — generalises Mutex to allow up to N concurrent holders.
547
- *
548
- * Useful for rate-limiting concurrency: e.g. "at most 3 in-flight HTTP requests".
549
- * With slots=1 it behaves identically to Mutex.
550
- *
551
- * Accepts the same `capacity` and `yieldMode` options as Mutex, plus `slots`.
552
- */
553
- declare class Semaphore {
554
- private _slots;
555
- private _available;
556
- private _capacity;
557
- private _yieldMode;
558
- private waiters;
559
- constructor(options?: SemaphoreOptions);
560
- /**
561
- * Acquires one slot. If all slots are taken, waits until one is released.
562
- *
563
- * @param timeout - Optional maximum wait time in milliseconds.
564
- * @throws {TimeoutError} If a slot cannot be acquired within the timeout.
565
- * @throws {Error} If the wait queue is full.
566
- */
567
- acquire(timeout?: number): Promise<void>;
568
- /**
569
- * Attempts to acquire a slot without waiting.
570
- * @returns `true` if a slot was acquired, `false` otherwise.
571
- */
572
- tryAcquire(): boolean;
573
- /**
574
- * Releases one slot. If waiters are queued, the next one is scheduled
575
- * according to yieldMode.
576
- *
577
- * @throws {Error} If no slot is currently held (release without acquire).
578
- */
579
- release(): void;
580
- /**
581
- * Runs a function with one acquired slot, releasing it when done.
582
- * Convenience wrapper — prefer this over manual acquire/release.
583
- */
584
- run<T>(fn: () => Promise<T> | T, timeout?: number): Promise<T>;
585
- /** Number of slots currently free. */
586
- available(): number;
587
- /** Number of callers waiting for a slot. */
588
- pending(): number;
589
- /** Total slot count (as configured). */
590
- slots(): number;
591
- }
592
-
593
- type SerializerResult<T> = {
594
- value: T | null;
595
- error?: unknown;
596
- };
597
- interface SerializerOptions {
598
- /**
599
- * Max items in queue. If full, .do() returns an error immediately.
600
- * @default 1000
601
- */
602
- capacity?: number;
603
- /**
604
- * Yield mode for the internal mutex. Defaults to "macrotask" for
605
- * coarse-grained serializers. Use "microtask" for fine-grained
606
- * latency-sensitive serializers.
607
- */
608
- yieldMode?: "macrotask" | "microtask";
609
- }
610
- /**
611
- * Ensures tasks are executed sequentially (FIFO).
612
- * Maintains the result of the last successful execution.
613
- * Includes backpressure protection via configurable queue capacity.
614
- */
615
- declare class Serializer<T = void> {
616
- private mutex;
617
- private _done;
618
- private _lastValue;
619
- private _lastError;
620
- private _hasRun;
621
- constructor(options?: SerializerOptions);
622
- /**
623
- * Enqueue a function to be executed after all previous tasks complete.
624
- *
625
- * @param fn - The function to execute.
626
- * @param timeout - Max time to wait to acquire the lock.
627
- * @returns Object containing the value or error.
628
- */
629
- do(fn: () => Promise<T> | T, timeout?: number): Promise<SerializerResult<T | null>>;
630
- /**
631
- * Returns the result of the last execution.
632
- *
633
- * Returns `{ value: null, error: undefined }` both when the serializer has
634
- * never run and when it ran and returned null — use `hasRun()` to distinguish
635
- * these two cases.
636
- */
637
- peek(): SerializerResult<T | null>;
638
- /**
639
- * Returns true if at least one task has been executed (successfully or not).
640
- */
641
- hasRun(): boolean;
642
- /**
643
- * Permanently closes the serializer.
644
- * Subsequent calls to `do()` will fail immediately with SerializerExecutionDone.
645
- */
646
- close(): void;
647
- /** Returns the number of tasks currently waiting. */
648
- pending(): number;
649
- /** Returns true if a task is currently executing. */
650
- running(): boolean;
651
- }
652
-
653
- interface SharedResourceOptions {
654
- /**
655
- * How long to wait after the last subscriber leaves before cleaning up.
656
- * - "microtask": (Default) Waits until the end of the current synchronous execution tick.
657
- * Perfect for React StrictMode or concurrent rendering.
658
- * - number: Waits for the specified milliseconds. Useful for debouncing rapid reconnects.
659
- * - "sync": Cleans up immediately (bypasses the grace period entirely).
660
- */
661
- gracePeriod?: "microtask" | "sync" | number;
662
- }
663
- /**
664
- * Manages the lifecycle of a reference-counted shared resource.
665
- * Ensures the resource is created exactly once on the first acquisition,
666
- * and cleaned up only when the last subscriber releases it (after an optional grace period).
667
- */
668
- declare class SharedResource<T> {
669
- private readonly factory;
670
- private readonly onCleanup;
671
- private readonly options;
672
- private _count;
673
- private readonly init;
674
- private pendingMicrotask;
675
- private cleanupTimer?;
676
- constructor(factory: () => Promise<T> | T, onCleanup: (value: T | null) => void | Promise<void>, options?: SharedResourceOptions);
677
- /**
678
- * The current number of active subscribers.
679
- */
680
- get subscribers(): number;
681
- /**
682
- * Increments the reference count and ensures the resource is initialized.
683
- * If a cleanup was scheduled but hasn't executed yet, it is cancelled.
684
- *
685
- * @returns The initialized resource.
686
- */
687
- acquire(): Promise<T>;
688
- /**
689
- * Decrements the reference count.
690
- * If the count reaches zero, the cleanup process is scheduled according to the grace period.
691
- */
692
- release(): void;
693
- /**
694
- * Returns the current value synchronously if it has been successfully initialized.
695
- * Returns null if initialization is pending, failed, or hasn't started.
696
- */
697
- peek(): T | null;
698
- /**
699
- * Forcibly tears down the resource, ignoring the reference count and grace period.
700
- * Useful for emergency teardowns (e.g., container disposal).
701
- */
702
- forceCleanup(): void;
703
- /**
704
- * Cancels any scheduled cleanup tasks.
705
- * This is the core mechanism that prevents React StrictMode from destroying the resource.
706
- */
707
- private cancelPendingCleanup;
708
- /**
709
- * Determines how to schedule the cleanup based on the configured options.
710
- */
711
- private scheduleCleanup;
712
- /**
713
- * Performs the actual teardown of the resource and resets the initialization state.
714
- */
715
- private executeCleanup;
716
- }
717
-
718
- export { Debouncer, type DebouncerCancelled, type DebouncerError, type DebouncerOk, type DebouncerOptions, type DebouncerResult, Latch, Mutex, type MutexOptions, Once, OnceExecutionConflict, type OnceResult, RWMutex, type RWMutexOptions, Semaphore, type SemaphoreOptions, Serializer, SerializerExecutionDone, type SerializerOptions, type SerializerResult, SharedResource, type SharedResourceOptions, SyncError, TimeoutError };