@asaidimu/utils-sync 2.2.0 → 2.2.2
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 +171 -2
- package/index.d.ts +171 -2
- package/index.js +1 -1
- package/index.mjs +1 -1
- package/package.json +1 -1
package/index.d.mts
CHANGED
|
@@ -122,8 +122,112 @@ declare class Debouncer<T = void> {
|
|
|
122
122
|
private _fire;
|
|
123
123
|
}
|
|
124
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
|
+
|
|
125
229
|
/** Represents all errors within the sync system */
|
|
126
|
-
declare class SyncError extends
|
|
230
|
+
declare class SyncError extends SystemError {
|
|
127
231
|
constructor(message: string, cause?: unknown);
|
|
128
232
|
}
|
|
129
233
|
declare class TimeoutError extends SyncError {
|
|
@@ -539,4 +643,69 @@ declare class Serializer<T = void> {
|
|
|
539
643
|
running(): boolean;
|
|
540
644
|
}
|
|
541
645
|
|
|
542
|
-
|
|
646
|
+
interface SharedResourceOptions {
|
|
647
|
+
/**
|
|
648
|
+
* How long to wait after the last subscriber leaves before cleaning up.
|
|
649
|
+
* - "microtask": (Default) Waits until the end of the current synchronous execution tick.
|
|
650
|
+
* Perfect for React StrictMode or concurrent rendering.
|
|
651
|
+
* - number: Waits for the specified milliseconds. Useful for debouncing rapid reconnects.
|
|
652
|
+
* - "sync": Cleans up immediately (bypasses the grace period entirely).
|
|
653
|
+
*/
|
|
654
|
+
gracePeriod?: "microtask" | "sync" | number;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Manages the lifecycle of a reference-counted shared resource.
|
|
658
|
+
* Ensures the resource is created exactly once on the first acquisition,
|
|
659
|
+
* and cleaned up only when the last subscriber releases it (after an optional grace period).
|
|
660
|
+
*/
|
|
661
|
+
declare class SharedResource<T> {
|
|
662
|
+
private readonly factory;
|
|
663
|
+
private readonly onCleanup;
|
|
664
|
+
private readonly options;
|
|
665
|
+
private _count;
|
|
666
|
+
private readonly init;
|
|
667
|
+
private pendingMicrotask;
|
|
668
|
+
private cleanupTimer?;
|
|
669
|
+
constructor(factory: () => Promise<T> | T, onCleanup: (value: T | null) => void | Promise<void>, options?: SharedResourceOptions);
|
|
670
|
+
/**
|
|
671
|
+
* The current number of active subscribers.
|
|
672
|
+
*/
|
|
673
|
+
get subscribers(): number;
|
|
674
|
+
/**
|
|
675
|
+
* Increments the reference count and ensures the resource is initialized.
|
|
676
|
+
* If a cleanup was scheduled but hasn't executed yet, it is cancelled.
|
|
677
|
+
*
|
|
678
|
+
* @returns The initialized resource.
|
|
679
|
+
*/
|
|
680
|
+
acquire(): Promise<T>;
|
|
681
|
+
/**
|
|
682
|
+
* Decrements the reference count.
|
|
683
|
+
* If the count reaches zero, the cleanup process is scheduled according to the grace period.
|
|
684
|
+
*/
|
|
685
|
+
release(): void;
|
|
686
|
+
/**
|
|
687
|
+
* Returns the current value synchronously if it has been successfully initialized.
|
|
688
|
+
* Returns null if initialization is pending, failed, or hasn't started.
|
|
689
|
+
*/
|
|
690
|
+
peek(): T | null;
|
|
691
|
+
/**
|
|
692
|
+
* Forcibly tears down the resource, ignoring the reference count and grace period.
|
|
693
|
+
* Useful for emergency teardowns (e.g., container disposal).
|
|
694
|
+
*/
|
|
695
|
+
forceCleanup(): void;
|
|
696
|
+
/**
|
|
697
|
+
* Cancels any scheduled cleanup tasks.
|
|
698
|
+
* This is the core mechanism that prevents React StrictMode from destroying the resource.
|
|
699
|
+
*/
|
|
700
|
+
private cancelPendingCleanup;
|
|
701
|
+
/**
|
|
702
|
+
* Determines how to schedule the cleanup based on the configured options.
|
|
703
|
+
*/
|
|
704
|
+
private scheduleCleanup;
|
|
705
|
+
/**
|
|
706
|
+
* Performs the actual teardown of the resource and resets the initialization state.
|
|
707
|
+
*/
|
|
708
|
+
private executeCleanup;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
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 };
|
package/index.d.ts
CHANGED
|
@@ -122,8 +122,112 @@ declare class Debouncer<T = void> {
|
|
|
122
122
|
private _fire;
|
|
123
123
|
}
|
|
124
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
|
+
|
|
125
229
|
/** Represents all errors within the sync system */
|
|
126
|
-
declare class SyncError extends
|
|
230
|
+
declare class SyncError extends SystemError {
|
|
127
231
|
constructor(message: string, cause?: unknown);
|
|
128
232
|
}
|
|
129
233
|
declare class TimeoutError extends SyncError {
|
|
@@ -539,4 +643,69 @@ declare class Serializer<T = void> {
|
|
|
539
643
|
running(): boolean;
|
|
540
644
|
}
|
|
541
645
|
|
|
542
|
-
|
|
646
|
+
interface SharedResourceOptions {
|
|
647
|
+
/**
|
|
648
|
+
* How long to wait after the last subscriber leaves before cleaning up.
|
|
649
|
+
* - "microtask": (Default) Waits until the end of the current synchronous execution tick.
|
|
650
|
+
* Perfect for React StrictMode or concurrent rendering.
|
|
651
|
+
* - number: Waits for the specified milliseconds. Useful for debouncing rapid reconnects.
|
|
652
|
+
* - "sync": Cleans up immediately (bypasses the grace period entirely).
|
|
653
|
+
*/
|
|
654
|
+
gracePeriod?: "microtask" | "sync" | number;
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Manages the lifecycle of a reference-counted shared resource.
|
|
658
|
+
* Ensures the resource is created exactly once on the first acquisition,
|
|
659
|
+
* and cleaned up only when the last subscriber releases it (after an optional grace period).
|
|
660
|
+
*/
|
|
661
|
+
declare class SharedResource<T> {
|
|
662
|
+
private readonly factory;
|
|
663
|
+
private readonly onCleanup;
|
|
664
|
+
private readonly options;
|
|
665
|
+
private _count;
|
|
666
|
+
private readonly init;
|
|
667
|
+
private pendingMicrotask;
|
|
668
|
+
private cleanupTimer?;
|
|
669
|
+
constructor(factory: () => Promise<T> | T, onCleanup: (value: T | null) => void | Promise<void>, options?: SharedResourceOptions);
|
|
670
|
+
/**
|
|
671
|
+
* The current number of active subscribers.
|
|
672
|
+
*/
|
|
673
|
+
get subscribers(): number;
|
|
674
|
+
/**
|
|
675
|
+
* Increments the reference count and ensures the resource is initialized.
|
|
676
|
+
* If a cleanup was scheduled but hasn't executed yet, it is cancelled.
|
|
677
|
+
*
|
|
678
|
+
* @returns The initialized resource.
|
|
679
|
+
*/
|
|
680
|
+
acquire(): Promise<T>;
|
|
681
|
+
/**
|
|
682
|
+
* Decrements the reference count.
|
|
683
|
+
* If the count reaches zero, the cleanup process is scheduled according to the grace period.
|
|
684
|
+
*/
|
|
685
|
+
release(): void;
|
|
686
|
+
/**
|
|
687
|
+
* Returns the current value synchronously if it has been successfully initialized.
|
|
688
|
+
* Returns null if initialization is pending, failed, or hasn't started.
|
|
689
|
+
*/
|
|
690
|
+
peek(): T | null;
|
|
691
|
+
/**
|
|
692
|
+
* Forcibly tears down the resource, ignoring the reference count and grace period.
|
|
693
|
+
* Useful for emergency teardowns (e.g., container disposal).
|
|
694
|
+
*/
|
|
695
|
+
forceCleanup(): void;
|
|
696
|
+
/**
|
|
697
|
+
* Cancels any scheduled cleanup tasks.
|
|
698
|
+
* This is the core mechanism that prevents React StrictMode from destroying the resource.
|
|
699
|
+
*/
|
|
700
|
+
private cancelPendingCleanup;
|
|
701
|
+
/**
|
|
702
|
+
* Determines how to schedule the cleanup based on the configured options.
|
|
703
|
+
*/
|
|
704
|
+
private scheduleCleanup;
|
|
705
|
+
/**
|
|
706
|
+
* Performs the actual teardown of the resource and resets the initialization state.
|
|
707
|
+
*/
|
|
708
|
+
private executeCleanup;
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
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 };
|
package/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var e=class e extends Error{constructor(t,i){super(t,{cause:i}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},t=class extends e{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},i=class extends e{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},r=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let i;const r=new Promise((e=>i=e));if(this.waiters.push(i),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,o)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(i);-1!==e&&this.waiters.splice(e,1),o(new t("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}};exports.Debouncer=class{_delay;_leading;_timer;_pendingFn;_pendingResolvers=[];_leadingFired=!1;constructor(e){this._delay=e?.delay??300,this._leading=e?.leading??!1}do(e){return new Promise((t=>{this._enqueue(e,t)}))}fire(e){this._enqueue(e,void 0)}_enqueue(e,t){if(this._pendingFn=e,t&&this._pendingResolvers.push(t),this._leading&&!this._leadingFired)return this._leadingFired=!0,this._fire(),clearTimeout(this._timer),void(this._timer=setTimeout((()=>{this._leadingFired=!1,void 0!==this._pendingFn&&this._fire()}),this._delay));clearTimeout(this._timer),this._timer=setTimeout((()=>{this._leadingFired=!1,this._fire()}),this._delay)}cancel(){clearTimeout(this._timer),this._timer=void 0,this._pendingFn=void 0,this._leadingFired=!1;const e=this._pendingResolvers.splice(0);for(const t of e)t({status:"cancelled"})}async flush(){return this._pendingFn?(clearTimeout(this._timer),this._timer=void 0,this._leadingFired=!1,this._fire()):null}pending(){return void 0!==this._pendingFn}async _fire(){const e=this._pendingFn,t=this._pendingResolvers.splice(0);let i;this._pendingFn=void 0;try{i={status:"ok",value:await e()}}catch(e){i={status:"error",error:e}}for(const e of t)e(i);return i}},exports.Latch=class{_open=!1;_resolve;_promise;constructor(){this._promise=new Promise((e=>{this._resolve=e}))}open(){this._open||(this._open=!0,this._resolve())}async wait(e){if(this._open)return;if(null==e)return this._promise;let i;await Promise.race([this._promise.then((()=>clearTimeout(i))),new Promise(((r,s)=>{i=setTimeout((()=>s(new t("Latch timed out"))),e)}))])}isOpen(){return this._open}},exports.Mutex=r,exports.Once=class{mutex=new r({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,i,r="Operation timed out"){if(null==i)return e;let s;return Promise.race([e.then((e=>(clearTimeout(s),e))),new Promise(((e,o)=>{s=setTimeout((()=>o(new t(r))),i)}))])}},exports.OnceExecutionConflict=class extends e{constructor(e){super("[Once] A method has already been registered!",e)}},exports.RWMutex=class{_readers=0;_writeLocked=!1;_pendingWriters=0;_yieldMode;readerWaiters=[];writerWaiters=[];constructor(e){this._yieldMode=e?.yieldMode??"microtask"}async rlock(e){if(!this._writeLocked&&0===this._pendingWriters)return void this._readers++;let i;const r=new Promise((e=>i=e));if(this.readerWaiters.push(i),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,o)=>{s=setTimeout((()=>{const e=this.readerWaiters.indexOf(i);-1!==e&&this.readerWaiters.splice(e,1),o(new t("RWMutex rlock timed out"))}),e)}))])}runlock(){if(this._readers<=0)throw new Error("RWMutex: runlock called without a matching rlock");this._readers--,this._tryWakeWriter()}async lock(e){if(!this._writeLocked&&0===this._readers)return void(this._writeLocked=!0);let i;this._pendingWriters++;const r=new Promise((e=>i=e));if(this.writerWaiters.push(i),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,o)=>{s=setTimeout((()=>{const e=this.writerWaiters.indexOf(i);-1!==e&&(this.writerWaiters.splice(e,1),this._pendingWriters--),o(new t("RWMutex lock timed out"))}),e)}))])}unlock(){if(!this._writeLocked)throw new Error("RWMutex: unlock called without a matching lock");this._writeLocked=!1,this._tryWakeWriter()||this._wakeAllReaders()}async read(e,t){await this.rlock(t);try{return await e()}finally{this.runlock()}}async write(e,t){await this.lock(t);try{return await e()}finally{this.unlock()}}writeLocked(){return this._writeLocked}readers(){return this._readers}pendingWriters(){return this._pendingWriters}pendingReaders(){return this.readerWaiters.length}_tryWakeWriter(){if(this._writeLocked||this._readers>0)return!1;const e=this.writerWaiters.shift();return!!e&&(this._writeLocked=!0,this._pendingWriters--,this._schedule(e),!0)}_wakeAllReaders(){const e=this.readerWaiters.splice(0);if(0!==e.length){this._readers+=e.length;for(const t of e)this._schedule(t)}}_schedule(e){"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0)}},exports.Semaphore=class{_slots;_available;_capacity;_yieldMode;waiters=[];constructor(e){if(this._slots=e?.slots??1,this._available=this._slots,this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask",this._slots<1)throw new Error("Semaphore slots must be >= 1")}async acquire(e){if(this._available>0)return void this._available--;if(this.waiters.length>=this._capacity)throw new Error(`Semaphore queue is full (capacity: ${this._capacity})`);let i;const r=new Promise((e=>i=e));if(this.waiters.push(i),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,o)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(i);-1!==e&&this.waiters.splice(e,1),o(new t("Semaphore acquire timed out"))}),e)}))])}tryAcquire(){return this._available>0&&(this._available--,!0)}release(){if(this._available>=this._slots)throw new Error("Semaphore released more times than acquired");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._available++}async run(e,t){await this.acquire(t);try{return await e()}finally{this.release()}}available(){return this._available}pending(){return this.waiters.length}slots(){return this._slots}},exports.Serializer=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new r({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new i};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let r,s=null;try{if(this._done)throw new i;s=await e(),this._lastValue=s,this._lastError=void 0,this._hasRun=!0}catch(e){r=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:s,error:r}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},exports.SerializerExecutionDone=i,exports.SyncError=e,exports.TimeoutError=t;
|
|
1
|
+
"use strict";var e={VALIDATION_FAILED:{code:"VAL-001",name:"VALIDATION_FAILED",description:"Input validation failed due to one or more invalid fields",category:"validation",httpStatus:400,logLevel:"warn"},REQUIRED_FIELD_MISSING:{code:"VAL-002",name:"REQUIRED_FIELD_MISSING",description:"A required field was not provided in the request",category:"validation",httpStatus:400,logLevel:"warn"},INVALID_FORMAT:{code:"VAL-003",name:"INVALID_FORMAT",description:"Field value does not match expected format",category:"validation",httpStatus:400,logLevel:"warn"},NOT_FOUND:{code:"DB-001-NF",name:"NOT_FOUND",description:"The requested resource could not be found",category:"database",httpStatus:404,logLevel:"info",action:"Verify the resource identifier exists before accessing"},DUPLICATE_KEY:{code:"DB-002-DUP",name:"DUPLICATE_KEY",description:"A unique constraint violation occurred",category:"database",httpStatus:409,logLevel:"warn",action:"Check if the resource already exists before creation"},RESOURCE_LOCKED:{code:"DB-003-LOCK",name:"RESOURCE_LOCKED",description:"The resource is currently locked by another operation",category:"database",httpStatus:409,logLevel:"warn",action:"Retry the operation after a brief delay"},PERMISSION_DENIED:{code:"AUTH-001-DENIED",name:"PERMISSION_DENIED",description:"The authenticated user lacks permission for this operation",category:"auth",httpStatus:403,logLevel:"warn",action:"Check user roles and permissions"},UNAUTHENTICATED:{code:"AUTH-002-UNAUTH",name:"UNAUTHENTICATED",description:"Authentication is required for this operation",category:"auth",httpStatus:401,logLevel:"info",action:"Provide valid authentication credentials"},INVALID_COMMAND:{code:"BUS-001",name:"INVALID_COMMAND",description:"The command or operation is invalid for the current state",category:"business",httpStatus:400,logLevel:"warn"},OPERATION_ABORTED:{code:"BUS-002-ABORT",name:"OPERATION_ABORTED",description:"The operation was explicitly aborted",category:"business",httpStatus:409,logLevel:"info"},INTERNAL_ERROR:{code:"SYS-001",name:"INTERNAL_ERROR",description:"An unexpected internal error occurred",category:"system",httpStatus:500,logLevel:"error",action:"Check system logs for stack traces and diagnostic information"},BACKEND_ERROR:{code:"SYS-002",name:"BACKEND_ERROR",description:"An error occurred in a backend service",category:"system",httpStatus:502,logLevel:"error"},CONCURRENCY_ERROR:{code:"CON-001",name:"CONCURRENCY_ERROR",description:"A concurrency conflict occurred during the operation",category:"concurrency",httpStatus:409,logLevel:"warn",action:"Retry the operation with updated data"}},t=new Map;var i=class i extends Error{code;codeMetadata;severity;path;operation;issues;cause;constructor(s){const r={...function(i){const s=Object.values(e).find((e=>e.code===i));if(s)return s;return t.get(i)||{code:i,name:i.replace(/-/g,"_"),description:`Unknown error: ${i}`,category:"custom",httpStatus:500,logLevel:"error",action:"Check if this error code is properly registered or handle as unknown error"}}(s.code),...s.metadata,code:s.code};super(s.message??r.description),this.name="SystemError",this.code=s.code,this.codeMetadata=r,this.severity=s.severity??"error",this.path=s.path,this.operation=s.operation,this.issues=s.issues??[],this.cause=s.cause,Object.setPrototypeOf(this,i.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,i)}withPath(e){return new i({code:this.code,message:this.message,severity:this.severity,path:e,operation:this.operation,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withOperation(e){return new i({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:e,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withIssue(e){return new i({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,e],cause:this.cause,metadata:this.codeMetadata})}withIssues(e){return new i({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,...e],cause:this.cause,metadata:this.codeMetadata})}withCause(e){return new i({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:this.issues,cause:e,metadata:this.codeMetadata})}getHttpStatus(){return this.codeMetadata.httpStatus}toLogEntry(){return{name:this.name,code:this.code,category:this.codeMetadata.category,message:this.message,path:this.path,operation:this.operation,issues:this.issues,cause:this.cause instanceof Error?this.cause.message:this.cause,stack:this.stack,timestamp:(new Date).toISOString()}}toString(){let e=`[${this.code}] ${this.message} (${this.codeMetadata.category})`;return this.path&&(e+=` at '${this.path}'`),this.operation&&(e+=` during '${this.operation}'`),this.issues.length>0&&(e+="\nIssues:\n"+this.issues.map(((e,t)=>` ${t+1}. ${e.message} [${e.code}]`)).join("\n")),this.cause&&(e+=`\nCause: ${this.cause instanceof Error?this.cause.message:String(this.cause)}`),e}},s=class e extends i{constructor(t,i){super({code:"SYNC_ERROR",message:t,cause:i}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},r=class e extends s{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},o=class e extends s{constructor(t){super("[Serializer] The serializer has been marked as done!",t),this.name="SerializerExecutionDone",Object.setPrototypeOf(this,e.prototype)}},a=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const i=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await i;let s;await Promise.race([i.then((()=>clearTimeout(s))),new Promise(((i,o)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),o(new r("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},n=class{mutex=new a({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,i="Operation timed out"){if(null==t)return e;let s;return Promise.race([e.then((e=>(clearTimeout(s),e))),new Promise(((e,o)=>{s=setTimeout((()=>o(new r(i))),t)}))])}};exports.Debouncer=class{_delay;_leading;_timer;_pendingFn;_pendingResolvers=[];_leadingFired=!1;constructor(e){this._delay=e?.delay??300,this._leading=e?.leading??!1}do(e){return new Promise((t=>{this._enqueue(e,t)}))}fire(e){this._enqueue(e,void 0)}_enqueue(e,t){if(this._pendingFn=e,t&&this._pendingResolvers.push(t),this._leading&&!this._leadingFired)return this._leadingFired=!0,this._fire(),clearTimeout(this._timer),void(this._timer=setTimeout((()=>{this._leadingFired=!1,void 0!==this._pendingFn&&this._fire()}),this._delay));clearTimeout(this._timer),this._timer=setTimeout((()=>{this._leadingFired=!1,this._fire()}),this._delay)}cancel(){clearTimeout(this._timer),this._timer=void 0,this._pendingFn=void 0,this._leadingFired=!1;const e=this._pendingResolvers.splice(0);for(const t of e)t({status:"cancelled"})}async flush(){return this._pendingFn?(clearTimeout(this._timer),this._timer=void 0,this._leadingFired=!1,this._fire()):null}pending(){return void 0!==this._pendingFn}async _fire(){const e=this._pendingFn,t=this._pendingResolvers.splice(0);let i;this._pendingFn=void 0;try{i={status:"ok",value:await e()}}catch(e){i={status:"error",error:e}}for(const e of t)e(i);return i}},exports.Latch=class{_open=!1;_resolve;_promise;constructor(){this._promise=new Promise((e=>{this._resolve=e}))}open(){this._open||(this._open=!0,this._resolve())}async wait(e){if(this._open)return;if(null==e)return this._promise;let t;await Promise.race([this._promise.then((()=>clearTimeout(t))),new Promise(((i,s)=>{t=setTimeout((()=>s(new r("Latch timed out"))),e)}))])}isOpen(){return this._open}},exports.Mutex=a,exports.Once=n,exports.OnceExecutionConflict=class e extends s{constructor(t){super("[Once] A method has already been registered!",t),this.name="OnceExecutionConflict",Object.setPrototypeOf(this,e.prototype)}},exports.RWMutex=class{_readers=0;_writeLocked=!1;_pendingWriters=0;_yieldMode;readerWaiters=[];writerWaiters=[];constructor(e){this._yieldMode=e?.yieldMode??"microtask"}async rlock(e){if(!this._writeLocked&&0===this._pendingWriters)return void this._readers++;let t;const i=new Promise((e=>t=e));if(this.readerWaiters.push(t),null==e)return void await i;let s;await Promise.race([i.then((()=>clearTimeout(s))),new Promise(((i,o)=>{s=setTimeout((()=>{const e=this.readerWaiters.indexOf(t);-1!==e&&this.readerWaiters.splice(e,1),o(new r("RWMutex rlock timed out"))}),e)}))])}runlock(){if(this._readers<=0)throw new Error("RWMutex: runlock called without a matching rlock");this._readers--,this._tryWakeWriter()}async lock(e){if(!this._writeLocked&&0===this._readers)return void(this._writeLocked=!0);let t;this._pendingWriters++;const i=new Promise((e=>t=e));if(this.writerWaiters.push(t),null==e)return void await i;let s;await Promise.race([i.then((()=>clearTimeout(s))),new Promise(((i,o)=>{s=setTimeout((()=>{const e=this.writerWaiters.indexOf(t);-1!==e&&(this.writerWaiters.splice(e,1),this._pendingWriters--),o(new r("RWMutex lock timed out"))}),e)}))])}unlock(){if(!this._writeLocked)throw new Error("RWMutex: unlock called without a matching lock");this._writeLocked=!1,this._tryWakeWriter()||this._wakeAllReaders()}async read(e,t){await this.rlock(t);try{return await e()}finally{this.runlock()}}async write(e,t){await this.lock(t);try{return await e()}finally{this.unlock()}}writeLocked(){return this._writeLocked}readers(){return this._readers}pendingWriters(){return this._pendingWriters}pendingReaders(){return this.readerWaiters.length}_tryWakeWriter(){if(this._writeLocked||this._readers>0)return!1;const e=this.writerWaiters.shift();return!!e&&(this._writeLocked=!0,this._pendingWriters--,this._schedule(e),!0)}_wakeAllReaders(){const e=this.readerWaiters.splice(0);if(0!==e.length){this._readers+=e.length;for(const t of e)this._schedule(t)}}_schedule(e){"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0)}},exports.Semaphore=class{_slots;_available;_capacity;_yieldMode;waiters=[];constructor(e){if(this._slots=e?.slots??1,this._available=this._slots,this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask",this._slots<1)throw new Error("Semaphore slots must be >= 1")}async acquire(e){if(this._available>0)return void this._available--;if(this.waiters.length>=this._capacity)throw new Error(`Semaphore queue is full (capacity: ${this._capacity})`);let t;const i=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await i;let s;await Promise.race([i.then((()=>clearTimeout(s))),new Promise(((i,o)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),o(new r("Semaphore acquire timed out"))}),e)}))])}tryAcquire(){return this._available>0&&(this._available--,!0)}release(){if(this._available>=this._slots)throw new Error("Semaphore released more times than acquired");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._available++}async run(e,t){await this.acquire(t);try{return await e()}finally{this.release()}}available(){return this._available}pending(){return this.waiters.length}slots(){return this._slots}},exports.Serializer=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new a({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new o};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let i,s=null;try{if(this._done)throw new o;s=await e(),this._lastValue=s,this._lastError=void 0,this._hasRun=!0}catch(e){i=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:s,error:i}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},exports.SerializerExecutionDone=o,exports.SharedResource=class{constructor(e,t,i={}){this.factory=e,this.onCleanup=t,this.options=i}_count=0;init=new n({retry:!1,throws:!1});pendingMicrotask=!1;cleanupTimer;get subscribers(){return this._count}async acquire(){this.cancelPendingCleanup(),this._count++;const e=await this.init.do(this.factory);if(e.error)throw e.error;return e.value}release(){this._count<=0?console.warn("SharedResource.release() called, but count is already 0."):(this._count--,0===this._count&&this.scheduleCleanup())}peek(){const e=this.init.peek();return e.error?null:e.value}forceCleanup(){this.cancelPendingCleanup(),this._count=0,this.executeCleanup()}cancelPendingCleanup(){this.pendingMicrotask=!1,void 0!==this.cleanupTimer&&(clearTimeout(this.cleanupTimer),this.cleanupTimer=void 0)}scheduleCleanup(){const e=this.options.gracePeriod??"microtask";if("sync"!==e)return"microtask"===e?(this.pendingMicrotask=!0,void queueMicrotask((()=>{!this.pendingMicrotask||this._count>0||(this.pendingMicrotask=!1,this.executeCleanup())}))):void(this.cleanupTimer=setTimeout((()=>{this.cleanupTimer=void 0,this._count>0||this.executeCleanup()}),e));this.executeCleanup()}executeCleanup(){const e=this.init.peek();try{this.onCleanup(e.value)}catch(e){console.error("[SharedResource] Error during cleanup callback:",e)}this.init.running()||this.init.reset()}},exports.SyncError=s,exports.TimeoutError=r;
|
package/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var e=class{_delay;_leading;_timer;_pendingFn;_pendingResolvers=[];_leadingFired=!1;constructor(e){this._delay=e?.delay??300,this._leading=e?.leading??!1}do(e){return new Promise((t=>{this._enqueue(e,t)}))}fire(e){this._enqueue(e,void 0)}_enqueue(e,t){if(this._pendingFn=e,t&&this._pendingResolvers.push(t),this._leading&&!this._leadingFired)return this._leadingFired=!0,this._fire(),clearTimeout(this._timer),void(this._timer=setTimeout((()=>{this._leadingFired=!1,void 0!==this._pendingFn&&this._fire()}),this._delay));clearTimeout(this._timer),this._timer=setTimeout((()=>{this._leadingFired=!1,this._fire()}),this._delay)}cancel(){clearTimeout(this._timer),this._timer=void 0,this._pendingFn=void 0,this._leadingFired=!1;const e=this._pendingResolvers.splice(0);for(const t of e)t({status:"cancelled"})}async flush(){return this._pendingFn?(clearTimeout(this._timer),this._timer=void 0,this._leadingFired=!1,this._fire()):null}pending(){return void 0!==this._pendingFn}async _fire(){const e=this._pendingFn,t=this._pendingResolvers.splice(0);let i;this._pendingFn=void 0;try{i={status:"ok",value:await e()}}catch(e){i={status:"error",error:e}}for(const e of t)e(i);return i}},t=class e extends Error{constructor(t,i){super(t,{cause:i}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},i=class extends t{constructor(e){super(`[ArtifactContainer] Operation timed out: ${e}`)}},r=class extends t{constructor(e){super("[Once] A method has already been registered!",e)}},s=class extends t{constructor(e){super("[Serializer] The serializer has been marked as done!",e)}},o=class{_open=!1;_resolve;_promise;constructor(){this._promise=new Promise((e=>{this._resolve=e}))}open(){this._open||(this._open=!0,this._resolve())}async wait(e){if(this._open)return;if(null==e)return this._promise;let t;await Promise.race([this._promise.then((()=>clearTimeout(t))),new Promise(((r,s)=>{t=setTimeout((()=>s(new i("Latch timed out"))),e)}))])}isOpen(){return this._open}},n=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,o)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),o(new i("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},a=class{mutex=new n({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,r="Operation timed out"){if(null==t)return e;let s;return Promise.race([e.then((e=>(clearTimeout(s),e))),new Promise(((e,o)=>{s=setTimeout((()=>o(new i(r))),t)}))])}},h=class{_readers=0;_writeLocked=!1;_pendingWriters=0;_yieldMode;readerWaiters=[];writerWaiters=[];constructor(e){this._yieldMode=e?.yieldMode??"microtask"}async rlock(e){if(!this._writeLocked&&0===this._pendingWriters)return void this._readers++;let t;const r=new Promise((e=>t=e));if(this.readerWaiters.push(t),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,o)=>{s=setTimeout((()=>{const e=this.readerWaiters.indexOf(t);-1!==e&&this.readerWaiters.splice(e,1),o(new i("RWMutex rlock timed out"))}),e)}))])}runlock(){if(this._readers<=0)throw new Error("RWMutex: runlock called without a matching rlock");this._readers--,this._tryWakeWriter()}async lock(e){if(!this._writeLocked&&0===this._readers)return void(this._writeLocked=!0);let t;this._pendingWriters++;const r=new Promise((e=>t=e));if(this.writerWaiters.push(t),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,o)=>{s=setTimeout((()=>{const e=this.writerWaiters.indexOf(t);-1!==e&&(this.writerWaiters.splice(e,1),this._pendingWriters--),o(new i("RWMutex lock timed out"))}),e)}))])}unlock(){if(!this._writeLocked)throw new Error("RWMutex: unlock called without a matching lock");this._writeLocked=!1,this._tryWakeWriter()||this._wakeAllReaders()}async read(e,t){await this.rlock(t);try{return await e()}finally{this.runlock()}}async write(e,t){await this.lock(t);try{return await e()}finally{this.unlock()}}writeLocked(){return this._writeLocked}readers(){return this._readers}pendingWriters(){return this._pendingWriters}pendingReaders(){return this.readerWaiters.length}_tryWakeWriter(){if(this._writeLocked||this._readers>0)return!1;const e=this.writerWaiters.shift();return!!e&&(this._writeLocked=!0,this._pendingWriters--,this._schedule(e),!0)}_wakeAllReaders(){const e=this.readerWaiters.splice(0);if(0!==e.length){this._readers+=e.length;for(const t of e)this._schedule(t)}}_schedule(e){"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0)}},l=class{_slots;_available;_capacity;_yieldMode;waiters=[];constructor(e){if(this._slots=e?.slots??1,this._available=this._slots,this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask",this._slots<1)throw new Error("Semaphore slots must be >= 1")}async acquire(e){if(this._available>0)return void this._available--;if(this.waiters.length>=this._capacity)throw new Error(`Semaphore queue is full (capacity: ${this._capacity})`);let t;const r=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await r;let s;await Promise.race([r.then((()=>clearTimeout(s))),new Promise(((r,o)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),o(new i("Semaphore acquire timed out"))}),e)}))])}tryAcquire(){return this._available>0&&(this._available--,!0)}release(){if(this._available>=this._slots)throw new Error("Semaphore released more times than acquired");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._available++}async run(e,t){await this.acquire(t);try{return await e()}finally{this.release()}}available(){return this._available}pending(){return this.waiters.length}slots(){return this._slots}},c=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new n({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new s};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let i,r=null;try{if(this._done)throw new s;r=await e(),this._lastValue=r,this._lastError=void 0,this._hasRun=!0}catch(e){i=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:r,error:i}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}};export{e as Debouncer,o as Latch,n as Mutex,a as Once,r as OnceExecutionConflict,h as RWMutex,l as Semaphore,c as Serializer,s as SerializerExecutionDone,t as SyncError,i as TimeoutError};
|
|
1
|
+
var e=class{_delay;_leading;_timer;_pendingFn;_pendingResolvers=[];_leadingFired=!1;constructor(e){this._delay=e?.delay??300,this._leading=e?.leading??!1}do(e){return new Promise((t=>{this._enqueue(e,t)}))}fire(e){this._enqueue(e,void 0)}_enqueue(e,t){if(this._pendingFn=e,t&&this._pendingResolvers.push(t),this._leading&&!this._leadingFired)return this._leadingFired=!0,this._fire(),clearTimeout(this._timer),void(this._timer=setTimeout((()=>{this._leadingFired=!1,void 0!==this._pendingFn&&this._fire()}),this._delay));clearTimeout(this._timer),this._timer=setTimeout((()=>{this._leadingFired=!1,this._fire()}),this._delay)}cancel(){clearTimeout(this._timer),this._timer=void 0,this._pendingFn=void 0,this._leadingFired=!1;const e=this._pendingResolvers.splice(0);for(const t of e)t({status:"cancelled"})}async flush(){return this._pendingFn?(clearTimeout(this._timer),this._timer=void 0,this._leadingFired=!1,this._fire()):null}pending(){return void 0!==this._pendingFn}async _fire(){const e=this._pendingFn,t=this._pendingResolvers.splice(0);let i;this._pendingFn=void 0;try{i={status:"ok",value:await e()}}catch(e){i={status:"error",error:e}}for(const e of t)e(i);return i}},t={VALIDATION_FAILED:{code:"VAL-001",name:"VALIDATION_FAILED",description:"Input validation failed due to one or more invalid fields",category:"validation",httpStatus:400,logLevel:"warn"},REQUIRED_FIELD_MISSING:{code:"VAL-002",name:"REQUIRED_FIELD_MISSING",description:"A required field was not provided in the request",category:"validation",httpStatus:400,logLevel:"warn"},INVALID_FORMAT:{code:"VAL-003",name:"INVALID_FORMAT",description:"Field value does not match expected format",category:"validation",httpStatus:400,logLevel:"warn"},NOT_FOUND:{code:"DB-001-NF",name:"NOT_FOUND",description:"The requested resource could not be found",category:"database",httpStatus:404,logLevel:"info",action:"Verify the resource identifier exists before accessing"},DUPLICATE_KEY:{code:"DB-002-DUP",name:"DUPLICATE_KEY",description:"A unique constraint violation occurred",category:"database",httpStatus:409,logLevel:"warn",action:"Check if the resource already exists before creation"},RESOURCE_LOCKED:{code:"DB-003-LOCK",name:"RESOURCE_LOCKED",description:"The resource is currently locked by another operation",category:"database",httpStatus:409,logLevel:"warn",action:"Retry the operation after a brief delay"},PERMISSION_DENIED:{code:"AUTH-001-DENIED",name:"PERMISSION_DENIED",description:"The authenticated user lacks permission for this operation",category:"auth",httpStatus:403,logLevel:"warn",action:"Check user roles and permissions"},UNAUTHENTICATED:{code:"AUTH-002-UNAUTH",name:"UNAUTHENTICATED",description:"Authentication is required for this operation",category:"auth",httpStatus:401,logLevel:"info",action:"Provide valid authentication credentials"},INVALID_COMMAND:{code:"BUS-001",name:"INVALID_COMMAND",description:"The command or operation is invalid for the current state",category:"business",httpStatus:400,logLevel:"warn"},OPERATION_ABORTED:{code:"BUS-002-ABORT",name:"OPERATION_ABORTED",description:"The operation was explicitly aborted",category:"business",httpStatus:409,logLevel:"info"},INTERNAL_ERROR:{code:"SYS-001",name:"INTERNAL_ERROR",description:"An unexpected internal error occurred",category:"system",httpStatus:500,logLevel:"error",action:"Check system logs for stack traces and diagnostic information"},BACKEND_ERROR:{code:"SYS-002",name:"BACKEND_ERROR",description:"An error occurred in a backend service",category:"system",httpStatus:502,logLevel:"error"},CONCURRENCY_ERROR:{code:"CON-001",name:"CONCURRENCY_ERROR",description:"A concurrency conflict occurred during the operation",category:"concurrency",httpStatus:409,logLevel:"warn",action:"Retry the operation with updated data"}},i=new Map;var s=class e extends Error{code;codeMetadata;severity;path;operation;issues;cause;constructor(s){const r={...function(e){const s=Object.values(t).find((t=>t.code===e));if(s)return s;return i.get(e)||{code:e,name:e.replace(/-/g,"_"),description:`Unknown error: ${e}`,category:"custom",httpStatus:500,logLevel:"error",action:"Check if this error code is properly registered or handle as unknown error"}}(s.code),...s.metadata,code:s.code};super(s.message??r.description),this.name="SystemError",this.code=s.code,this.codeMetadata=r,this.severity=s.severity??"error",this.path=s.path,this.operation=s.operation,this.issues=s.issues??[],this.cause=s.cause,Object.setPrototypeOf(this,e.prototype),Error.captureStackTrace&&Error.captureStackTrace(this,e)}withPath(t){return new e({code:this.code,message:this.message,severity:this.severity,path:t,operation:this.operation,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withOperation(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:t,issues:this.issues,cause:this.cause,metadata:this.codeMetadata})}withIssue(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,t],cause:this.cause,metadata:this.codeMetadata})}withIssues(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:[...this.issues,...t],cause:this.cause,metadata:this.codeMetadata})}withCause(t){return new e({code:this.code,message:this.message,severity:this.severity,path:this.path,operation:this.operation,issues:this.issues,cause:t,metadata:this.codeMetadata})}getHttpStatus(){return this.codeMetadata.httpStatus}toLogEntry(){return{name:this.name,code:this.code,category:this.codeMetadata.category,message:this.message,path:this.path,operation:this.operation,issues:this.issues,cause:this.cause instanceof Error?this.cause.message:this.cause,stack:this.stack,timestamp:(new Date).toISOString()}}toString(){let e=`[${this.code}] ${this.message} (${this.codeMetadata.category})`;return this.path&&(e+=` at '${this.path}'`),this.operation&&(e+=` during '${this.operation}'`),this.issues.length>0&&(e+="\nIssues:\n"+this.issues.map(((e,t)=>` ${t+1}. ${e.message} [${e.code}]`)).join("\n")),this.cause&&(e+=`\nCause: ${this.cause instanceof Error?this.cause.message:String(this.cause)}`),e}},r=class e extends s{constructor(t,i){super({code:"SYNC_ERROR",message:t,cause:i}),this.name="SyncError",Object.setPrototypeOf(this,e.prototype)}},o=class e extends r{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},a=class e extends r{constructor(t){super("[Once] A method has already been registered!",t),this.name="OnceExecutionConflict",Object.setPrototypeOf(this,e.prototype)}},n=class e extends r{constructor(t){super("[Serializer] The serializer has been marked as done!",t),this.name="SerializerExecutionDone",Object.setPrototypeOf(this,e.prototype)}},h=class{_open=!1;_resolve;_promise;constructor(){this._promise=new Promise((e=>{this._resolve=e}))}open(){this._open||(this._open=!0,this._resolve())}async wait(e){if(this._open)return;if(null==e)return this._promise;let t;await Promise.race([this._promise.then((()=>clearTimeout(t))),new Promise(((i,s)=>{t=setTimeout((()=>s(new o("Latch timed out"))),e)}))])}isOpen(){return this._open}},c=class{_locked=!1;_capacity;_yieldMode;waiters=[];constructor(e){this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask"}async lock(e){if(!this._locked)return void(this._locked=!0);if(this.waiters.length>=this._capacity)throw new Error(`Mutex queue is full (capacity: ${this._capacity})`);let t;const i=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await i;let s;await Promise.race([i.then((()=>clearTimeout(s))),new Promise(((i,r)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),r(new o("Mutex lock timed out"))}),e)}))])}tryLock(){return!this._locked&&(this._locked=!0,!0)}unlock(){if(!this._locked)throw new Error("Mutex is not locked");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._locked=!1}locked(){return this._locked}pending(){return this.waiters.length}},u=class{mutex=new c({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}async do(e,t){return this._done?this.peek():this.promise?this._awaitWithTimeout(this.promise,t,"Once do() timed out"):(await this.mutex.lock(),this.promise?(this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")):(this.promise=(async()=>{try{this._value=await e(),this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.retry&&!this._done&&(this.promise=null)}return this.peek()})(),this.mutex.unlock(),this._awaitWithTimeout(this.promise,t,"Once do() timed out")))}doSync(e){if(this._done){if(this.throws&&this._error)throw this._error;return this.peek()}if(this.promise){const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}if(!this.mutex.tryLock()){const e=new Error("Cannot execute doSync: lock is currently held.");if(this.throws)throw e;return{value:null,error:e}}if(this.promise||this._done){if(this.mutex.unlock(),this._done){if(this.throws&&this._error)throw this._error;return this.peek()}const e=new Error("Cannot execute doSync while an async operation is pending.");if(this.throws)throw e;return{value:null,error:e}}try{const t=e();this._value=t,this._done=!0}catch(e){if(this._error=e,this.retry||(this._done=!0),this.throws)throw e}finally{this.mutex.unlock()}return this.peek()}running(){return null!==this.promise&&!this.done()}peek(){return{value:this._value,error:this._error}}get(){if(!this._done)throw new Error("Once operation is not yet complete");if(this._error)throw this._error;return this._value}reset(){if(this.running())throw new Error("Cannot reset Once while an operation is in progress.");this._done=!1,this.promise=null,this._value=null,this._error=void 0}done(){return this._done}current(){return this.promise}_awaitWithTimeout(e,t,i="Operation timed out"){if(null==t)return e;let s;return Promise.race([e.then((e=>(clearTimeout(s),e))),new Promise(((e,r)=>{s=setTimeout((()=>r(new o(i))),t)}))])}},l=class{_readers=0;_writeLocked=!1;_pendingWriters=0;_yieldMode;readerWaiters=[];writerWaiters=[];constructor(e){this._yieldMode=e?.yieldMode??"microtask"}async rlock(e){if(!this._writeLocked&&0===this._pendingWriters)return void this._readers++;let t;const i=new Promise((e=>t=e));if(this.readerWaiters.push(t),null==e)return void await i;let s;await Promise.race([i.then((()=>clearTimeout(s))),new Promise(((i,r)=>{s=setTimeout((()=>{const e=this.readerWaiters.indexOf(t);-1!==e&&this.readerWaiters.splice(e,1),r(new o("RWMutex rlock timed out"))}),e)}))])}runlock(){if(this._readers<=0)throw new Error("RWMutex: runlock called without a matching rlock");this._readers--,this._tryWakeWriter()}async lock(e){if(!this._writeLocked&&0===this._readers)return void(this._writeLocked=!0);let t;this._pendingWriters++;const i=new Promise((e=>t=e));if(this.writerWaiters.push(t),null==e)return void await i;let s;await Promise.race([i.then((()=>clearTimeout(s))),new Promise(((i,r)=>{s=setTimeout((()=>{const e=this.writerWaiters.indexOf(t);-1!==e&&(this.writerWaiters.splice(e,1),this._pendingWriters--),r(new o("RWMutex lock timed out"))}),e)}))])}unlock(){if(!this._writeLocked)throw new Error("RWMutex: unlock called without a matching lock");this._writeLocked=!1,this._tryWakeWriter()||this._wakeAllReaders()}async read(e,t){await this.rlock(t);try{return await e()}finally{this.runlock()}}async write(e,t){await this.lock(t);try{return await e()}finally{this.unlock()}}writeLocked(){return this._writeLocked}readers(){return this._readers}pendingWriters(){return this._pendingWriters}pendingReaders(){return this.readerWaiters.length}_tryWakeWriter(){if(this._writeLocked||this._readers>0)return!1;const e=this.writerWaiters.shift();return!!e&&(this._writeLocked=!0,this._pendingWriters--,this._schedule(e),!0)}_wakeAllReaders(){const e=this.readerWaiters.splice(0);if(0!==e.length){this._readers+=e.length;for(const t of e)this._schedule(t)}}_schedule(e){"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0)}},d=class{_slots;_available;_capacity;_yieldMode;waiters=[];constructor(e){if(this._slots=e?.slots??1,this._available=this._slots,this._capacity=e?.capacity??1/0,this._yieldMode=e?.yieldMode??"macrotask",this._slots<1)throw new Error("Semaphore slots must be >= 1")}async acquire(e){if(this._available>0)return void this._available--;if(this.waiters.length>=this._capacity)throw new Error(`Semaphore queue is full (capacity: ${this._capacity})`);let t;const i=new Promise((e=>t=e));if(this.waiters.push(t),null==e)return void await i;let s;await Promise.race([i.then((()=>clearTimeout(s))),new Promise(((i,r)=>{s=setTimeout((()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),r(new o("Semaphore acquire timed out"))}),e)}))])}tryAcquire(){return this._available>0&&(this._available--,!0)}release(){if(this._available>=this._slots)throw new Error("Semaphore released more times than acquired");const e=this.waiters.shift();e?"microtask"===this._yieldMode?queueMicrotask(e):setTimeout(e,0):this._available++}async run(e,t){await this.acquire(t);try{return await e()}finally{this.release()}}available(){return this._available}pending(){return this.waiters.length}slots(){return this._slots}},p=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new c({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new n};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let i,s=null;try{if(this._done)throw new n;s=await e(),this._lastValue=s,this._lastError=void 0,this._hasRun=!0}catch(e){i=e,this._lastError=e,this._hasRun=!0}finally{this.mutex.unlock()}return{value:s,error:i}}peek(){return{value:this._lastValue,error:this._lastError}}hasRun(){return this._hasRun}close(){this._done=!0}pending(){return this.mutex.pending()}running(){return this.mutex.locked()}},_=class{constructor(e,t,i={}){this.factory=e,this.onCleanup=t,this.options=i}_count=0;init=new u({retry:!1,throws:!1});pendingMicrotask=!1;cleanupTimer;get subscribers(){return this._count}async acquire(){this.cancelPendingCleanup(),this._count++;const e=await this.init.do(this.factory);if(e.error)throw e.error;return e.value}release(){this._count<=0?console.warn("SharedResource.release() called, but count is already 0."):(this._count--,0===this._count&&this.scheduleCleanup())}peek(){const e=this.init.peek();return e.error?null:e.value}forceCleanup(){this.cancelPendingCleanup(),this._count=0,this.executeCleanup()}cancelPendingCleanup(){this.pendingMicrotask=!1,void 0!==this.cleanupTimer&&(clearTimeout(this.cleanupTimer),this.cleanupTimer=void 0)}scheduleCleanup(){const e=this.options.gracePeriod??"microtask";if("sync"!==e)return"microtask"===e?(this.pendingMicrotask=!0,void queueMicrotask((()=>{!this.pendingMicrotask||this._count>0||(this.pendingMicrotask=!1,this.executeCleanup())}))):void(this.cleanupTimer=setTimeout((()=>{this.cleanupTimer=void 0,this._count>0||this.executeCleanup()}),e));this.executeCleanup()}executeCleanup(){const e=this.init.peek();try{this.onCleanup(e.value)}catch(e){console.error("[SharedResource] Error during cleanup callback:",e)}this.init.running()||this.init.reset()}};export{e as Debouncer,h as Latch,c as Mutex,u as Once,a as OnceExecutionConflict,l as RWMutex,d as Semaphore,p as Serializer,n as SerializerExecutionDone,_ as SharedResource,r as SyncError,o as TimeoutError};
|