@xbg.solutions/bpsk-utils-mutex 1.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,25 @@
1
+ /**
2
+ * src/lib/constants/mutex.constants.ts
3
+ * Constants for mutex utility
4
+ *
5
+ * @deprecated This file has been consolidated into central configuration.
6
+ * New code should import from '@/lib/config/app.config.ts' instead.
7
+ *
8
+ * Legacy mutex constants - use central config for new development.
9
+ */
10
+ /**
11
+ * @deprecated Use APP_CONFIG.security.mutex instead
12
+ * Default maximum wait time for acquiring a lock (ms)
13
+ */
14
+ export declare const DEFAULT_MUTEX_TIMEOUT: number;
15
+ /**
16
+ * @deprecated Use APP_CONFIG.security.mutex instead
17
+ * Default maximum lock retention time (ms)
18
+ */
19
+ export declare const DEFAULT_MUTEX_LOCK_EXPIRY: number;
20
+ /**
21
+ * @deprecated Use APP_CONFIG.security.mutex instead
22
+ * Polling interval when waiting for a lock (ms)
23
+ */
24
+ export declare const MUTEX_POLLING_INTERVAL: number;
25
+ //# sourceMappingURL=mutex.constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.constants.d.ts","sourceRoot":"","sources":["../../src/constants/mutex.constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH;;;GAGG;AACH,eAAO,MAAM,qBAAqB,QAA2C,CAAC;AAE9E;;;GAGG;AACH,eAAO,MAAM,yBAAyB,QAA8C,CAAC;AAErF;;;GAGG;AACH,eAAO,MAAM,sBAAsB,QAA4C,CAAC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * src/lib/constants/mutex.constants.ts
3
+ * Constants for mutex utility
4
+ *
5
+ * @deprecated This file has been consolidated into central configuration.
6
+ * New code should import from '@/lib/config/app.config.ts' instead.
7
+ *
8
+ * Legacy mutex constants - use central config for new development.
9
+ */
10
+ import { APP_CONFIG } from '@xbg.solutions/bpsk-core';
11
+ /**
12
+ * @deprecated Use APP_CONFIG.security.mutex instead
13
+ * Default maximum wait time for acquiring a lock (ms)
14
+ */
15
+ export const DEFAULT_MUTEX_TIMEOUT = APP_CONFIG.security.mutex.defaultTimeout;
16
+ /**
17
+ * @deprecated Use APP_CONFIG.security.mutex instead
18
+ * Default maximum lock retention time (ms)
19
+ */
20
+ export const DEFAULT_MUTEX_LOCK_EXPIRY = APP_CONFIG.security.mutex.defaultLockExpiry;
21
+ /**
22
+ * @deprecated Use APP_CONFIG.security.mutex instead
23
+ * Polling interval when waiting for a lock (ms)
24
+ */
25
+ export const MUTEX_POLLING_INTERVAL = APP_CONFIG.security.mutex.pollingInterval;
26
+ //# sourceMappingURL=mutex.constants.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.constants.js","sourceRoot":"","sources":["../../src/constants/mutex.constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC;AAE9E;;;GAGG;AACH,MAAM,CAAC,MAAM,yBAAyB,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,iBAAiB,CAAC;AAErF;;;GAGG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,CAAC,eAAe,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,4 @@
1
+ export * from './constants/mutex.constants';
2
+ export type * from './types/mutex.types';
3
+ export * from './utils/mutex';
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,cAAc,6BAA6B,CAAC;AAG5C,mBAAmB,qBAAqB,CAAC;AAGzC,cAAc,eAAe,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,6 @@
1
+ // Mutex package barrel exports
2
+ // Constants
3
+ export * from './constants/mutex.constants';
4
+ // Utils
5
+ export * from './utils/mutex';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,+BAA+B;AAE/B,YAAY;AACZ,cAAc,6BAA6B,CAAC;AAK5C,QAAQ;AACR,cAAc,eAAe,CAAC"}
@@ -0,0 +1,42 @@
1
+ /**
2
+ * src/lib/types/mutex.types.ts
3
+ * Type definitions for mutex utility
4
+ */
5
+ /**
6
+ * Options for mutex operations
7
+ */
8
+ export type MutexOptions = {
9
+ /** Maximum time to wait for lock acquisition (ms) */
10
+ timeout?: number;
11
+ /** Maximum time a lock can be held (ms) */
12
+ lockExpiry?: number;
13
+ /** Whether to track detailed acquisition info (stack traces etc.) */
14
+ debug?: boolean;
15
+ /** Internal testing flag - not for general use */
16
+ _testMode?: boolean;
17
+ };
18
+ /**
19
+ * Information about a held mutex lock
20
+ */
21
+ export type MutexLockInfo = {
22
+ /** Name of the lock */
23
+ name: string;
24
+ /** Timestamp when the lock was acquired */
25
+ acquiredAt: number;
26
+ /** Timestamp when the lock will expire */
27
+ expiresAt: number;
28
+ /** Stack trace from when the lock was acquired (only in debug mode) */
29
+ stack?: string;
30
+ };
31
+ /**
32
+ * Result type for safe mutex operations
33
+ */
34
+ export type MutexResult<T> = {
35
+ /** Whether the operation succeeded */
36
+ success: boolean;
37
+ /** Result of the operation if successful */
38
+ result?: T;
39
+ /** Error if operation failed */
40
+ error?: Error;
41
+ };
42
+ //# sourceMappingURL=mutex.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.types.d.ts","sourceRoot":"","sources":["../../src/types/mutex.types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG;IACzB,qDAAqD;IACrD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,2CAA2C;IAC3C,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB,qEAAqE;IACrE,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,uBAAuB;IACvB,IAAI,EAAE,MAAM,CAAC;IAEb,2CAA2C;IAC3C,UAAU,EAAE,MAAM,CAAC;IAEnB,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAElB,uEAAuE;IACvE,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IAAI;IAC3B,sCAAsC;IACtC,OAAO,EAAE,OAAO,CAAC;IAEjB,4CAA4C;IAC5C,MAAM,CAAC,EAAE,CAAC,CAAC;IAEX,gCAAgC;IAChC,KAAK,CAAC,EAAE,KAAK,CAAC;CACf,CAAC"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * src/lib/types/mutex.types.ts
3
+ * Type definitions for mutex utility
4
+ */
5
+ export {};
6
+ //# sourceMappingURL=mutex.types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.types.js","sourceRoot":"","sources":["../../src/types/mutex.types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
@@ -0,0 +1,105 @@
1
+ /**
2
+ * src/lib/utils/mutex.ts
3
+ * Mutex utility for managing critical sections
4
+ */
5
+ import { AppError } from '@xbg.solutions/bpsk-core';
6
+ import type { MutexOptions, MutexLockInfo, MutexResult } from '../types/mutex.types';
7
+ /**
8
+ * Error class for mutex-specific errors
9
+ */
10
+ export declare class MutexError extends AppError {
11
+ /** Lock name that caused the error */
12
+ lockName?: string;
13
+ /** Timeout duration if applicable */
14
+ timeout?: number;
15
+ constructor(message: string, options?: {
16
+ lockName?: string;
17
+ timeout?: number;
18
+ [key: string]: any;
19
+ });
20
+ }
21
+ /**
22
+ * Mutex implementation for managing critical sections
23
+ */
24
+ declare class Mutex {
25
+ /** Map of active locks by name */
26
+ private locks;
27
+ /**
28
+ * Acquire a named mutex lock
29
+ *
30
+ * @param name Unique name of the lock
31
+ * @param options Lock acquisition options
32
+ * @returns Promise that resolves to a function that releases the lock
33
+ * @throws MutexError if lock cannot be acquired within timeout
34
+ */
35
+ acquire(name: string, options?: MutexOptions): Promise<() => boolean>;
36
+ /**
37
+ * Release a mutex lock
38
+ *
39
+ * @param name Name of the lock to release
40
+ * @returns true if lock was released, false if it wasn't held
41
+ */
42
+ release(name: string): boolean;
43
+ /**
44
+ * Force release a lock regardless of who holds it
45
+ *
46
+ * @param name Name of the lock to force release
47
+ * @returns true if a lock was force-released, false if it wasn't held
48
+ */
49
+ forceRelease(name: string): boolean;
50
+ /**
51
+ * Check if a lock is currently held
52
+ *
53
+ * @param name Name of the lock to check
54
+ * @returns true if the lock is held, false otherwise
55
+ */
56
+ isLocked(name: string): boolean;
57
+ /**
58
+ * Get information about a held lock
59
+ *
60
+ * @param name Name of the lock
61
+ * @returns Lock information or null if not held
62
+ */
63
+ getLockInfo(name: string): MutexLockInfo | null;
64
+ /**
65
+ * Get all currently held locks
66
+ *
67
+ * @returns Array of lock information
68
+ */
69
+ getAllLocks(): MutexLockInfo[];
70
+ /**
71
+ * Safe version of acquire that never throws
72
+ *
73
+ * @param name Lock name
74
+ * @param options Lock options
75
+ * @returns Promise that resolves to a release function or null if acquisition failed
76
+ */
77
+ safeAcquire(name: string, options?: MutexOptions): Promise<(() => boolean) | null>;
78
+ /**
79
+ * Execute a function with a mutex lock
80
+ *
81
+ * @param name Lock name
82
+ * @param fn Function to execute with the lock
83
+ * @param options Lock options
84
+ * @returns Promise resolving to the function result
85
+ * @throws Original error from the function or MutexError if lock cannot be acquired
86
+ */
87
+ withLock<T>(name: string, fn: () => Promise<T>, options?: MutexOptions): Promise<T>;
88
+ /**
89
+ * Safely execute a function with a mutex lock, never throws mutex errors
90
+ *
91
+ * @param name Lock name
92
+ * @param fn Function to execute with the lock
93
+ * @param options Lock options
94
+ * @returns Promise resolving to an object with success flag and result or error
95
+ */
96
+ safeWithLock<T>(name: string, fn: () => Promise<T>, options?: MutexOptions): Promise<MutexResult<T>>;
97
+ /**
98
+ * Clean up any expired locks
99
+ * @private
100
+ */
101
+ private cleanupExpiredLocks;
102
+ }
103
+ export declare const mutexService: Mutex;
104
+ export {};
105
+ //# sourceMappingURL=mutex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.d.ts","sourceRoot":"","sources":["../../src/utils/mutex.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAiB,QAAQ,EAAkB,MAAM,0BAA0B,CAAC;AACnF,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAUrF;;GAEG;AACH,qBAAa,UAAW,SAAQ,QAAQ;IACtC,sCAAsC;IAC/B,QAAQ,CAAC,EAAE,MAAM,CAAC;IACzB,qCAAqC;IAC9B,OAAO,CAAC,EAAE,MAAM,CAAC;gBAEZ,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;KACf;CAWP;AAED;;GAEG;AACH,cAAM,KAAK;IACT,kCAAkC;IAClC,OAAO,CAAC,KAAK,CAAyC;IAEtD;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC;IAmE/E;;;;;OAKG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAgB9B;;;;;OAKG;IACH,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAgBnC;;;;;OAKG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAK/B;;;;;OAKG;IACH,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI;IAK/C;;;;OAIG;IACH,WAAW,IAAI,aAAa,EAAE;IAK9B;;;;;;OAMG;IACG,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,CAAC,MAAM,OAAO,CAAC,GAAG,IAAI,CAAC;IAc5F;;;;;;;;OAQG;IACG,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,CAAC,CAAC;IAU7F;;;;;;;OAOG;IACG,YAAY,CAAC,CAAC,EAClB,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,GAAE,YAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC;IA+B1B;;;OAGG;IACH,OAAO,CAAC,mBAAmB;CAqB5B;AAGD,eAAO,MAAM,YAAY,OAAc,CAAC"}
@@ -0,0 +1,258 @@
1
+ /**
2
+ * src/lib/utils/mutex.ts
3
+ * Mutex utility for managing critical sections
4
+ */
5
+ import { loggerService, AppError, normalizeError } from '@xbg.solutions/bpsk-core';
6
+ import { DEFAULT_MUTEX_TIMEOUT, DEFAULT_MUTEX_LOCK_EXPIRY, MUTEX_POLLING_INTERVAL } from '../constants/mutex.constants';
7
+ // Create a context-aware logger
8
+ const mutexLogger = loggerService.withContext('MutexUtility');
9
+ /**
10
+ * Error class for mutex-specific errors
11
+ */
12
+ export class MutexError extends AppError {
13
+ constructor(message, options = {}) {
14
+ super(message, {
15
+ category: 'mutex',
16
+ statusCode: 423, // Locked (WebDAV status code)
17
+ userMessage: options.userMessage || 'Resource is currently locked. Please try again later.',
18
+ ...options
19
+ });
20
+ this.lockName = options.lockName;
21
+ this.timeout = options.timeout;
22
+ }
23
+ }
24
+ /**
25
+ * Mutex implementation for managing critical sections
26
+ */
27
+ class Mutex {
28
+ constructor() {
29
+ /** Map of active locks by name */
30
+ this.locks = new Map();
31
+ }
32
+ /**
33
+ * Acquire a named mutex lock
34
+ *
35
+ * @param name Unique name of the lock
36
+ * @param options Lock acquisition options
37
+ * @returns Promise that resolves to a function that releases the lock
38
+ * @throws MutexError if lock cannot be acquired within timeout
39
+ */
40
+ async acquire(name, options = {}) {
41
+ const timeout = options.timeout || DEFAULT_MUTEX_TIMEOUT;
42
+ const lockExpiry = options.lockExpiry || DEFAULT_MUTEX_LOCK_EXPIRY;
43
+ const debug = options.debug ?? import.meta.env.DEV;
44
+ const testMode = options._testMode || false; // Private option for testing
45
+ const startTime = Date.now();
46
+ // Clean up any expired locks first
47
+ this.cleanupExpiredLocks();
48
+ // Try to acquire the lock
49
+ while (this.locks.has(name)) {
50
+ // Check if we've exceeded timeout
51
+ if (Date.now() - startTime > timeout) {
52
+ const existingLock = this.locks.get(name);
53
+ mutexLogger.warn(`Mutex acquisition timeout for "${name}"`, {
54
+ timeout,
55
+ lockInfo: existingLock,
56
+ acquiredAgo: existingLock ? Date.now() - existingLock.acquiredAt : null,
57
+ timeRemaining: existingLock ? existingLock.expiresAt - Date.now() : null
58
+ });
59
+ throw new MutexError(`Failed to acquire mutex "${name}" after ${timeout}ms`, {
60
+ lockName: name,
61
+ timeout,
62
+ context: {
63
+ acquiredAt: existingLock?.acquiredAt,
64
+ expiresAt: existingLock?.expiresAt,
65
+ heldFor: existingLock ? Date.now() - existingLock.acquiredAt : null
66
+ }
67
+ });
68
+ }
69
+ // In test mode, we fail fast instead of waiting
70
+ if (testMode) {
71
+ throw new MutexError(`Failed to acquire mutex "${name}" (test mode)`, {
72
+ lockName: name,
73
+ timeout
74
+ });
75
+ }
76
+ // Wait a bit before trying again
77
+ await new Promise(resolve => setTimeout(resolve, MUTEX_POLLING_INTERVAL));
78
+ }
79
+ // Acquire the lock
80
+ const now = Date.now();
81
+ const lockInfo = {
82
+ name,
83
+ acquiredAt: now,
84
+ expiresAt: now + lockExpiry,
85
+ stack: debug ? new Error().stack : undefined
86
+ };
87
+ this.locks.set(name, lockInfo);
88
+ mutexLogger.info(`Mutex "${name}" acquired`, {
89
+ lockInfo,
90
+ expiresIn: lockExpiry
91
+ });
92
+ // Return release function
93
+ return () => this.release(name);
94
+ }
95
+ /**
96
+ * Release a mutex lock
97
+ *
98
+ * @param name Name of the lock to release
99
+ * @returns true if lock was released, false if it wasn't held
100
+ */
101
+ release(name) {
102
+ if (!this.locks.has(name)) {
103
+ mutexLogger.warn(`Attempted to release non-existent mutex "${name}"`);
104
+ return false;
105
+ }
106
+ const lockInfo = this.locks.get(name);
107
+ this.locks.delete(name);
108
+ mutexLogger.info(`Mutex "${name}" released`, {
109
+ heldFor: Date.now() - (lockInfo?.acquiredAt || 0)
110
+ });
111
+ return true;
112
+ }
113
+ /**
114
+ * Force release a lock regardless of who holds it
115
+ *
116
+ * @param name Name of the lock to force release
117
+ * @returns true if a lock was force-released, false if it wasn't held
118
+ */
119
+ forceRelease(name) {
120
+ if (!this.locks.has(name)) {
121
+ return false;
122
+ }
123
+ const lockInfo = this.locks.get(name);
124
+ this.locks.delete(name);
125
+ mutexLogger.warn(`Mutex "${name}" force released`, {
126
+ lockInfo,
127
+ heldFor: Date.now() - (lockInfo?.acquiredAt || 0)
128
+ });
129
+ return true;
130
+ }
131
+ /**
132
+ * Check if a lock is currently held
133
+ *
134
+ * @param name Name of the lock to check
135
+ * @returns true if the lock is held, false otherwise
136
+ */
137
+ isLocked(name) {
138
+ this.cleanupExpiredLocks();
139
+ return this.locks.has(name);
140
+ }
141
+ /**
142
+ * Get information about a held lock
143
+ *
144
+ * @param name Name of the lock
145
+ * @returns Lock information or null if not held
146
+ */
147
+ getLockInfo(name) {
148
+ this.cleanupExpiredLocks();
149
+ return this.locks.get(name) || null;
150
+ }
151
+ /**
152
+ * Get all currently held locks
153
+ *
154
+ * @returns Array of lock information
155
+ */
156
+ getAllLocks() {
157
+ this.cleanupExpiredLocks();
158
+ return Array.from(this.locks.values());
159
+ }
160
+ /**
161
+ * Safe version of acquire that never throws
162
+ *
163
+ * @param name Lock name
164
+ * @param options Lock options
165
+ * @returns Promise that resolves to a release function or null if acquisition failed
166
+ */
167
+ async safeAcquire(name, options = {}) {
168
+ try {
169
+ return await this.acquire(name, options);
170
+ }
171
+ catch (error) {
172
+ const normalizedError = normalizeError(error);
173
+ mutexLogger.error(`Failed to safely acquire mutex "${name}"`, normalizedError, {
174
+ options
175
+ });
176
+ return null;
177
+ }
178
+ }
179
+ /**
180
+ * Execute a function with a mutex lock
181
+ *
182
+ * @param name Lock name
183
+ * @param fn Function to execute with the lock
184
+ * @param options Lock options
185
+ * @returns Promise resolving to the function result
186
+ * @throws Original error from the function or MutexError if lock cannot be acquired
187
+ */
188
+ async withLock(name, fn, options = {}) {
189
+ const release = await this.acquire(name, options);
190
+ try {
191
+ return await fn();
192
+ }
193
+ finally {
194
+ release();
195
+ }
196
+ }
197
+ /**
198
+ * Safely execute a function with a mutex lock, never throws mutex errors
199
+ *
200
+ * @param name Lock name
201
+ * @param fn Function to execute with the lock
202
+ * @param options Lock options
203
+ * @returns Promise resolving to an object with success flag and result or error
204
+ */
205
+ async safeWithLock(name, fn, options = {}) {
206
+ try {
207
+ const release = await this.acquire(name, options);
208
+ try {
209
+ const result = await fn();
210
+ return { success: true, result };
211
+ }
212
+ catch (error) {
213
+ const normalizedError = normalizeError(error);
214
+ mutexLogger.error(`Operation failed while holding mutex "${name}"`, normalizedError);
215
+ return {
216
+ success: false,
217
+ error: normalizedError
218
+ };
219
+ }
220
+ finally {
221
+ release();
222
+ }
223
+ }
224
+ catch (error) {
225
+ const normalizedError = normalizeError(error);
226
+ mutexLogger.error(`Failed to acquire mutex "${name}" for safe operation`, normalizedError);
227
+ return {
228
+ success: false,
229
+ error: normalizedError
230
+ };
231
+ }
232
+ }
233
+ /**
234
+ * Clean up any expired locks
235
+ * @private
236
+ */
237
+ cleanupExpiredLocks() {
238
+ const now = Date.now();
239
+ let expiredCount = 0;
240
+ for (const [name, info] of this.locks.entries()) {
241
+ if (info.expiresAt <= now) {
242
+ this.locks.delete(name);
243
+ expiredCount++;
244
+ mutexLogger.warn(`Mutex "${name}" expired and auto-released`, {
245
+ lockInfo: info,
246
+ heldFor: now - info.acquiredAt,
247
+ expiredAgo: now - info.expiresAt
248
+ });
249
+ }
250
+ }
251
+ if (expiredCount > 0) {
252
+ mutexLogger.info(`Cleaned up ${expiredCount} expired lock(s)`);
253
+ }
254
+ }
255
+ }
256
+ // Export a singleton instance
257
+ export const mutexService = new Mutex();
258
+ //# sourceMappingURL=mutex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mutex.js","sourceRoot":"","sources":["../../src/utils/mutex.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAEnF,OAAO,EACL,qBAAqB,EACrB,yBAAyB,EACzB,sBAAsB,EACvB,MAAM,8BAA8B,CAAC;AAEtC,gCAAgC;AAChC,MAAM,WAAW,GAAG,aAAa,CAAC,WAAW,CAAC,cAAc,CAAC,CAAC;AAE9D;;GAEG;AACH,MAAM,OAAO,UAAW,SAAQ,QAAQ;IAMtC,YAAY,OAAe,EAAE,UAIzB,EAAE;QACJ,KAAK,CAAC,OAAO,EAAE;YACb,QAAQ,EAAE,OAAO;YACjB,UAAU,EAAE,GAAG,EAAE,8BAA8B;YAC/C,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,uDAAuD;YAC3F,GAAG,OAAO;SACX,CAAC,CAAC;QAEH,IAAI,CAAC,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;QACjC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IACjC,CAAC;CACF;AAED;;GAEG;AACH,MAAM,KAAK;IAAX;QACE,kCAAkC;QAC1B,UAAK,GAA+B,IAAI,GAAG,EAAE,CAAC;IAqQxD,CAAC;IAnQC;;;;;;;OAOG;IACH,KAAK,CAAC,OAAO,CAAC,IAAY,EAAE,UAAwB,EAAE;QACpD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,qBAAqB,CAAC;QACzD,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,yBAAyB,CAAC;QACnE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;QACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,IAAI,KAAK,CAAC,CAAC,6BAA6B;QAE1E,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,mCAAmC;QACnC,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAE3B,0BAA0B;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC5B,kCAAkC;YAClC,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC;gBACrC,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAE1C,WAAW,CAAC,IAAI,CAAC,kCAAkC,IAAI,GAAG,EAAE;oBAC1D,OAAO;oBACP,QAAQ,EAAE,YAAY;oBACtB,WAAW,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;oBACvE,aAAa,EAAE,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,IAAI;iBACzE,CAAC,CAAC;gBAEH,MAAM,IAAI,UAAU,CAAC,4BAA4B,IAAI,WAAW,OAAO,IAAI,EAAE;oBAC3E,QAAQ,EAAE,IAAI;oBACd,OAAO;oBACP,OAAO,EAAE;wBACP,UAAU,EAAE,YAAY,EAAE,UAAU;wBACpC,SAAS,EAAE,YAAY,EAAE,SAAS;wBAClC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI;qBACpE;iBACF,CAAC,CAAC;YACL,CAAC;YAED,gDAAgD;YAChD,IAAI,QAAQ,EAAE,CAAC;gBACb,MAAM,IAAI,UAAU,CAAC,4BAA4B,IAAI,eAAe,EAAE;oBACpE,QAAQ,EAAE,IAAI;oBACd,OAAO;iBACR,CAAC,CAAC;YACL,CAAC;YAED,iCAAiC;YACjC,MAAM,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC;QAC5E,CAAC;QAED,mBAAmB;QACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,MAAM,QAAQ,GAAkB;YAC9B,IAAI;YACJ,UAAU,EAAE,GAAG;YACf,SAAS,EAAE,GAAG,GAAG,UAAU;YAC3B,KAAK,EAAE,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;SAC7C,CAAC;QAEF,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;QAE/B,WAAW,CAAC,IAAI,CAAC,UAAU,IAAI,YAAY,EAAE;YAC3C,QAAQ;YACR,SAAS,EAAE,UAAU;SACtB,CAAC,CAAC;QAEH,0BAA0B;QAC1B,OAAO,GAAG,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAED;;;;;OAKG;IACH,OAAO,CAAC,IAAY;QAClB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,WAAW,CAAC,IAAI,CAAC,4CAA4C,IAAI,GAAG,CAAC,CAAC;YACtE,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAExB,WAAW,CAAC,IAAI,CAAC,UAAU,IAAI,YAAY,EAAE;YAC3C,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,UAAU,IAAI,CAAC,CAAC;SAClD,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,YAAY,CAAC,IAAY;QACvB,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC;QACf,CAAC;QAED,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACtC,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QAExB,WAAW,CAAC,IAAI,CAAC,UAAU,IAAI,kBAAkB,EAAE;YACjD,QAAQ;YACR,OAAO,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,CAAC,QAAQ,EAAE,UAAU,IAAI,CAAC,CAAC;SAClD,CAAC,CAAC;QAEH,OAAO,IAAI,CAAC;IACd,CAAC;IAED;;;;;OAKG;IACH,QAAQ,CAAC,IAAY;QACnB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED;;;;;OAKG;IACH,WAAW,CAAC,IAAY;QACtB,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,IAAI,CAAC;IACtC,CAAC;IAED;;;;OAIG;IACH,WAAW;QACT,IAAI,CAAC,mBAAmB,EAAE,CAAC;QAC3B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,CAAC;IAED;;;;;;OAMG;IACH,KAAK,CAAC,WAAW,CAAC,IAAY,EAAE,UAAwB,EAAE;QACxD,IAAI,CAAC;YACH,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YAE9C,WAAW,CAAC,KAAK,CAAC,mCAAmC,IAAI,GAAG,EAAE,eAAe,EAAE;gBAC7E,OAAO;aACR,CAAC,CAAC;YAEH,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,QAAQ,CAAI,IAAY,EAAE,EAAoB,EAAE,UAAwB,EAAE;QAC9E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAElD,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAC;QACpB,CAAC;gBAAS,CAAC;YACT,OAAO,EAAE,CAAC;QACZ,CAAC;IACH,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,YAAY,CAChB,IAAY,EACZ,EAAoB,EACpB,UAAwB,EAAE;QAE1B,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YAElD,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;gBAC1B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YACnC,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;gBAE9C,WAAW,CAAC,KAAK,CAAC,yCAAyC,IAAI,GAAG,EAAE,eAAe,CAAC,CAAC;gBAErF,OAAO;oBACL,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,eAAe;iBACvB,CAAC;YACJ,CAAC;oBAAS,CAAC;gBACT,OAAO,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,eAAe,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;YAE9C,WAAW,CAAC,KAAK,CAAC,4BAA4B,IAAI,sBAAsB,EAAE,eAAe,CAAC,CAAC;YAE3F,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,eAAe;aACvB,CAAC;QACJ,CAAC;IACH,CAAC;IAED;;;OAGG;IACK,mBAAmB;QACzB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QACvB,IAAI,YAAY,GAAG,CAAC,CAAC;QAErB,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAChD,IAAI,IAAI,CAAC,SAAS,IAAI,GAAG,EAAE,CAAC;gBAC1B,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACxB,YAAY,EAAE,CAAC;gBAEf,WAAW,CAAC,IAAI,CAAC,UAAU,IAAI,6BAA6B,EAAE;oBAC5D,QAAQ,EAAE,IAAI;oBACd,OAAO,EAAE,GAAG,GAAG,IAAI,CAAC,UAAU;oBAC9B,UAAU,EAAE,GAAG,GAAG,IAAI,CAAC,SAAS;iBACjC,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAED,IAAI,YAAY,GAAG,CAAC,EAAE,CAAC;YACrB,WAAW,CAAC,IAAI,CAAC,cAAc,YAAY,kBAAkB,CAAC,CAAC;QACjE,CAAC;IACH,CAAC;CACF;AAED,8BAA8B;AAC9B,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,KAAK,EAAE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@xbg.solutions/bpsk-utils-mutex",
3
+ "version": "1.2.3",
4
+ "description": "XBG Mutex - Mutual exclusion for concurrent operations",
5
+ "main": "lib/index.js",
6
+ "types": "lib/index.d.ts",
7
+ "type": "module",
8
+ "files": ["lib"],
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "build:watch": "tsc --watch",
12
+ "clean": "rm -rf lib",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "dependencies": {
19
+ "@xbg.solutions/bpsk-core": "^1.0.0"
20
+ }
21
+ }