@asaidimu/utils-sync 2.2.3 → 2.3.0

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 CHANGED
@@ -131,15 +131,15 @@ type Severity = "error" | "warning" | "info";
131
131
  * Designed to be machine-readable while remaining human-friendly.
132
132
  */
133
133
  interface Issue {
134
- /** Machine-readable identifier (e.g., "REQUIRED_FIELD_MISSING"). */
134
+ /** Machine-readable identifier (e.g., `"REQUIRED_FIELD_MISSING"`). */
135
135
  readonly code: string;
136
136
  /** Human-readable description of the problem. */
137
137
  readonly message: string;
138
- /** Field path in a document or state (e.g., "users.0.email"). */
138
+ /** Field path in a document or state (e.g., `"users.0.email"`). */
139
139
  readonly path?: string;
140
140
  /** Optional array index when the issue relates to a specific element. */
141
141
  readonly index?: number;
142
- /** Seriousness of the issue. Defaults to "error". */
142
+ /** Seriousness of the issue. Defaults to `"error"`. */
143
143
  readonly severity?: Severity;
144
144
  /** Optional detailed explanation, can be multi-line. */
145
145
  readonly description?: string;
@@ -147,81 +147,122 @@ interface Issue {
147
147
  readonly cause?: readonly Issue[];
148
148
  }
149
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)
150
+ * Standardized error code format: `CATEGORY-XXX[-SUFFIX]`
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * // VAL-001 (Validation: required field missing)
155
+ * // DB-001-NF (Database: not found)
156
+ * // AUTH-001-DENIED (Auth: permission denied)
157
+ * ```
155
158
  */
156
159
  interface ErrorCodeMetadata {
157
- /** The formal error code (e.g., "VAL-001") */
160
+ /** The formal unique error code identifier (e.g., `"VAL-001"`). */
158
161
  readonly code: string;
159
- /** Human-readable name for the error type */
162
+ /** Human-readable uppercase name for the error type (e.g., `"VALIDATION_FAILED"`). */
160
163
  readonly name: string;
161
- /** Detailed description of when this error occurs */
164
+ /** Detailed description of when and why this error occurs. */
162
165
  readonly description: string;
163
- /** Suggested action for handling or resolving the error */
166
+ /** Suggested immediate action for engineers or systems to handle or resolve the error. */
164
167
  readonly action?: string;
165
- /** HTTP status code mapping (if applicable) */
168
+ /** HTTP status code mapping for upstream REST APIs (e.g., `404`, `500`). */
166
169
  readonly httpStatus?: number;
167
- /** Category of the error */
170
+ /** Operational category this error belongs to. */
168
171
  readonly category: ErrorCategory;
169
- /** Whether this error should be logged as warning vs error */
172
+ /** Recommended logging level threshold (`"debug" | "info" | "warn" | "error"`). */
170
173
  readonly logLevel?: "debug" | "info" | "warn" | "error";
171
174
  }
175
+ /**
176
+ * Categories classifying the origin and nature of an error.
177
+ */
172
178
  type ErrorCategory = "validation" | "database" | "auth" | "business" | "system" | "network" | "concurrency" | "custom";
173
179
  /**
174
- * SystemError is the primary error type for all operational and validation errors.
175
- * Supports both predefined and custom error codes with full metadata.
180
+ * Configuration options container used when constructing a new `SystemError`.
181
+ */
182
+ interface SystemErrorParams {
183
+ /** The unique registered error code identifier (e.g., `ErrorCodes.INTERNAL_ERROR.code`). */
184
+ code: string;
185
+ /** Explicit error message overrides. If omitted, defaults to the error code's description. */
186
+ message?: string;
187
+ /** Operational severity tier. Defaults to `"error"`. */
188
+ severity?: Severity;
189
+ /** State path or key where the operational failure occurred (e.g., `"users.0.email"`). */
190
+ path?: string;
191
+ /** The function block, track component, or routing process executing during failure. */
192
+ operation?: string;
193
+ /** Flat array of precise granular input issues or schema violations. */
194
+ issues?: readonly Issue[];
195
+ /** The underlying trigger cause. Accepts native `Error` instances, custom errors, or concurrent `Error[]` arrays. */
196
+ cause?: unknown | unknown[];
197
+ /** Ad-hoc modifications overriding base properties mapped from the code registry. */
198
+ metadata?: Partial<Omit<ErrorCodeMetadata, "code" | "category">>;
199
+ }
200
+ /**
201
+ * Primary domain operational error wrapper.
202
+ * Unfolds historical deep error hierarchies into flat, parallel-aware trace timelines.
176
203
  */
177
204
  declare class SystemError extends Error {
205
+ /** The associated error identifier code (e.g., `"SYS-001"`). */
178
206
  readonly code: string;
207
+ /** Static documentation mapping and registration rules bound to this code type. */
179
208
  readonly codeMetadata: ErrorCodeMetadata;
209
+ /** Severity tier grading the operational consequence of this failure. */
180
210
  readonly severity: Severity;
211
+ /** Target state or document path where processing failed. */
181
212
  readonly path?: string;
213
+ /** Active system segment, workflow node, or function context executing during failure. */
182
214
  readonly operation?: string;
215
+ /** Detailed sub-layer list representing structural data validation failures. */
183
216
  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
- });
217
+ /** Raw backing trigger, array of concurrent branches, or source error instance. */
218
+ readonly cause?: unknown | unknown[];
219
+ /** Exact moment this error was instantiated (ISO string). */
220
+ readonly timestamp: string;
195
221
  /**
196
- * Returns a new SystemError with the specified path.
222
+ * Instantiate a structurally traceable `SystemError`.
223
+ * @param params - Configuration parameters outlining the error's state context.
224
+ */
225
+ constructor(params: SystemErrorParams);
226
+ /**
227
+ * Generates a separate immutable clone assigning a target file, state, or field path.
197
228
  */
198
229
  withPath(path: string): SystemError;
199
230
  /**
200
- * Returns a new SystemError with the specified operation name.
231
+ * Generates a separate immutable clone assigning a specific execution block or track tracking context.
201
232
  */
202
233
  withOperation(operation: string): SystemError;
203
234
  /**
204
- * Returns a new SystemError with the specified issue appended.
235
+ * Appends an operational validation structural issue to a fresh clone of this error.
205
236
  */
206
237
  withIssue(issue: Issue): SystemError;
207
238
  /**
208
- * Returns a new SystemError with multiple issues appended.
239
+ * Appends multiple validation issues onto a fresh clone of this error instance.
209
240
  */
210
241
  withIssues(issues: readonly Issue[]): SystemError;
211
242
  /**
212
- * Returns a new SystemError wrapping the specified cause.
243
+ * Maps a backing raw trigger or concurrent array tracking set to a fresh clone of this error instance.
213
244
  */
214
- withCause(cause: unknown): SystemError;
245
+ withCause(cause: unknown | unknown[]): SystemError;
215
246
  /**
216
- * Returns the HTTP status code for this error (if applicable).
247
+ * Retrieves the recommended HTTP Status code mapped to this error's code metadata registry.
217
248
  */
218
249
  getHttpStatus(): number | undefined;
219
250
  /**
220
- * Formats the error for logging with structured metadata.
251
+ * Unrolls execution hierarchies chronologically, isolating parallel pipelines into clear trace frames.
252
+ * Always returns an array of trace nodes.
253
+ */
254
+ private extractChronologicalTrace;
255
+ /**
256
+ * Transforms the error payload into a flattened transmission format.
257
+ * Strips recursive depth in favor of an array-mapped chronological failure `trace`.
258
+ */
259
+ toJSON(): Record<string, unknown>;
260
+ /**
261
+ * Generates a flat payload matching `toJSON` format requirements for centralized platform ingestion engines.
221
262
  */
222
263
  toLogEntry(): Record<string, unknown>;
223
264
  /**
224
- * Produces a human-readable representation suitable for logging.
265
+ * Terminal terminal dump representation formatting details cleanly into plain strings.
225
266
  */
226
267
  toString(): string;
227
268
  }
@@ -715,4 +756,54 @@ declare class SharedResource<T> {
715
756
  private executeCleanup;
716
757
  }
717
758
 
718
- export { Debouncer, type DebouncerCancelled, type DebouncerError, type DebouncerOk, type DebouncerOptions, type DebouncerResult, Latch, Mutex, type MutexOptions, Once, OnceExecutionConflict, type OnceResult, RWMutex, type RWMutexOptions, Semaphore, type SemaphoreOptions, Serializer, SerializerExecutionDone, type SerializerOptions, type SerializerResult, SharedResource, type SharedResourceOptions, SyncError, TimeoutError };
759
+ interface ResourceRegistryOptions<T, K, O> {
760
+ /**
761
+ * Async factory: receives the key and per-call options.
762
+ * Only invoked when a resource does not already exist.
763
+ */
764
+ onCreate?: (key: K, options: O) => Promise<T>;
765
+ /**
766
+ * Sync factory: receives the key and per-call options.
767
+ * Only invoked when a resource does not already exist.
768
+ */
769
+ onCreateSync?: (key: K, options: O) => T;
770
+ /**
771
+ * Optional disposer for explicit cleanup (release/clear).
772
+ */
773
+ onDispose?: (resource: T) => void | Promise<void>;
774
+ /**
775
+ * Optional callback fired when the resource is GC'd.
776
+ */
777
+ onEvict?: (key: K) => void;
778
+ }
779
+ declare class ResourceRegistry<R extends object, K extends string | number = string, O = void> {
780
+ private readonly entries;
781
+ private readonly resourceToOnce;
782
+ private readonly finalizer;
783
+ private readonly onCreate?;
784
+ private readonly onCreateSync?;
785
+ private readonly onDispose?;
786
+ private readonly onEvict?;
787
+ constructor(options: ResourceRegistryOptions<R, K, O>);
788
+ /**
789
+ * Get or create a resource.
790
+ *
791
+ * IMPORTANT: The `options` are ONLY used if the resource does NOT exist yet.
792
+ * If the resource already exists (or is being created by another concurrent call),
793
+ * the `options` are ignored and the existing instance is returned.
794
+ *
795
+ * This matches the original `registry.ts` behavior.
796
+ */
797
+ get(key: K, options: O, timeout?: number): Promise<R>;
798
+ /**
799
+ * Synchronous version of `get`.
800
+ * Options are only used on the first creation.
801
+ */
802
+ getSync(key: K, options: O): R;
803
+ release(key: K): Promise<boolean>;
804
+ clear(): Promise<void>;
805
+ has(key: K): boolean;
806
+ get size(): number;
807
+ }
808
+
809
+ export { Debouncer, type DebouncerCancelled, type DebouncerError, type DebouncerOk, type DebouncerOptions, type DebouncerResult, Latch, Mutex, type MutexOptions, Once, OnceExecutionConflict, type OnceResult, RWMutex, type RWMutexOptions, ResourceRegistry, type ResourceRegistryOptions, Semaphore, type SemaphoreOptions, Serializer, SerializerExecutionDone, type SerializerOptions, type SerializerResult, SharedResource, type SharedResourceOptions, SyncError, TimeoutError };
package/index.d.ts CHANGED
@@ -131,15 +131,15 @@ type Severity = "error" | "warning" | "info";
131
131
  * Designed to be machine-readable while remaining human-friendly.
132
132
  */
133
133
  interface Issue {
134
- /** Machine-readable identifier (e.g., "REQUIRED_FIELD_MISSING"). */
134
+ /** Machine-readable identifier (e.g., `"REQUIRED_FIELD_MISSING"`). */
135
135
  readonly code: string;
136
136
  /** Human-readable description of the problem. */
137
137
  readonly message: string;
138
- /** Field path in a document or state (e.g., "users.0.email"). */
138
+ /** Field path in a document or state (e.g., `"users.0.email"`). */
139
139
  readonly path?: string;
140
140
  /** Optional array index when the issue relates to a specific element. */
141
141
  readonly index?: number;
142
- /** Seriousness of the issue. Defaults to "error". */
142
+ /** Seriousness of the issue. Defaults to `"error"`. */
143
143
  readonly severity?: Severity;
144
144
  /** Optional detailed explanation, can be multi-line. */
145
145
  readonly description?: string;
@@ -147,81 +147,122 @@ interface Issue {
147
147
  readonly cause?: readonly Issue[];
148
148
  }
149
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)
150
+ * Standardized error code format: `CATEGORY-XXX[-SUFFIX]`
151
+ *
152
+ * @example
153
+ * ```typescript
154
+ * // VAL-001 (Validation: required field missing)
155
+ * // DB-001-NF (Database: not found)
156
+ * // AUTH-001-DENIED (Auth: permission denied)
157
+ * ```
155
158
  */
156
159
  interface ErrorCodeMetadata {
157
- /** The formal error code (e.g., "VAL-001") */
160
+ /** The formal unique error code identifier (e.g., `"VAL-001"`). */
158
161
  readonly code: string;
159
- /** Human-readable name for the error type */
162
+ /** Human-readable uppercase name for the error type (e.g., `"VALIDATION_FAILED"`). */
160
163
  readonly name: string;
161
- /** Detailed description of when this error occurs */
164
+ /** Detailed description of when and why this error occurs. */
162
165
  readonly description: string;
163
- /** Suggested action for handling or resolving the error */
166
+ /** Suggested immediate action for engineers or systems to handle or resolve the error. */
164
167
  readonly action?: string;
165
- /** HTTP status code mapping (if applicable) */
168
+ /** HTTP status code mapping for upstream REST APIs (e.g., `404`, `500`). */
166
169
  readonly httpStatus?: number;
167
- /** Category of the error */
170
+ /** Operational category this error belongs to. */
168
171
  readonly category: ErrorCategory;
169
- /** Whether this error should be logged as warning vs error */
172
+ /** Recommended logging level threshold (`"debug" | "info" | "warn" | "error"`). */
170
173
  readonly logLevel?: "debug" | "info" | "warn" | "error";
171
174
  }
175
+ /**
176
+ * Categories classifying the origin and nature of an error.
177
+ */
172
178
  type ErrorCategory = "validation" | "database" | "auth" | "business" | "system" | "network" | "concurrency" | "custom";
173
179
  /**
174
- * SystemError is the primary error type for all operational and validation errors.
175
- * Supports both predefined and custom error codes with full metadata.
180
+ * Configuration options container used when constructing a new `SystemError`.
181
+ */
182
+ interface SystemErrorParams {
183
+ /** The unique registered error code identifier (e.g., `ErrorCodes.INTERNAL_ERROR.code`). */
184
+ code: string;
185
+ /** Explicit error message overrides. If omitted, defaults to the error code's description. */
186
+ message?: string;
187
+ /** Operational severity tier. Defaults to `"error"`. */
188
+ severity?: Severity;
189
+ /** State path or key where the operational failure occurred (e.g., `"users.0.email"`). */
190
+ path?: string;
191
+ /** The function block, track component, or routing process executing during failure. */
192
+ operation?: string;
193
+ /** Flat array of precise granular input issues or schema violations. */
194
+ issues?: readonly Issue[];
195
+ /** The underlying trigger cause. Accepts native `Error` instances, custom errors, or concurrent `Error[]` arrays. */
196
+ cause?: unknown | unknown[];
197
+ /** Ad-hoc modifications overriding base properties mapped from the code registry. */
198
+ metadata?: Partial<Omit<ErrorCodeMetadata, "code" | "category">>;
199
+ }
200
+ /**
201
+ * Primary domain operational error wrapper.
202
+ * Unfolds historical deep error hierarchies into flat, parallel-aware trace timelines.
176
203
  */
177
204
  declare class SystemError extends Error {
205
+ /** The associated error identifier code (e.g., `"SYS-001"`). */
178
206
  readonly code: string;
207
+ /** Static documentation mapping and registration rules bound to this code type. */
179
208
  readonly codeMetadata: ErrorCodeMetadata;
209
+ /** Severity tier grading the operational consequence of this failure. */
180
210
  readonly severity: Severity;
211
+ /** Target state or document path where processing failed. */
181
212
  readonly path?: string;
213
+ /** Active system segment, workflow node, or function context executing during failure. */
182
214
  readonly operation?: string;
215
+ /** Detailed sub-layer list representing structural data validation failures. */
183
216
  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
- });
217
+ /** Raw backing trigger, array of concurrent branches, or source error instance. */
218
+ readonly cause?: unknown | unknown[];
219
+ /** Exact moment this error was instantiated (ISO string). */
220
+ readonly timestamp: string;
195
221
  /**
196
- * Returns a new SystemError with the specified path.
222
+ * Instantiate a structurally traceable `SystemError`.
223
+ * @param params - Configuration parameters outlining the error's state context.
224
+ */
225
+ constructor(params: SystemErrorParams);
226
+ /**
227
+ * Generates a separate immutable clone assigning a target file, state, or field path.
197
228
  */
198
229
  withPath(path: string): SystemError;
199
230
  /**
200
- * Returns a new SystemError with the specified operation name.
231
+ * Generates a separate immutable clone assigning a specific execution block or track tracking context.
201
232
  */
202
233
  withOperation(operation: string): SystemError;
203
234
  /**
204
- * Returns a new SystemError with the specified issue appended.
235
+ * Appends an operational validation structural issue to a fresh clone of this error.
205
236
  */
206
237
  withIssue(issue: Issue): SystemError;
207
238
  /**
208
- * Returns a new SystemError with multiple issues appended.
239
+ * Appends multiple validation issues onto a fresh clone of this error instance.
209
240
  */
210
241
  withIssues(issues: readonly Issue[]): SystemError;
211
242
  /**
212
- * Returns a new SystemError wrapping the specified cause.
243
+ * Maps a backing raw trigger or concurrent array tracking set to a fresh clone of this error instance.
213
244
  */
214
- withCause(cause: unknown): SystemError;
245
+ withCause(cause: unknown | unknown[]): SystemError;
215
246
  /**
216
- * Returns the HTTP status code for this error (if applicable).
247
+ * Retrieves the recommended HTTP Status code mapped to this error's code metadata registry.
217
248
  */
218
249
  getHttpStatus(): number | undefined;
219
250
  /**
220
- * Formats the error for logging with structured metadata.
251
+ * Unrolls execution hierarchies chronologically, isolating parallel pipelines into clear trace frames.
252
+ * Always returns an array of trace nodes.
253
+ */
254
+ private extractChronologicalTrace;
255
+ /**
256
+ * Transforms the error payload into a flattened transmission format.
257
+ * Strips recursive depth in favor of an array-mapped chronological failure `trace`.
258
+ */
259
+ toJSON(): Record<string, unknown>;
260
+ /**
261
+ * Generates a flat payload matching `toJSON` format requirements for centralized platform ingestion engines.
221
262
  */
222
263
  toLogEntry(): Record<string, unknown>;
223
264
  /**
224
- * Produces a human-readable representation suitable for logging.
265
+ * Terminal terminal dump representation formatting details cleanly into plain strings.
225
266
  */
226
267
  toString(): string;
227
268
  }
@@ -715,4 +756,54 @@ declare class SharedResource<T> {
715
756
  private executeCleanup;
716
757
  }
717
758
 
718
- export { Debouncer, type DebouncerCancelled, type DebouncerError, type DebouncerOk, type DebouncerOptions, type DebouncerResult, Latch, Mutex, type MutexOptions, Once, OnceExecutionConflict, type OnceResult, RWMutex, type RWMutexOptions, Semaphore, type SemaphoreOptions, Serializer, SerializerExecutionDone, type SerializerOptions, type SerializerResult, SharedResource, type SharedResourceOptions, SyncError, TimeoutError };
759
+ interface ResourceRegistryOptions<T, K, O> {
760
+ /**
761
+ * Async factory: receives the key and per-call options.
762
+ * Only invoked when a resource does not already exist.
763
+ */
764
+ onCreate?: (key: K, options: O) => Promise<T>;
765
+ /**
766
+ * Sync factory: receives the key and per-call options.
767
+ * Only invoked when a resource does not already exist.
768
+ */
769
+ onCreateSync?: (key: K, options: O) => T;
770
+ /**
771
+ * Optional disposer for explicit cleanup (release/clear).
772
+ */
773
+ onDispose?: (resource: T) => void | Promise<void>;
774
+ /**
775
+ * Optional callback fired when the resource is GC'd.
776
+ */
777
+ onEvict?: (key: K) => void;
778
+ }
779
+ declare class ResourceRegistry<R extends object, K extends string | number = string, O = void> {
780
+ private readonly entries;
781
+ private readonly resourceToOnce;
782
+ private readonly finalizer;
783
+ private readonly onCreate?;
784
+ private readonly onCreateSync?;
785
+ private readonly onDispose?;
786
+ private readonly onEvict?;
787
+ constructor(options: ResourceRegistryOptions<R, K, O>);
788
+ /**
789
+ * Get or create a resource.
790
+ *
791
+ * IMPORTANT: The `options` are ONLY used if the resource does NOT exist yet.
792
+ * If the resource already exists (or is being created by another concurrent call),
793
+ * the `options` are ignored and the existing instance is returned.
794
+ *
795
+ * This matches the original `registry.ts` behavior.
796
+ */
797
+ get(key: K, options: O, timeout?: number): Promise<R>;
798
+ /**
799
+ * Synchronous version of `get`.
800
+ * Options are only used on the first creation.
801
+ */
802
+ getSync(key: K, options: O): R;
803
+ release(key: K): Promise<boolean>;
804
+ clear(): Promise<void>;
805
+ has(key: K): boolean;
806
+ get size(): number;
807
+ }
808
+
809
+ export { Debouncer, type DebouncerCancelled, type DebouncerError, type DebouncerOk, type DebouncerOptions, type DebouncerResult, Latch, Mutex, type MutexOptions, Once, OnceExecutionConflict, type OnceResult, RWMutex, type RWMutexOptions, ResourceRegistry, type ResourceRegistryOptions, 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={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)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}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;
1
+ "use strict";var e=require("@asaidimu/utils-error"),t=class t extends e.SystemError{constructor(e,i){super({code:"SYNC_ERROR",message:e,cause:i}),this.name="SyncError",Object.setPrototypeOf(this,t.prototype)}},i=class e extends t{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},r=class e extends t{constructor(t){super("[Serializer] The serializer has been marked as done!",t),this.name="SerializerExecutionDone",Object.setPrototypeOf(this,e.prototype)}},s=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,n)=>{s=setTimeout(()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),n(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}},n=class{mutex=new s({yieldMode:"microtask"});promise=null;_value=null;_error;_done=!1;retry;throws;constructor({retry:e,throws:t}={}){this.retry=Boolean(e),this.throws=Boolean(t)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}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,n)=>{s=setTimeout(()=>n(new i(r)),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((r,s)=>{t=setTimeout(()=>s(new i("Latch timed out")),e)})])}isOpen(){return this._open}},exports.Mutex=s,exports.Once=n,exports.OnceExecutionConflict=class e extends t{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 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,n)=>{s=setTimeout(()=>{const e=this.readerWaiters.indexOf(t);-1!==e&&this.readerWaiters.splice(e,1),n(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,n)=>{s=setTimeout(()=>{const e=this.writerWaiters.indexOf(t);-1!==e&&(this.writerWaiters.splice(e,1),this._pendingWriters--),n(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)}},exports.ResourceRegistry=class{entries=new Map;resourceToOnce=new WeakMap;finalizer;onCreate;onCreateSync;onDispose;onEvict;constructor(e){if(this.onCreate=e.onCreate,this.onCreateSync=e.onCreateSync,this.onDispose=e.onDispose,this.onEvict=e.onEvict,!this.onCreate&&!this.onCreateSync)throw new Error("[ResourceRegistry] Must provide either `onCreate` or `onCreateSync`.");this.finalizer=new FinalizationRegistry(({key:e,ref:t})=>{this.entries.get(e)===t&&(this.entries.delete(e),this.onEvict?.(e))})}async get(e,t,i){if(!this.onCreate)throw new Error('[ResourceRegistry] Async get() called, but no "onCreate" factory provided.');let r=this.entries.get(e),s=r?.deref();if(!s){s=new n({throws:!1});const t=new WeakRef(s);this.entries.set(e,t),this.finalizer.register(s,{key:e,ref:t},s)}const o=await s.do(()=>this.onCreate(e,t),i);if(o.error)throw this.entries.get(e)?.deref()===s&&(this.entries.delete(e),this.finalizer.unregister(s)),o.error;const a=o.value;return this.resourceToOnce.set(a,s),a}getSync(e,t){if(!this.onCreateSync)throw new Error('[ResourceRegistry] Sync get() called, but no "onCreateSync" factory provided.');let i=this.entries.get(e),r=i?.deref();if(!r){r=new n({throws:!1});const t=new WeakRef(r);this.entries.set(e,t),this.finalizer.register(r,{key:e,ref:t},r)}const s=r.doSync(()=>this.onCreateSync(e,t));if(s.error)throw this.entries.get(e)?.deref()===r&&(this.entries.delete(e),this.finalizer.unregister(r)),s.error;const o=s.value;return this.resourceToOnce.set(o,r),o}async release(e){const t=this.entries.get(e);if(!t)return!1;try{const e=t.deref();if(e&&(this.finalizer.unregister(e),e.done())){const t=e.get();t&&this.onDispose&&(await this.onDispose(t),this.resourceToOnce.delete(t))}}catch(e){throw e}finally{this.entries.delete(e)}return!0}async clear(){for(const e of this.entries.values()){const t=e.deref();if(t&&(this.finalizer.unregister(t),t.done()&&this.onDispose)){const e=t.get();e&&(await this.onDispose(e),this.resourceToOnce.delete(e))}}this.entries.clear()}has(e){return this.entries.has(e)}get size(){return this.entries.size}},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 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,n)=>{s=setTimeout(()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),n(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}},exports.Serializer=class{mutex;_done=!1;_lastValue=null;_lastError=void 0;_hasRun=!1;constructor(e){this.mutex=new s({capacity:e?.capacity??1e3,yieldMode:e?.yieldMode??"macrotask"})}async do(e,t){if(this._done)return{value:null,error:new r};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let i,s=null;try{if(this._done)throw new r;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=r,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=t,exports.TimeoutError=i;
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={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)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}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};
1
+ import{SystemError as e}from"@asaidimu/utils-error";var t=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}},i=class t extends e{constructor(e,i){super({code:"SYNC_ERROR",message:e,cause:i}),this.name="SyncError",Object.setPrototypeOf(this,t.prototype)}},r=class e extends i{constructor(t){super(`[ArtifactContainer] Operation timed out: ${t}`),this.name="TimeoutError",Object.setPrototypeOf(this,e.prototype)}},s=class e extends i{constructor(t){super("[Once] A method has already been registered!",t),this.name="OnceExecutionConflict",Object.setPrototypeOf(this,e.prototype)}},n=class e extends i{constructor(t){super("[Serializer] The serializer has been marked as done!",t),this.name="SerializerExecutionDone",Object.setPrototypeOf(this,e.prototype)}},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((i,s)=>{t=setTimeout(()=>s(new r("Latch timed out")),e)})])}isOpen(){return this._open}},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,n)=>{s=setTimeout(()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),n(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}},h=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)}resolve(e){if(this._done)throw new Error("Cannot resolve: operation is already completed.");if(this.running())throw new Error("Cannot resolve: operation is currently running.");this._value=e,this._done=!0}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,n)=>{s=setTimeout(()=>n(new r(i)),t)})])}},c=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,n)=>{s=setTimeout(()=>{const e=this.readerWaiters.indexOf(t);-1!==e&&this.readerWaiters.splice(e,1),n(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,n)=>{s=setTimeout(()=>{const e=this.writerWaiters.indexOf(t);-1!==e&&(this.writerWaiters.splice(e,1),this._pendingWriters--),n(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)}},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 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,n)=>{s=setTimeout(()=>{const e=this.waiters.indexOf(t);-1!==e&&this.waiters.splice(e,1),n(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}},u=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 n};try{await this.mutex.lock(t)}catch(e){return{value:null,error:e}}let i,r=null;try{if(this._done)throw new n;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()}},d=class{constructor(e,t,i={}){this.factory=e,this.onCleanup=t,this.options=i}_count=0;init=new h({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()}},_=class{entries=new Map;resourceToOnce=new WeakMap;finalizer;onCreate;onCreateSync;onDispose;onEvict;constructor(e){if(this.onCreate=e.onCreate,this.onCreateSync=e.onCreateSync,this.onDispose=e.onDispose,this.onEvict=e.onEvict,!this.onCreate&&!this.onCreateSync)throw new Error("[ResourceRegistry] Must provide either `onCreate` or `onCreateSync`.");this.finalizer=new FinalizationRegistry(({key:e,ref:t})=>{this.entries.get(e)===t&&(this.entries.delete(e),this.onEvict?.(e))})}async get(e,t,i){if(!this.onCreate)throw new Error('[ResourceRegistry] Async get() called, but no "onCreate" factory provided.');let r=this.entries.get(e),s=r?.deref();if(!s){s=new h({throws:!1});const t=new WeakRef(s);this.entries.set(e,t),this.finalizer.register(s,{key:e,ref:t},s)}const n=await s.do(()=>this.onCreate(e,t),i);if(n.error)throw this.entries.get(e)?.deref()===s&&(this.entries.delete(e),this.finalizer.unregister(s)),n.error;const o=n.value;return this.resourceToOnce.set(o,s),o}getSync(e,t){if(!this.onCreateSync)throw new Error('[ResourceRegistry] Sync get() called, but no "onCreateSync" factory provided.');let i=this.entries.get(e),r=i?.deref();if(!r){r=new h({throws:!1});const t=new WeakRef(r);this.entries.set(e,t),this.finalizer.register(r,{key:e,ref:t},r)}const s=r.doSync(()=>this.onCreateSync(e,t));if(s.error)throw this.entries.get(e)?.deref()===r&&(this.entries.delete(e),this.finalizer.unregister(r)),s.error;const n=s.value;return this.resourceToOnce.set(n,r),n}async release(e){const t=this.entries.get(e);if(!t)return!1;try{const e=t.deref();if(e&&(this.finalizer.unregister(e),e.done())){const t=e.get();t&&this.onDispose&&(await this.onDispose(t),this.resourceToOnce.delete(t))}}catch(e){throw e}finally{this.entries.delete(e)}return!0}async clear(){for(const e of this.entries.values()){const t=e.deref();if(t&&(this.finalizer.unregister(t),t.done()&&this.onDispose)){const e=t.get();e&&(await this.onDispose(e),this.resourceToOnce.delete(e))}}this.entries.clear()}has(e){return this.entries.has(e)}get size(){return this.entries.size}};export{t as Debouncer,o as Latch,a as Mutex,h as Once,s as OnceExecutionConflict,c as RWMutex,_ as ResourceRegistry,l as Semaphore,u as Serializer,n as SerializerExecutionDone,d as SharedResource,i as SyncError,r as TimeoutError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@asaidimu/utils-sync",
3
- "version": "2.2.3",
3
+ "version": "2.3.0",
4
4
  "description": "A collection of sync utilities.",
5
5
  "main": "index.js",
6
6
  "module": "index.mjs",