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