mini-semaphore 1.3.17 → 1.4.4

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/README.md CHANGED
@@ -163,6 +163,69 @@ async function resolve(id: string | number): Promise<TType> {
163
163
  }
164
164
 
165
165
  ```
166
+
167
+ ---
168
+ > ## Abortable Semaphore
169
+
170
+ Starting from version **1.4.3**, `mini-semaphore` introduces support for abortable semaphores.
171
+ This feature allows you to cancel pending tasks and notify listeners when an abort event occurs.
172
+ This is particularly useful in scenarios where you need to terminate ongoing operations gracefully.
173
+
174
+ ### Key Features
175
+
176
+ - **Abort Method**: Immediately cancels all pending tasks and restores the semaphore's capacity.
177
+ - **Event Emission**: Emits an `abort` event to notify listeners of the cancellation.
178
+ - **Listener Management**: Provides `onAbort` and `offAbort` methods to register and remove event listeners.
179
+
180
+ ### Example Usage
181
+
182
+ ```typescript
183
+ import { createWithAbort } from "mini-semaphore";
184
+
185
+ // Create an abortable semaphore with a capacity of 3
186
+ const semaphore = createWithAbort(3);
187
+
188
+ // Register an abort event listener
189
+ semaphore.onAbort((reason) => {
190
+ console.log("Abort event received:", reason.message);
191
+ });
192
+
193
+ // Simulate tasks
194
+ const task = async (id: number) => {
195
+ try {
196
+ await semaphore.acquire();
197
+ console.log(`Task ${id} started`);
198
+ await new Promise((resolve) => setTimeout(resolve, 1000)); // Simulate work
199
+ console.log(`Task ${id} completed`);
200
+ semaphore.release();
201
+ } catch (e) {
202
+ console.log(`Task ${id} aborted:`, e.message);
203
+ }
204
+ };
205
+
206
+ // Start tasks
207
+ const tasks = [1, 2, 3, 4, 5].map((id) => task(id));
208
+
209
+ // Abort all pending tasks after 2 seconds
210
+ setTimeout(() => {
211
+ semaphore.abort();
212
+ }, 2000);
213
+
214
+ // Wait for all tasks to settle
215
+ Promise.allSettled(tasks).then(() => {
216
+ console.log("All tasks settled");
217
+ });
218
+ ```
219
+
220
+ ### Explanation
221
+
222
+ 1. **Creating an Abortable Semaphore**: Use `createWithAbort` to create a semaphore with abort capabilities.
223
+ 2. **Registering Listeners**: Use `onAbort` to listen for abort events and handle cleanup or logging.
224
+ 3. **Aborting Tasks**: Call `abort` to cancel all pending tasks. Tasks that are already running will not be interrupted but will complete normally.
225
+ 4. **Graceful Cleanup**: Use `offAbort` to remove listeners when they are no longer needed.
226
+
227
+ This feature enhances the flexibility of `mini-semaphore`, making it suitable for more complex concurrency control scenarios.
228
+
166
229
  > ## Authors
167
230
 
168
231
  + **jeffy-g** - [jeffy-g](https://github.com/jeffy-g)
package/cjs/core.js CHANGED
@@ -1,9 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.release = exports.acquire = void 0;
3
+ exports.releaseWithAbort = exports.acquireWithAbort = exports.release = exports.acquire = void 0;
4
4
  /**
5
5
  * @typedef {import("./index").TVoidFunction} TVoidFunction
6
6
  * @typedef {import("./index").Deque<TVoidFunction>} Deque
7
+ * @typedef {import("./index").TFlowableLockWithAbort} TFlowableLockWithAbort
8
+ * @typedef {import("./index").Deque<TResolver>} DequeWithAbort
7
9
  * @typedef {import("./index").ISimplifiedLock} ISimplifiedLock
8
10
  * @typedef {import("./index").TFlowableLock} TFlowableLock
9
11
  * @typedef {import("./index").IFlowableLock} IFlowableLock
@@ -62,4 +64,41 @@ const release = (dis) => {
62
64
  dis.capacity = dis.limit;
63
65
  }
64
66
  };
65
- exports.release = release;
67
+ exports.release = release;
68
+ /**
69
+ * @param {TFlowableLockWithAbort} dis
70
+ * @returns {Promise<void>}
71
+ */
72
+ const acquireWithAbort = (dis) => {
73
+ return new Promise((resolve, reject) => {
74
+ if (dis.capacity > 0) {
75
+ dis.capacity--, resolve();
76
+ }
77
+ else {
78
+ dis.q.push({
79
+ resolve, reject
80
+ });
81
+ }
82
+ });
83
+ };
84
+ exports.acquireWithAbort = acquireWithAbort;
85
+ /**
86
+ * @param {TFlowableLockWithAbort} dis
87
+ * @returns {void}
88
+ */
89
+ const releaseWithAbort = (dis) => {
90
+ /** @type {DequeWithAbort} */
91
+ let dq;
92
+ if ((dq = dis.q).length) {
93
+ const resolver = dq.shift();
94
+ resolver && resolver.resolve() || (
95
+ /* istanbul ignore next */
96
+ THROW());
97
+ }
98
+ else {
99
+ if (dis.capacity < dis.limit) {
100
+ dis.capacity++;
101
+ }
102
+ }
103
+ };
104
+ exports.releaseWithAbort = releaseWithAbort;
package/cjs/deque.js CHANGED
@@ -57,24 +57,28 @@ class Deque {
57
57
  constructor(ic) {
58
58
  /**
59
59
  * capacity
60
+ * @internal
60
61
  */
61
62
  this._c = gc(ic || 16);
62
63
  /**
63
64
  * current length (size
65
+ * @internal
64
66
  */
65
67
  this._l = 0;
66
68
  /**
67
69
  * current front position
70
+ * @internal
68
71
  */
69
72
  this._f = 0;
70
- /**
71
- *
72
- */
73
- this.length = 0;
74
73
  /**
75
74
  * @type {T[]}
75
+ * @internal
76
76
  */
77
77
  this._a = [];
78
+ /**
79
+ * current length (size
80
+ */
81
+ this.length = 0;
78
82
  }
79
83
  /**
80
84
  * @param {T} s subject
@@ -109,6 +113,7 @@ exports.Deque = Deque;
109
113
  * @template {any} T
110
114
  * @param {Deque<T>} dis
111
115
  * @param {number} n expected capacity
116
+ * @todo test code
112
117
  */
113
118
  const rt = (dis, n) => {
114
119
  const oc = dis._c;
package/cjs/index.d.ts CHANGED
@@ -7,23 +7,24 @@
7
7
  export declare class Deque<T extends any> {
8
8
  /**
9
9
  * capacity
10
- * @type {number}
10
+ * @internal
11
11
  */
12
12
  _c: number;
13
13
  /**
14
14
  * current length (size
15
- * @type {number}
15
+ * @internal
16
16
  */
17
17
  _l: number;
18
18
  /**
19
19
  * current front position
20
- * @type {number}
20
+ * @internal
21
21
  */
22
22
  _f: number;
23
23
  /**
24
- * @type {T[]}
24
+ * @internal
25
25
  */
26
26
  _a: T[];
27
+
27
28
  /**
28
29
  * default capacity `16`
29
30
  * @param ic initial capacity
@@ -95,6 +96,20 @@ export declare type TFlowableLock<T = TVoidFunction> = IFlowableLock & {
95
96
  };
96
97
  export declare type TVoidFunction = () => void;
97
98
 
99
+ export declare type TResolver = {
100
+ resolve: () => void;
101
+ reject: (reason: any) => void;
102
+ };
103
+ export declare interface IProcessAbortedError {
104
+ readonly message: "Process Aborted";
105
+ }
106
+ export type TAbortListener = (reason: IProcessAbortedError) => void;
107
+ export declare type TFlowableLockWithAbort = IFlowableLock & {
108
+ readonly q: Deque<TResolver>;
109
+ abort(): void;
110
+ onAbort(listener: TAbortListener): void;
111
+ offAbort(listener: TAbortListener): void;
112
+ };
98
113
 
99
114
  /**
100
115
  * #### Mini Semaphore
@@ -160,7 +175,7 @@ export declare class MiniSemaphore implements TFlowableLock {
160
175
  }
161
176
 
162
177
  /**
163
- * object implementation of `IFlowableLock`
178
+ * object implementation of `TFlowableLock`
164
179
  *
165
180
  * + constructs a semaphore object limited at `capacity`
166
181
  *
@@ -168,7 +183,18 @@ export declare class MiniSemaphore implements TFlowableLock {
168
183
  * @date 2020/2/7
169
184
  * @version 1.0
170
185
  */
171
- export declare const create: (capacity: number) => IFlowableLock;
186
+ export declare const create: (capacity: number) => TFlowableLock;
187
+ /**
188
+ * object implementation of `TFlowableLockWithAbort`
189
+ *
190
+ * + constructs a semaphore object limited at `capacity`
191
+ *
192
+ * @param {number} capacity limitation of concurrent async by `capacity`
193
+ * @date 2025/5/12
194
+ * @version 1.4
195
+ */
196
+ export declare const createWithAbort: (capacity: number) => TFlowableLockWithAbort;
197
+
172
198
 
173
199
  declare namespace fr {
174
200
  /**
package/cjs/index.js CHANGED
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.version = exports.restrictor = exports.Deque = exports.create = exports.MiniSemaphore = void 0;
3
+ exports.version = exports.restrictor = exports.Deque = exports.createWithAbort = exports.create = exports.MiniSemaphore = void 0;
4
4
  var class_1 = require("./class");
5
5
  Object.defineProperty(exports, "MiniSemaphore", { enumerable: true, get: function () { return class_1.MiniSemaphore; } });
6
6
  var object_1 = require("./object");
7
7
  Object.defineProperty(exports, "create", { enumerable: true, get: function () { return object_1.create; } });
8
+ Object.defineProperty(exports, "createWithAbort", { enumerable: true, get: function () { return object_1.createWithAbort; } });
8
9
  var deque_1 = require("./deque");
9
10
  Object.defineProperty(exports, "Deque", { enumerable: true, get: function () { return deque_1.Deque; } });
10
11
  var flow_restrictor_1 = require("./flow-restrictor");
11
12
  Object.defineProperty(exports, "restrictor", { enumerable: true, get: function () { return flow_restrictor_1.restrictor; } });
12
- exports.version = "v1.3.17";
13
+ exports.version = "v1.4.4";
package/cjs/object.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.create = void 0;
3
+ exports.createWithAbort = exports.create = void 0;
4
4
  /*!
5
5
  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
6
6
  Copyright (C) 2020 jeffy-g <hirotom1107@gmail.com>
@@ -17,6 +17,26 @@ const core = require("./core");
17
17
  const deque_1 = require("./deque");
18
18
  const a = core.acquire;
19
19
  const r = core.release;
20
+ const aa = core.acquireWithAbort;
21
+ const ra = core.releaseWithAbort;
22
+ /**
23
+ * @template {core.IFlowableLock & { q: Deque<unknown>}} T
24
+ * @param {number} capacity
25
+ * @returns
26
+ */
27
+ const createBase = (capacity) => {
28
+ return /** @type {T} */ ({
29
+ capacity,
30
+ limit: capacity,
31
+ q: new deque_1.Deque(capacity),
32
+ /**
33
+ * @param {number} restriction
34
+ */
35
+ setRestriction(restriction) {
36
+ this.limit = this.capacity = restriction;
37
+ },
38
+ });
39
+ };
20
40
  /**
21
41
  * object implementation of `IFlowableLock`
22
42
  *
@@ -27,10 +47,13 @@ const r = core.release;
27
47
  * @version 1.0
28
48
  */
29
49
  const create = (capacity) => {
50
+ /** @type {core.TFlowableLock} */
51
+ const base = createBase(capacity);
30
52
  return /** @satisfies {core.TFlowableLock} */ ({
31
- capacity,
32
- limit: capacity,
33
- q: new deque_1.Deque(capacity),
53
+ ...base,
54
+ get pending() {
55
+ return this.q.length;
56
+ },
34
57
  /**
35
58
  *
36
59
  * @param {boolean} [lazy]
@@ -42,15 +65,6 @@ const create = (capacity) => {
42
65
  release() {
43
66
  r(this);
44
67
  },
45
- /**
46
- * @param {number} restriction
47
- */
48
- setRestriction(restriction) {
49
- this.limit = this.capacity = restriction;
50
- },
51
- get pending() {
52
- return this.q.length;
53
- },
54
68
  /**
55
69
  * @template {any} T
56
70
  * @param {() => Promise<T>} process
@@ -68,4 +82,84 @@ const create = (capacity) => {
68
82
  }
69
83
  });
70
84
  };
71
- exports.create = create;
85
+ exports.create = create;
86
+ /**
87
+ * object implementation of `TFlowableLockWithAbort`
88
+ *
89
+ * + constructs a semaphore object limited at `capacity`
90
+ *
91
+ * @param {number} capacity limitation of concurrent async by `capacity`
92
+ * @date 2025/5/12
93
+ * @version 1.4
94
+ */
95
+ const createWithAbort = (capacity) => {
96
+ /** @type {core.TFlowableLockWithAbort} */
97
+ const base = createBase(capacity);
98
+ const abortListeners = [];
99
+ return /** @satisfies {core.TFlowableLockWithAbort} */ ({
100
+ ...base,
101
+ get pending() {
102
+ return this.q.length;
103
+ },
104
+ /**
105
+ * @returns {Promise<void>}
106
+ */
107
+ acquire() {
108
+ return aa(this);
109
+ },
110
+ release() {
111
+ ra(this);
112
+ },
113
+ /**
114
+ * @template {any} T
115
+ * @param {() => Promise<T>} process
116
+ * @returns {Promise<T>}
117
+ */
118
+ async flow(process) {
119
+ let result;
120
+ try {
121
+ await aa(this);
122
+ result = await process();
123
+ ra(this);
124
+ }
125
+ finally {
126
+ return result;
127
+ }
128
+ },
129
+ /**
130
+ * @throws {AggregateError} description
131
+ */
132
+ abort() {
133
+ const reason = {
134
+ message: "Process Aborted"
135
+ };
136
+ abortListeners.forEach(listener => listener(reason));
137
+ const dq = this.q;
138
+ let resolver;
139
+ while (resolver = dq.shift()) {
140
+ resolver.reject(reason);
141
+ }
142
+ this.capacity = this.limit;
143
+ },
144
+ /**
145
+ * Registers an event listener for the "abort" event.
146
+ * @param {core.TAbortListener} listener
147
+ */
148
+ onAbort(listener) {
149
+ if (!abortListeners.includes(listener)) {
150
+ abortListeners.push(listener);
151
+ }
152
+ },
153
+ /**
154
+ * Removes an event listener for the "abort" event.
155
+ * @param {core.TAbortListener} listener
156
+ */
157
+ offAbort(listener) {
158
+ const idx = abortListeners.findIndex(ls => listener === ls);
159
+ if (idx !== -1) {
160
+ /*return */ abortListeners.splice(idx, 1);
161
+ }
162
+ }
163
+ });
164
+ };
165
+ exports.createWithAbort = createWithAbort;
package/esm/core.mjs CHANGED
@@ -1,6 +1,8 @@
1
1
  /**
2
2
  * @typedef {import("./index.mjs").TVoidFunction} TVoidFunction
3
3
  * @typedef {import("./index.mjs").Deque<TVoidFunction>} Deque
4
+ * @typedef {import("./index.mjs").TFlowableLockWithAbort} TFlowableLockWithAbort
5
+ * @typedef {import("./index.mjs").Deque<TResolver>} DequeWithAbort
4
6
  * @typedef {import("./index.mjs").ISimplifiedLock} ISimplifiedLock
5
7
  * @typedef {import("./index.mjs").TFlowableLock} TFlowableLock
6
8
  * @typedef {import("./index.mjs").IFlowableLock} IFlowableLock
@@ -57,4 +59,39 @@ export const release = (dis) => {
57
59
  console.warn("inconsistent release!");
58
60
  dis.capacity = dis.limit;
59
61
  }
62
+ };
63
+ /**
64
+ * @param {TFlowableLockWithAbort} dis
65
+ * @returns {Promise<void>}
66
+ */
67
+ export const acquireWithAbort = (dis) => {
68
+ return new Promise((resolve, reject) => {
69
+ if (dis.capacity > 0) {
70
+ dis.capacity--, resolve();
71
+ }
72
+ else {
73
+ dis.q.push({
74
+ resolve, reject
75
+ });
76
+ }
77
+ });
78
+ };
79
+ /**
80
+ * @param {TFlowableLockWithAbort} dis
81
+ * @returns {void}
82
+ */
83
+ export const releaseWithAbort = (dis) => {
84
+ /** @type {DequeWithAbort} */
85
+ let dq;
86
+ if ((dq = dis.q).length) {
87
+ const resolver = dq.shift();
88
+ resolver && resolver.resolve() || (
89
+ /* istanbul ignore next */
90
+ THROW());
91
+ }
92
+ else {
93
+ if (dis.capacity < dis.limit) {
94
+ dis.capacity++;
95
+ }
96
+ }
60
97
  };
package/esm/deque.mjs CHANGED
@@ -54,24 +54,28 @@ export class Deque {
54
54
  constructor(ic) {
55
55
  /**
56
56
  * capacity
57
+ * @internal
57
58
  */
58
59
  this._c = gc(ic || 16);
59
60
  /**
60
61
  * current length (size
62
+ * @internal
61
63
  */
62
64
  this._l = 0;
63
65
  /**
64
66
  * current front position
67
+ * @internal
65
68
  */
66
69
  this._f = 0;
67
- /**
68
- *
69
- */
70
- this.length = 0;
71
70
  /**
72
71
  * @type {T[]}
72
+ * @internal
73
73
  */
74
74
  this._a = [];
75
+ /**
76
+ * current length (size
77
+ */
78
+ this.length = 0;
75
79
  }
76
80
  /**
77
81
  * @param {T} s subject
@@ -105,6 +109,7 @@ export class Deque {
105
109
  * @template {any} T
106
110
  * @param {Deque<T>} dis
107
111
  * @param {number} n expected capacity
112
+ * @todo test code
108
113
  */
109
114
  const rt = (dis, n) => {
110
115
  const oc = dis._c;
package/esm/index.d.mts CHANGED
@@ -7,23 +7,24 @@
7
7
  export declare class Deque<T extends any> {
8
8
  /**
9
9
  * capacity
10
- * @type {number}
10
+ * @internal
11
11
  */
12
12
  _c: number;
13
13
  /**
14
14
  * current length (size
15
- * @type {number}
15
+ * @internal
16
16
  */
17
17
  _l: number;
18
18
  /**
19
19
  * current front position
20
- * @type {number}
20
+ * @internal
21
21
  */
22
22
  _f: number;
23
23
  /**
24
- * @type {T[]}
24
+ * @internal
25
25
  */
26
26
  _a: T[];
27
+
27
28
  /**
28
29
  * default capacity `16`
29
30
  * @param ic initial capacity
@@ -95,6 +96,20 @@ export declare type TFlowableLock<T = TVoidFunction> = IFlowableLock & {
95
96
  };
96
97
  export declare type TVoidFunction = () => void;
97
98
 
99
+ export declare type TResolver = {
100
+ resolve: () => void;
101
+ reject: (reason: any) => void;
102
+ };
103
+ export declare interface IProcessAbortedError {
104
+ readonly message: "Process Aborted";
105
+ }
106
+ export type TAbortListener = (reason: IProcessAbortedError) => void;
107
+ export declare type TFlowableLockWithAbort = IFlowableLock & {
108
+ readonly q: Deque<TResolver>;
109
+ abort(): void;
110
+ onAbort(listener: TAbortListener): void;
111
+ offAbort(listener: TAbortListener): void;
112
+ };
98
113
 
99
114
  /**
100
115
  * #### Mini Semaphore
@@ -160,7 +175,7 @@ export declare class MiniSemaphore implements TFlowableLock {
160
175
  }
161
176
 
162
177
  /**
163
- * object implementation of `IFlowableLock`
178
+ * object implementation of `TFlowableLock`
164
179
  *
165
180
  * + constructs a semaphore object limited at `capacity`
166
181
  *
@@ -168,7 +183,18 @@ export declare class MiniSemaphore implements TFlowableLock {
168
183
  * @date 2020/2/7
169
184
  * @version 1.0
170
185
  */
171
- export declare const create: (capacity: number) => IFlowableLock;
186
+ export declare const create: (capacity: number) => TFlowableLock;
187
+ /**
188
+ * object implementation of `TFlowableLockWithAbort`
189
+ *
190
+ * + constructs a semaphore object limited at `capacity`
191
+ *
192
+ * @param {number} capacity limitation of concurrent async by `capacity`
193
+ * @date 2025/5/12
194
+ * @version 1.4
195
+ */
196
+ export declare const createWithAbort: (capacity: number) => TFlowableLockWithAbort;
197
+
172
198
 
173
199
  declare namespace fr {
174
200
  /**
package/esm/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  export { MiniSemaphore } from "./class.mjs";
2
- export { create } from "./object.mjs";
2
+ export { create, createWithAbort } from "./object.mjs";
3
3
  export { Deque } from "./deque.mjs";
4
4
  export { restrictor } from "./flow-restrictor.mjs";
5
- export const version = "v1.3.17";
5
+ export const version = "v1.4.4";
package/esm/object.mjs CHANGED
@@ -14,6 +14,26 @@ import * as core from "./core.mjs";
14
14
  import { Deque } from "./deque.mjs";
15
15
  const a = core.acquire;
16
16
  const r = core.release;
17
+ const aa = core.acquireWithAbort;
18
+ const ra = core.releaseWithAbort;
19
+ /**
20
+ * @template {core.IFlowableLock & { q: Deque<unknown>}} T
21
+ * @param {number} capacity
22
+ * @returns
23
+ */
24
+ const createBase = (capacity) => {
25
+ return /** @type {T} */ ({
26
+ capacity,
27
+ limit: capacity,
28
+ q: new Deque(capacity),
29
+ /**
30
+ * @param {number} restriction
31
+ */
32
+ setRestriction(restriction) {
33
+ this.limit = this.capacity = restriction;
34
+ },
35
+ });
36
+ };
17
37
  /**
18
38
  * object implementation of `IFlowableLock`
19
39
  *
@@ -24,10 +44,13 @@ const r = core.release;
24
44
  * @version 1.0
25
45
  */
26
46
  export const create = (capacity) => {
47
+ /** @type {core.TFlowableLock} */
48
+ const base = createBase(capacity);
27
49
  return /** @satisfies {core.TFlowableLock} */ ({
28
- capacity,
29
- limit: capacity,
30
- q: new Deque(capacity),
50
+ ...base,
51
+ get pending() {
52
+ return this.q.length;
53
+ },
31
54
  /**
32
55
  *
33
56
  * @param {boolean} [lazy]
@@ -39,15 +62,6 @@ export const create = (capacity) => {
39
62
  release() {
40
63
  r(this);
41
64
  },
42
- /**
43
- * @param {number} restriction
44
- */
45
- setRestriction(restriction) {
46
- this.limit = this.capacity = restriction;
47
- },
48
- get pending() {
49
- return this.q.length;
50
- },
51
65
  /**
52
66
  * @template {any} T
53
67
  * @param {() => Promise<T>} process
@@ -64,4 +78,83 @@ export const create = (capacity) => {
64
78
  }
65
79
  }
66
80
  });
81
+ };
82
+ /**
83
+ * object implementation of `TFlowableLockWithAbort`
84
+ *
85
+ * + constructs a semaphore object limited at `capacity`
86
+ *
87
+ * @param {number} capacity limitation of concurrent async by `capacity`
88
+ * @date 2025/5/12
89
+ * @version 1.4
90
+ */
91
+ export const createWithAbort = (capacity) => {
92
+ /** @type {core.TFlowableLockWithAbort} */
93
+ const base = createBase(capacity);
94
+ const abortListeners = [];
95
+ return /** @satisfies {core.TFlowableLockWithAbort} */ ({
96
+ ...base,
97
+ get pending() {
98
+ return this.q.length;
99
+ },
100
+ /**
101
+ * @returns {Promise<void>}
102
+ */
103
+ acquire() {
104
+ return aa(this);
105
+ },
106
+ release() {
107
+ ra(this);
108
+ },
109
+ /**
110
+ * @template {any} T
111
+ * @param {() => Promise<T>} process
112
+ * @returns {Promise<T>}
113
+ */
114
+ async flow(process) {
115
+ let result;
116
+ try {
117
+ await aa(this);
118
+ result = await process();
119
+ ra(this);
120
+ }
121
+ finally {
122
+ return result;
123
+ }
124
+ },
125
+ /**
126
+ * @throws {AggregateError} description
127
+ */
128
+ abort() {
129
+ const reason = {
130
+ message: "Process Aborted"
131
+ };
132
+ abortListeners.forEach(listener => listener(reason));
133
+ const dq = this.q;
134
+ let resolver;
135
+ while (resolver = dq.shift()) {
136
+ resolver.reject(reason);
137
+ }
138
+ this.capacity = this.limit;
139
+ },
140
+ /**
141
+ * Registers an event listener for the "abort" event.
142
+ * @param {core.TAbortListener} listener
143
+ */
144
+ onAbort(listener) {
145
+ if (!abortListeners.includes(listener)) {
146
+ abortListeners.push(listener);
147
+ }
148
+ },
149
+ /**
150
+ * Removes an event listener for the "abort" event.
151
+ * @param {core.TAbortListener} listener
152
+ */
153
+ offAbort(listener) {
154
+ const idx = abortListeners.findIndex(ls => listener === ls);
155
+ if (idx !== -1) {
156
+ /*return */ abortListeners.splice(idx, 1);
157
+ }
158
+ }
159
+ });
67
160
  };
package/index.d.ts CHANGED
@@ -7,23 +7,24 @@
7
7
  export declare class Deque<T extends any> {
8
8
  /**
9
9
  * capacity
10
- * @type {number}
10
+ * @internal
11
11
  */
12
12
  _c: number;
13
13
  /**
14
14
  * current length (size
15
- * @type {number}
15
+ * @internal
16
16
  */
17
17
  _l: number;
18
18
  /**
19
19
  * current front position
20
- * @type {number}
20
+ * @internal
21
21
  */
22
22
  _f: number;
23
23
  /**
24
- * @type {T[]}
24
+ * @internal
25
25
  */
26
26
  _a: T[];
27
+
27
28
  /**
28
29
  * default capacity `16`
29
30
  * @param ic initial capacity
@@ -95,6 +96,20 @@ export declare type TFlowableLock<T = TVoidFunction> = IFlowableLock & {
95
96
  };
96
97
  export declare type TVoidFunction = () => void;
97
98
 
99
+ export declare type TResolver = {
100
+ resolve: () => void;
101
+ reject: (reason: any) => void;
102
+ };
103
+ export declare interface IProcessAbortedError {
104
+ readonly message: "Process Aborted";
105
+ }
106
+ export type TAbortListener = (reason: IProcessAbortedError) => void;
107
+ export declare type TFlowableLockWithAbort = IFlowableLock & {
108
+ readonly q: Deque<TResolver>;
109
+ abort(): void;
110
+ onAbort(listener: TAbortListener): void;
111
+ offAbort(listener: TAbortListener): void;
112
+ };
98
113
 
99
114
  /**
100
115
  * #### Mini Semaphore
@@ -160,7 +175,7 @@ export declare class MiniSemaphore implements TFlowableLock {
160
175
  }
161
176
 
162
177
  /**
163
- * object implementation of `IFlowableLock`
178
+ * object implementation of `TFlowableLock`
164
179
  *
165
180
  * + constructs a semaphore object limited at `capacity`
166
181
  *
@@ -168,7 +183,18 @@ export declare class MiniSemaphore implements TFlowableLock {
168
183
  * @date 2020/2/7
169
184
  * @version 1.0
170
185
  */
171
- export declare const create: (capacity: number) => IFlowableLock;
186
+ export declare const create: (capacity: number) => TFlowableLock;
187
+ /**
188
+ * object implementation of `TFlowableLockWithAbort`
189
+ *
190
+ * + constructs a semaphore object limited at `capacity`
191
+ *
192
+ * @param {number} capacity limitation of concurrent async by `capacity`
193
+ * @date 2025/5/12
194
+ * @version 1.4
195
+ */
196
+ export declare const createWithAbort: (capacity: number) => TFlowableLockWithAbort;
197
+
172
198
 
173
199
  declare namespace fr {
174
200
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mini-semaphore",
3
- "version": "1.3.17",
3
+ "version": "1.4.4",
4
4
  "description": "A lightweight version of Semaphore",
5
5
  "private": false,
6
6
  "main": "./cjs/index.js",
package/umd/index.d.ts CHANGED
@@ -7,23 +7,24 @@
7
7
  export declare class Deque<T extends any> {
8
8
  /**
9
9
  * capacity
10
- * @type {number}
10
+ * @internal
11
11
  */
12
12
  _c: number;
13
13
  /**
14
14
  * current length (size
15
- * @type {number}
15
+ * @internal
16
16
  */
17
17
  _l: number;
18
18
  /**
19
19
  * current front position
20
- * @type {number}
20
+ * @internal
21
21
  */
22
22
  _f: number;
23
23
  /**
24
- * @type {T[]}
24
+ * @internal
25
25
  */
26
26
  _a: T[];
27
+
27
28
  /**
28
29
  * default capacity `16`
29
30
  * @param ic initial capacity
@@ -95,6 +96,20 @@ export declare type TFlowableLock<T = TVoidFunction> = IFlowableLock & {
95
96
  };
96
97
  export declare type TVoidFunction = () => void;
97
98
 
99
+ export declare type TResolver = {
100
+ resolve: () => void;
101
+ reject: (reason: any) => void;
102
+ };
103
+ export declare interface IProcessAbortedError {
104
+ readonly message: "Process Aborted";
105
+ }
106
+ export type TAbortListener = (reason: IProcessAbortedError) => void;
107
+ export declare type TFlowableLockWithAbort = IFlowableLock & {
108
+ readonly q: Deque<TResolver>;
109
+ abort(): void;
110
+ onAbort(listener: TAbortListener): void;
111
+ offAbort(listener: TAbortListener): void;
112
+ };
98
113
 
99
114
  /**
100
115
  * #### Mini Semaphore
@@ -160,7 +175,7 @@ export declare class MiniSemaphore implements TFlowableLock {
160
175
  }
161
176
 
162
177
  /**
163
- * object implementation of `IFlowableLock`
178
+ * object implementation of `TFlowableLock`
164
179
  *
165
180
  * + constructs a semaphore object limited at `capacity`
166
181
  *
@@ -168,7 +183,18 @@ export declare class MiniSemaphore implements TFlowableLock {
168
183
  * @date 2020/2/7
169
184
  * @version 1.0
170
185
  */
171
- export declare const create: (capacity: number) => IFlowableLock;
186
+ export declare const create: (capacity: number) => TFlowableLock;
187
+ /**
188
+ * object implementation of `TFlowableLockWithAbort`
189
+ *
190
+ * + constructs a semaphore object limited at `capacity`
191
+ *
192
+ * @param {number} capacity limitation of concurrent async by `capacity`
193
+ * @date 2025/5/12
194
+ * @version 1.4
195
+ */
196
+ export declare const createWithAbort: (capacity: number) => TFlowableLockWithAbort;
197
+
172
198
 
173
199
  declare namespace fr {
174
200
  /**
package/umd/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  /*! For license information please see index.js.LICENSE.txt */
2
- ((e,t)=>{'object'==typeof exports&&'object'==typeof module?module.exports=t():'function'==typeof define&&define.amd?define([],t):'object'==typeof exports?exports.MiniSema=t():e.MiniSema=t()})(globalThis,(()=>(()=>{"use strict";var e={139:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.create=void 0;const r=i(461),n=i(761),s=r.acquire,o=r.release;t.create=e=>({capacity:e,limit:e,q:new n.Deque(e),acquire(e){return s(this,e)},release(){o(this)},setRestriction(e){this.limit=this.capacity=e},get pending(){return this.q.length},async flow(e,t){await s(this,t);try{return await e()}finally{o(this)}}})},461:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.release=t.acquire=void 0;const i=()=>{
3
- throw new Error("mini-semaphore: Detected an inconsistent state, possibly due to a logic error or unexpected behavior.")},r=(e,t)=>{e.capacity>0?(e.capacity--,t()):e.q.push(t)};t.acquire=(e,t=!0)=>new Promise((i=>{t?setTimeout((()=>r(e,i)),4):r(e,i)}));t.release=e=>{let t;(t=e.q).length?(t.shift()||i)():e.capacity++,e.capacity>e.limit&&(console.warn("inconsistent release!"),e.capacity=e.limit)}},464:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r=i(518);t.restrictor=(()=>{const{MiniSemaphore:e}=r,t=new e(1);let i=Object.create(null);async function n(r,n,s){const o=await(async(r,n)=>{await t.acquire(!1);let s=i[r];if(s||(i[r]=s=new e(n)),s.limit!==n)throw t.release(),
4
- new ReferenceError(`Cannot get object with different restriction: key: '${String(r)}', lock.limit: ${s.limit} <-> restriction: ${n},`);return t.release(),s})(r,n),a=o.flow(s);return o.last=Date.now(),a}return{getLockByKey:async e=>{await t.acquire(!1);const r=i[e];return t.release(),r},cleanup:async(e,r)=>{await t.acquire(!1);const n=i,s=Object.create(null),o=Object.keys(n);let a,c=0;!e&&(e=1),e*=1e3,r&&(a=[]);for(let t=0,i=o.length;t<i;){const i=o[t++],l=n[i];l.last&&Date.now()-l.last>=e?(c++,r&&a.push(i)):s[i]=l}return i=s,t.release(),r&&console.log(`eliminated: [\n${a.join(",\n")}\n]\nlived: [\n${Object.keys(s).join(",\n")}\n]`),c},multi:n,one:async function(e,t){return n(e,1,t)}}})()},518:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MiniSemaphore=void 0
5
- ;const r=i(461),n=i(761),s=r.acquire,o=r.release;t.MiniSemaphore=class{constructor(e){this.limit=this.capacity=e,this.q=new n.Deque(e)}acquire(e){return s(this,e)}release(){o(this)}setRestriction(e){this.limit=this.capacity=e}get pending(){return this.q.length}async flow(e,t){await s(this,t);try{return await e()}finally{o(this)}}}},761:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Deque=void 0;const i=e=>(e=>(e>>>=0,e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,1+(e|=e>>16)))(Math.min(Math.max(16,0|e),1073741824));t.Deque=class{constructor(e){this._c=i(e||16),this._l=0,this._f=0,this.length=0,this._a=[]}push(e){const t=this._l;this._c<t+1&&r(this,i(1.5*this._c+16));const n=this._f+t&this._c-1;this._a[n]=e,this.length=this._l=t+1}shift(){const e=this._l;if(0===e)return
6
- ;const t=this._f,i=this._a[t];return this._a[t]=void 0,this._f=t+1&this._c-1,this.length=this._l=e-1,i}};const r=(e,t)=>{const i=e._c;e._c=t;const r=e._f+e._l;if(r>i){const t=r&i-1;((e,t,i,r,n)=>{for(let s=0;s<n;++s)i[s+r]=e[s+t],e[s+t]=void 0})(e._a,0,e._a,i,t)}}}},t={};function i(r){var n=t[r];if(void 0!==n)return n.exports;var s=t[r]={exports:{}};return e[r](s,s.exports,i),s.exports}var r={};return(()=>{var e=r;Object.defineProperty(e,"__esModule",{value:!0}),e.version=e.restrictor=e.Deque=e.create=e.MiniSemaphore=void 0;var t=i(518);Object.defineProperty(e,"MiniSemaphore",{enumerable:!0,get:function(){return t.MiniSemaphore}});var n=i(139);Object.defineProperty(e,"create",{enumerable:!0,get:function(){return n.create}});var s=i(761);Object.defineProperty(e,"Deque",{enumerable:!0,
7
- get:function(){return s.Deque}});var o=i(464);Object.defineProperty(e,"restrictor",{enumerable:!0,get:function(){return o.restrictor}}),e.version="v1.3.17"})(),r})()));
2
+ ((e,t)=>{'object'==typeof exports&&'object'==typeof module?module.exports=t():'function'==typeof define&&define.amd?define([],t):'object'==typeof exports?exports.MiniSema=t():e.MiniSema=t()})(globalThis,(()=>(()=>{"use strict";var e={139:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createWithAbort=t.create=void 0;const r=i(461),n=i(761),s=r.acquire,a=r.release,o=r.acquireWithAbort,c=r.releaseWithAbort,l=e=>({capacity:e,limit:e,q:new n.Deque(e),setRestriction(e){this.limit=this.capacity=e}});t.create=e=>({...l(e),get pending(){return this.q.length},acquire(e){return s(this,e)},release(){a(this)},async flow(e,t){await s(this,t);try{return await e()}finally{a(this)}}});t.createWithAbort=e=>{const t=l(e),i=[];return{...t,get pending(){return this.q.length},acquire(){
3
+ return o(this)},release(){c(this)},async flow(e){let t;try{await o(this),t=await e(),c(this)}finally{return t}},abort(){const e={message:"Process Aborted"};i.forEach((t=>t(e)));const t=this.q;let r;for(;r=t.shift();)r.reject(e);this.capacity=this.limit},onAbort(e){i.includes(e)||i.push(e)},offAbort(e){const t=i.findIndex((t=>e===t));-1!==t&&i.splice(t,1)}}}},461:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.releaseWithAbort=t.acquireWithAbort=t.release=t.acquire=void 0;const i=()=>{throw new Error("mini-semaphore: Detected an inconsistent state, possibly due to a logic error or unexpected behavior.")},r=(e,t)=>{e.capacity>0?(e.capacity--,t()):e.q.push(t)};t.acquire=(e,t=!0)=>new Promise((i=>{t?setTimeout((()=>r(e,i)),4):r(e,i)}));t.release=e=>{let t
4
+ ;(t=e.q).length?(t.shift()||i)():e.capacity++,e.capacity>e.limit&&(console.warn("inconsistent release!"),e.capacity=e.limit)};t.acquireWithAbort=e=>new Promise(((t,i)=>{e.capacity>0?(e.capacity--,t()):e.q.push({resolve:t,reject:i})}));t.releaseWithAbort=e=>{let t;if((t=e.q).length){const e=t.shift();e&&e.resolve()||i()}else e.capacity<e.limit&&e.capacity++}},464:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r=i(518);t.restrictor=(()=>{const{MiniSemaphore:e}=r,t=new e(1);let i=Object.create(null);async function n(r,n,s){const a=await(async(r,n)=>{await t.acquire(!1);let s=i[r];if(s||(i[r]=s=new e(n)),s.limit!==n)throw t.release(),
5
+ new ReferenceError(`Cannot get object with different restriction: key: '${String(r)}', lock.limit: ${s.limit} <-> restriction: ${n},`);return t.release(),s})(r,n),o=a.flow(s);return a.last=Date.now(),o}return{getLockByKey:async e=>{await t.acquire(!1);const r=i[e];return t.release(),r},cleanup:async(e,r)=>{await t.acquire(!1);const n=i,s=Object.create(null),a=Object.keys(n);let o,c=0;!e&&(e=1),e*=1e3,r&&(o=[]);for(let t=0,i=a.length;t<i;){const i=a[t++],l=n[i];l.last&&Date.now()-l.last>=e?(c++,r&&o.push(i)):s[i]=l}return i=s,t.release(),r&&console.log(`eliminated: [\n${o.join(",\n")}\n]\nlived: [\n${Object.keys(s).join(",\n")}\n]`),c},multi:n,one:async function(e,t){return n(e,1,t)}}})()},518:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MiniSemaphore=void 0
6
+ ;const r=i(461),n=i(761),s=r.acquire,a=r.release;t.MiniSemaphore=class{constructor(e){this.limit=this.capacity=e,this.q=new n.Deque(e)}acquire(e){return s(this,e)}release(){a(this)}setRestriction(e){this.limit=this.capacity=e}get pending(){return this.q.length}async flow(e,t){await s(this,t);try{return await e()}finally{a(this)}}}},761:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Deque=void 0;const i=e=>(e=>(e>>>=0,e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,1+(e|=e>>16)))(Math.min(Math.max(16,0|e),1073741824));t.Deque=class{constructor(e){this._c=i(e||16),this._l=0,this._f=0,this._a=[],this.length=0}push(e){const t=this._l;this._c<t+1&&r(this,i(1.5*this._c+16));const n=this._f+t&this._c-1;this._a[n]=e,this.length=this._l=t+1}shift(){const e=this._l;if(0===e)return
7
+ ;const t=this._f,i=this._a[t];return this._a[t]=void 0,this._f=t+1&this._c-1,this.length=this._l=e-1,i}};const r=(e,t)=>{const i=e._c;e._c=t;const r=e._f+e._l;if(r>i){const t=r&i-1;((e,t,i,r,n)=>{for(let s=0;s<n;++s)i[s+r]=e[s+t],e[s+t]=void 0})(e._a,0,e._a,i,t)}}}},t={};function i(r){var n=t[r];if(void 0!==n)return n.exports;var s=t[r]={exports:{}};return e[r](s,s.exports,i),s.exports}var r={};return(()=>{var e=r;Object.defineProperty(e,"__esModule",{value:!0}),e.version=e.restrictor=e.Deque=e.createWithAbort=e.create=e.MiniSemaphore=void 0;var t=i(518);Object.defineProperty(e,"MiniSemaphore",{enumerable:!0,get:function(){return t.MiniSemaphore}});var n=i(139);Object.defineProperty(e,"create",{enumerable:!0,get:function(){return n.create}}),Object.defineProperty(e,"createWithAbort",{
8
+ enumerable:!0,get:function(){return n.createWithAbort}});var s=i(761);Object.defineProperty(e,"Deque",{enumerable:!0,get:function(){return s.Deque}});var a=i(464);Object.defineProperty(e,"restrictor",{enumerable:!0,get:function(){return a.restrictor}}),e.version="v1.4.4"})(),r})()));
@@ -7,23 +7,24 @@
7
7
  export declare class Deque<T extends any> {
8
8
  /**
9
9
  * capacity
10
- * @type {number}
10
+ * @internal
11
11
  */
12
12
  _c: number;
13
13
  /**
14
14
  * current length (size
15
- * @type {number}
15
+ * @internal
16
16
  */
17
17
  _l: number;
18
18
  /**
19
19
  * current front position
20
- * @type {number}
20
+ * @internal
21
21
  */
22
22
  _f: number;
23
23
  /**
24
- * @type {T[]}
24
+ * @internal
25
25
  */
26
26
  _a: T[];
27
+
27
28
  /**
28
29
  * default capacity `16`
29
30
  * @param ic initial capacity
@@ -95,6 +96,20 @@ export declare type TFlowableLock<T = TVoidFunction> = IFlowableLock & {
95
96
  };
96
97
  export declare type TVoidFunction = () => void;
97
98
 
99
+ export declare type TResolver = {
100
+ resolve: () => void;
101
+ reject: (reason: any) => void;
102
+ };
103
+ export declare interface IProcessAbortedError {
104
+ readonly message: "Process Aborted";
105
+ }
106
+ export type TAbortListener = (reason: IProcessAbortedError) => void;
107
+ export declare type TFlowableLockWithAbort = IFlowableLock & {
108
+ readonly q: Deque<TResolver>;
109
+ abort(): void;
110
+ onAbort(listener: TAbortListener): void;
111
+ offAbort(listener: TAbortListener): void;
112
+ };
98
113
 
99
114
  /**
100
115
  * #### Mini Semaphore
@@ -160,7 +175,7 @@ export declare class MiniSemaphore implements TFlowableLock {
160
175
  }
161
176
 
162
177
  /**
163
- * object implementation of `IFlowableLock`
178
+ * object implementation of `TFlowableLock`
164
179
  *
165
180
  * + constructs a semaphore object limited at `capacity`
166
181
  *
@@ -168,7 +183,18 @@ export declare class MiniSemaphore implements TFlowableLock {
168
183
  * @date 2020/2/7
169
184
  * @version 1.0
170
185
  */
171
- export declare const create: (capacity: number) => IFlowableLock;
186
+ export declare const create: (capacity: number) => TFlowableLock;
187
+ /**
188
+ * object implementation of `TFlowableLockWithAbort`
189
+ *
190
+ * + constructs a semaphore object limited at `capacity`
191
+ *
192
+ * @param {number} capacity limitation of concurrent async by `capacity`
193
+ * @date 2025/5/12
194
+ * @version 1.4
195
+ */
196
+ export declare const createWithAbort: (capacity: number) => TFlowableLockWithAbort;
197
+
172
198
 
173
199
  declare namespace fr {
174
200
  /**
package/webpack/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  /*! For license information please see index.js.LICENSE.txt */
2
- (()=>{"use strict";var e={139:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.create=void 0;const r=i(461),n=i(761),s=r.acquire,a=r.release;t.create=e=>({capacity:e,limit:e,q:new n.Deque(e),acquire(e){return s(this,e)},release(){a(this)},setRestriction(e){this.limit=this.capacity=e},get pending(){return this.q.length},async flow(e,t){await s(this,t);try{return await e()}finally{a(this)}}})},461:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.release=t.acquire=void 0;const i=()=>{throw new Error("mini-semaphore: Detected an inconsistent state, possibly due to a logic error or unexpected behavior.")},r=(e,t)=>{e.capacity>0?(e.capacity--,t()):e.q.push(t)};t.acquire=(e,t=!0)=>new Promise((i=>{t?setTimeout((()=>r(e,i)),4):r(e,i)}));t.release=e=>{let t
3
- ;(t=e.q).length?(t.shift()||i)():e.capacity++,e.capacity>e.limit&&(console.warn("inconsistent release!"),e.capacity=e.limit)}},464:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r=i(518);t.restrictor=(()=>{const{MiniSemaphore:e}=r,t=new e(1);let i=Object.create(null);async function n(r,n,s){const a=await(async(r,n)=>{await t.acquire(!1);let s=i[r];if(s||(i[r]=s=new e(n)),s.limit!==n)throw t.release(),new ReferenceError(`Cannot get object with different restriction: key: '${String(r)}', lock.limit: ${s.limit} <-> restriction: ${n},`);return t.release(),s})(r,n),c=a.flow(s);return a.last=Date.now(),c}return{getLockByKey:async e=>{await t.acquire(!1);const r=i[e];return t.release(),r},cleanup:async(e,r)=>{await t.acquire(!1)
2
+ (()=>{"use strict";var e={139:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createWithAbort=t.create=void 0;const r=i(461),n=i(761),s=r.acquire,a=r.release,c=r.acquireWithAbort,o=r.releaseWithAbort,l=e=>({capacity:e,limit:e,q:new n.Deque(e),setRestriction(e){this.limit=this.capacity=e}});t.create=e=>({...l(e),get pending(){return this.q.length},acquire(e){return s(this,e)},release(){a(this)},async flow(e,t){await s(this,t);try{return await e()}finally{a(this)}}});t.createWithAbort=e=>{const t=l(e),i=[];return{...t,get pending(){return this.q.length},acquire(){return c(this)},release(){o(this)},async flow(e){let t;try{await c(this),t=await e(),o(this)}finally{return t}},abort(){const e={message:"Process Aborted"};i.forEach((t=>t(e)));const t=this.q;let r
3
+ ;for(;r=t.shift();)r.reject(e);this.capacity=this.limit},onAbort(e){i.includes(e)||i.push(e)},offAbort(e){const t=i.findIndex((t=>e===t));-1!==t&&i.splice(t,1)}}}},461:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.releaseWithAbort=t.acquireWithAbort=t.release=t.acquire=void 0;const i=()=>{throw new Error("mini-semaphore: Detected an inconsistent state, possibly due to a logic error or unexpected behavior.")},r=(e,t)=>{e.capacity>0?(e.capacity--,t()):e.q.push(t)};t.acquire=(e,t=!0)=>new Promise((i=>{t?setTimeout((()=>r(e,i)),4):r(e,i)}));t.release=e=>{let t;(t=e.q).length?(t.shift()||i)():e.capacity++,e.capacity>e.limit&&(console.warn("inconsistent release!"),e.capacity=e.limit)};t.acquireWithAbort=e=>new Promise(((t,i)=>{e.capacity>0?(e.capacity--,t()):e.q.push({resolve:t,
4
+ reject:i})}));t.releaseWithAbort=e=>{let t;if((t=e.q).length){const e=t.shift();e&&e.resolve()||i()}else e.capacity<e.limit&&e.capacity++}},464:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r=i(518);t.restrictor=(()=>{const{MiniSemaphore:e}=r,t=new e(1);let i=Object.create(null);async function n(r,n,s){const a=await(async(r,n)=>{await t.acquire(!1);let s=i[r];if(s||(i[r]=s=new e(n)),s.limit!==n)throw t.release(),new ReferenceError(`Cannot get object with different restriction: key: '${String(r)}', lock.limit: ${s.limit} <-> restriction: ${n},`);return t.release(),s})(r,n),c=a.flow(s);return a.last=Date.now(),c}return{getLockByKey:async e=>{await t.acquire(!1);const r=i[e];return t.release(),r},cleanup:async(e,r)=>{await t.acquire(!1)
4
5
  ;const n=i,s=Object.create(null),a=Object.keys(n);let c,o=0;!e&&(e=1),e*=1e3,r&&(c=[]);for(let t=0,i=a.length;t<i;){const i=a[t++],l=n[i];l.last&&Date.now()-l.last>=e?(o++,r&&c.push(i)):s[i]=l}return i=s,t.release(),r&&console.log(`eliminated: [\n${c.join(",\n")}\n]\nlived: [\n${Object.keys(s).join(",\n")}\n]`),o},multi:n,one:async function(e,t){return n(e,1,t)}}})()},518:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MiniSemaphore=void 0;const r=i(461),n=i(761),s=r.acquire,a=r.release;t.MiniSemaphore=class{constructor(e){this.limit=this.capacity=e,this.q=new n.Deque(e)}acquire(e){return s(this,e)}release(){a(this)}setRestriction(e){this.limit=this.capacity=e}get pending(){return this.q.length}async flow(e,t){await s(this,t);try{return await e()}finally{a(this)}}}},
5
- 761:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Deque=void 0;const i=e=>(e=>(e>>>=0,e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,1+(e|=e>>16)))(Math.min(Math.max(16,0|e),1073741824));t.Deque=class{constructor(e){this._c=i(e||16),this._l=0,this._f=0,this.length=0,this._a=[]}push(e){const t=this._l;this._c<t+1&&r(this,i(1.5*this._c+16));const n=this._f+t&this._c-1;this._a[n]=e,this.length=this._l=t+1}shift(){const e=this._l;if(0===e)return;const t=this._f,i=this._a[t];return this._a[t]=void 0,this._f=t+1&this._c-1,this.length=this._l=e-1,i}};const r=(e,t)=>{const i=e._c;e._c=t;const r=e._f+e._l;if(r>i){const t=r&i-1;((e,t,i,r,n)=>{for(let s=0;s<n;++s)i[s+r]=e[s+t],e[s+t]=void 0})(e._a,0,e._a,i,t)}}}},t={};function i(r){var n=t[r];if(void 0!==n)return n.exports;var s=t[r]={exports:{}}
6
- ;return e[r](s,s.exports,i),s.exports}var r={};(()=>{var e=r;Object.defineProperty(e,"__esModule",{value:!0}),e.version=e.restrictor=e.Deque=e.create=e.MiniSemaphore=void 0;var t=i(518);Object.defineProperty(e,"MiniSemaphore",{enumerable:!0,get:function(){return t.MiniSemaphore}});var n=i(139);Object.defineProperty(e,"create",{enumerable:!0,get:function(){return n.create}});var s=i(761);Object.defineProperty(e,"Deque",{enumerable:!0,get:function(){return s.Deque}});var a=i(464);Object.defineProperty(e,"restrictor",{enumerable:!0,get:function(){return a.restrictor}}),e.version="v1.3.17"})(),module.exports=r})();
6
+ 761:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Deque=void 0;const i=e=>(e=>(e>>>=0,e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,1+(e|=e>>16)))(Math.min(Math.max(16,0|e),1073741824));t.Deque=class{constructor(e){this._c=i(e||16),this._l=0,this._f=0,this._a=[],this.length=0}push(e){const t=this._l;this._c<t+1&&r(this,i(1.5*this._c+16));const n=this._f+t&this._c-1;this._a[n]=e,this.length=this._l=t+1}shift(){const e=this._l;if(0===e)return;const t=this._f,i=this._a[t];return this._a[t]=void 0,this._f=t+1&this._c-1,this.length=this._l=e-1,i}};const r=(e,t)=>{const i=e._c;e._c=t;const r=e._f+e._l;if(r>i){const t=r&i-1;((e,t,i,r,n)=>{for(let s=0;s<n;++s)i[s+r]=e[s+t],e[s+t]=void 0})(e._a,0,e._a,i,t)}}}},t={};function i(r){var n=t[r];if(void 0!==n)return n.exports;var s=t[r]={exports:{}}
7
+ ;return e[r](s,s.exports,i),s.exports}var r={};(()=>{var e=r;Object.defineProperty(e,"__esModule",{value:!0}),e.version=e.restrictor=e.Deque=e.createWithAbort=e.create=e.MiniSemaphore=void 0;var t=i(518);Object.defineProperty(e,"MiniSemaphore",{enumerable:!0,get:function(){return t.MiniSemaphore}});var n=i(139);Object.defineProperty(e,"create",{enumerable:!0,get:function(){return n.create}}),Object.defineProperty(e,"createWithAbort",{enumerable:!0,get:function(){return n.createWithAbort}});var s=i(761);Object.defineProperty(e,"Deque",{enumerable:!0,get:function(){return s.Deque}});var a=i(464);Object.defineProperty(e,"restrictor",{enumerable:!0,get:function(){return a.restrictor}}),e.version="v1.4.4"})(),module.exports=r})();
@@ -7,23 +7,24 @@
7
7
  export declare class Deque<T extends any> {
8
8
  /**
9
9
  * capacity
10
- * @type {number}
10
+ * @internal
11
11
  */
12
12
  _c: number;
13
13
  /**
14
14
  * current length (size
15
- * @type {number}
15
+ * @internal
16
16
  */
17
17
  _l: number;
18
18
  /**
19
19
  * current front position
20
- * @type {number}
20
+ * @internal
21
21
  */
22
22
  _f: number;
23
23
  /**
24
- * @type {T[]}
24
+ * @internal
25
25
  */
26
26
  _a: T[];
27
+
27
28
  /**
28
29
  * default capacity `16`
29
30
  * @param ic initial capacity
@@ -95,6 +96,20 @@ export declare type TFlowableLock<T = TVoidFunction> = IFlowableLock & {
95
96
  };
96
97
  export declare type TVoidFunction = () => void;
97
98
 
99
+ export declare type TResolver = {
100
+ resolve: () => void;
101
+ reject: (reason: any) => void;
102
+ };
103
+ export declare interface IProcessAbortedError {
104
+ readonly message: "Process Aborted";
105
+ }
106
+ export type TAbortListener = (reason: IProcessAbortedError) => void;
107
+ export declare type TFlowableLockWithAbort = IFlowableLock & {
108
+ readonly q: Deque<TResolver>;
109
+ abort(): void;
110
+ onAbort(listener: TAbortListener): void;
111
+ offAbort(listener: TAbortListener): void;
112
+ };
98
113
 
99
114
  /**
100
115
  * #### Mini Semaphore
@@ -160,7 +175,7 @@ export declare class MiniSemaphore implements TFlowableLock {
160
175
  }
161
176
 
162
177
  /**
163
- * object implementation of `IFlowableLock`
178
+ * object implementation of `TFlowableLock`
164
179
  *
165
180
  * + constructs a semaphore object limited at `capacity`
166
181
  *
@@ -168,7 +183,18 @@ export declare class MiniSemaphore implements TFlowableLock {
168
183
  * @date 2020/2/7
169
184
  * @version 1.0
170
185
  */
171
- export declare const create: (capacity: number) => IFlowableLock;
186
+ export declare const create: (capacity: number) => TFlowableLock;
187
+ /**
188
+ * object implementation of `TFlowableLockWithAbort`
189
+ *
190
+ * + constructs a semaphore object limited at `capacity`
191
+ *
192
+ * @param {number} capacity limitation of concurrent async by `capacity`
193
+ * @date 2025/5/12
194
+ * @version 1.4
195
+ */
196
+ export declare const createWithAbort: (capacity: number) => TFlowableLockWithAbort;
197
+
172
198
 
173
199
  declare namespace fr {
174
200
  /**
@@ -1,6 +1,7 @@
1
1
  /*! For license information please see index.js.LICENSE.txt */
2
- var e={139:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.create=void 0;const r=i(461),n=i(761),s=r.acquire,a=r.release;t.create=e=>({capacity:e,limit:e,q:new n.Deque(e),acquire(e){return s(this,e)},release(){a(this)},setRestriction(e){this.limit=this.capacity=e},get pending(){return this.q.length},async flow(e,t){await s(this,t);try{return await e()}finally{a(this)}}})},461:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.release=t.acquire=void 0;const i=()=>{throw new Error("mini-semaphore: Detected an inconsistent state, possibly due to a logic error or unexpected behavior.")},r=(e,t)=>{e.capacity>0?(e.capacity--,t()):e.q.push(t)};t.acquire=(e,t=!0)=>new Promise((i=>{t?setTimeout((()=>r(e,i)),4):r(e,i)}));t.release=e=>{let t
3
- ;(t=e.q).length?(t.shift()||i)():e.capacity++,e.capacity>e.limit&&(console.warn("inconsistent release!"),e.capacity=e.limit)}},464:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r=i(518);t.restrictor=(()=>{const{MiniSemaphore:e}=r,t=new e(1);let i=Object.create(null);async function n(r,n,s){const a=await(async(r,n)=>{await t.acquire(!1);let s=i[r];if(s||(i[r]=s=new e(n)),s.limit!==n)throw t.release(),new ReferenceError(`Cannot get object with different restriction: key: '${String(r)}', lock.limit: ${s.limit} <-> restriction: ${n},`);return t.release(),s})(r,n),c=a.flow(s);return a.last=Date.now(),c}return{getLockByKey:async e=>{await t.acquire(!1);const r=i[e];return t.release(),r},cleanup:async(e,r)=>{await t.acquire(!1)
4
- ;const n=i,s=Object.create(null),a=Object.keys(n);let c,o=0;!e&&(e=1),e*=1e3,r&&(c=[]);for(let t=0,i=a.length;t<i;){const i=a[t++],l=n[i];l.last&&Date.now()-l.last>=e?(o++,r&&c.push(i)):s[i]=l}return i=s,t.release(),r&&console.log(`eliminated: [\n${c.join(",\n")}\n]\nlived: [\n${Object.keys(s).join(",\n")}\n]`),o},multi:n,one:async function(e,t){return n(e,1,t)}}})()},518:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MiniSemaphore=void 0;const r=i(461),n=i(761),s=r.acquire,a=r.release;t.MiniSemaphore=class{constructor(e){this.limit=this.capacity=e,this.q=new n.Deque(e)}acquire(e){return s(this,e)}release(){a(this)}setRestriction(e){this.limit=this.capacity=e}get pending(){return this.q.length}async flow(e,t){await s(this,t);try{return await e()}finally{a(this)}}}},
5
- 761:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Deque=void 0;const i=e=>(e=>(e>>>=0,e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,1+(e|=e>>16)))(Math.min(Math.max(16,0|e),1073741824));t.Deque=class{constructor(e){this._c=i(e||16),this._l=0,this._f=0,this.length=0,this._a=[]}push(e){const t=this._l;this._c<t+1&&r(this,i(1.5*this._c+16));const n=this._f+t&this._c-1;this._a[n]=e,this.length=this._l=t+1}shift(){const e=this._l;if(0===e)return;const t=this._f,i=this._a[t];return this._a[t]=void 0,this._f=t+1&this._c-1,this.length=this._l=e-1,i}};const r=(e,t)=>{const i=e._c;e._c=t;const r=e._f+e._l;if(r>i){const t=r&i-1;((e,t,i,r,n)=>{for(let s=0;s<n;++s)i[s+r]=e[s+t],e[s+t]=void 0})(e._a,0,e._a,i,t)}}}},t={};function i(r){var n=t[r];if(void 0!==n)return n.exports;var s=t[r]={exports:{}}
6
- ;return e[r](s,s.exports,i),s.exports}var r={};(()=>{var e=r;Object.defineProperty(e,"BJ",{value:!0}),e.rE=e.Ws=e.Jj=e.vt=e.C=void 0;var t=i(518);Object.defineProperty(e,"C",{enumerable:!0,get:function(){return t.MiniSemaphore}});var n=i(139);Object.defineProperty(e,"vt",{enumerable:!0,get:function(){return n.create}});var s=i(761);Object.defineProperty(e,"Jj",{enumerable:!0,get:function(){return s.Deque}});var a=i(464);Object.defineProperty(e,"Ws",{enumerable:!0,get:function(){return a.restrictor}}),e.rE="v1.3.17"})();const n=r.Jj,s=r.C,a=r.BJ,c=r.vt,o=r.Ws,l=r.rE;export{n as Deque,s as MiniSemaphore,a as __esModule,c as create,o as restrictor,l as version};
2
+ var e={139:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createWithAbort=t.create=void 0;const r=i(461),s=i(761),n=r.acquire,a=r.release,c=r.acquireWithAbort,o=r.releaseWithAbort,l=e=>({capacity:e,limit:e,q:new s.Deque(e),setRestriction(e){this.limit=this.capacity=e}});t.create=e=>({...l(e),get pending(){return this.q.length},acquire(e){return n(this,e)},release(){a(this)},async flow(e,t){await n(this,t);try{return await e()}finally{a(this)}}});t.createWithAbort=e=>{const t=l(e),i=[];return{...t,get pending(){return this.q.length},acquire(){return c(this)},release(){o(this)},async flow(e){let t;try{await c(this),t=await e(),o(this)}finally{return t}},abort(){const e={message:"Process Aborted"};i.forEach((t=>t(e)));const t=this.q;let r;for(;r=t.shift();)r.reject(e)
3
+ ;this.capacity=this.limit},onAbort(e){i.includes(e)||i.push(e)},offAbort(e){const t=i.findIndex((t=>e===t));-1!==t&&i.splice(t,1)}}}},461:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.releaseWithAbort=t.acquireWithAbort=t.release=t.acquire=void 0;const i=()=>{throw new Error("mini-semaphore: Detected an inconsistent state, possibly due to a logic error or unexpected behavior.")},r=(e,t)=>{e.capacity>0?(e.capacity--,t()):e.q.push(t)};t.acquire=(e,t=!0)=>new Promise((i=>{t?setTimeout((()=>r(e,i)),4):r(e,i)}));t.release=e=>{let t;(t=e.q).length?(t.shift()||i)():e.capacity++,e.capacity>e.limit&&(console.warn("inconsistent release!"),e.capacity=e.limit)};t.acquireWithAbort=e=>new Promise(((t,i)=>{e.capacity>0?(e.capacity--,t()):e.q.push({resolve:t,reject:i})}))
4
+ ;t.releaseWithAbort=e=>{let t;if((t=e.q).length){const e=t.shift();e&&e.resolve()||i()}else e.capacity<e.limit&&e.capacity++}},464:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r=i(518);t.restrictor=(()=>{const{MiniSemaphore:e}=r,t=new e(1);let i=Object.create(null);async function s(r,s,n){const a=await(async(r,s)=>{await t.acquire(!1);let n=i[r];if(n||(i[r]=n=new e(s)),n.limit!==s)throw t.release(),new ReferenceError(`Cannot get object with different restriction: key: '${String(r)}', lock.limit: ${n.limit} <-> restriction: ${s},`);return t.release(),n})(r,s),c=a.flow(n);return a.last=Date.now(),c}return{getLockByKey:async e=>{await t.acquire(!1);const r=i[e];return t.release(),r},cleanup:async(e,r)=>{await t.acquire(!1)
5
+ ;const s=i,n=Object.create(null),a=Object.keys(s);let c,o=0;!e&&(e=1),e*=1e3,r&&(c=[]);for(let t=0,i=a.length;t<i;){const i=a[t++],l=s[i];l.last&&Date.now()-l.last>=e?(o++,r&&c.push(i)):n[i]=l}return i=n,t.release(),r&&console.log(`eliminated: [\n${c.join(",\n")}\n]\nlived: [\n${Object.keys(n).join(",\n")}\n]`),o},multi:s,one:async function(e,t){return s(e,1,t)}}})()},518:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MiniSemaphore=void 0;const r=i(461),s=i(761),n=r.acquire,a=r.release;t.MiniSemaphore=class{constructor(e){this.limit=this.capacity=e,this.q=new s.Deque(e)}acquire(e){return n(this,e)}release(){a(this)}setRestriction(e){this.limit=this.capacity=e}get pending(){return this.q.length}async flow(e,t){await n(this,t);try{return await e()}finally{a(this)}}}},
6
+ 761:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Deque=void 0;const i=e=>(e=>(e>>>=0,e--,e|=e>>1,e|=e>>2,e|=e>>4,e|=e>>8,1+(e|=e>>16)))(Math.min(Math.max(16,0|e),1073741824));t.Deque=class{constructor(e){this._c=i(e||16),this._l=0,this._f=0,this._a=[],this.length=0}push(e){const t=this._l;this._c<t+1&&r(this,i(1.5*this._c+16));const s=this._f+t&this._c-1;this._a[s]=e,this.length=this._l=t+1}shift(){const e=this._l;if(0===e)return;const t=this._f,i=this._a[t];return this._a[t]=void 0,this._f=t+1&this._c-1,this.length=this._l=e-1,i}};const r=(e,t)=>{const i=e._c;e._c=t;const r=e._f+e._l;if(r>i){const t=r&i-1;((e,t,i,r,s)=>{for(let n=0;n<s;++n)i[n+r]=e[n+t],e[n+t]=void 0})(e._a,0,e._a,i,t)}}}},t={};function i(r){var s=t[r];if(void 0!==s)return s.exports;var n=t[r]={exports:{}}
7
+ ;return e[r](n,n.exports,i),n.exports}var r={};(()=>{var e=r;Object.defineProperty(e,"BJ",{value:!0}),e.rE=e.Ws=e.Jj=e.Xz=e.vt=e.C=void 0;var t=i(518);Object.defineProperty(e,"C",{enumerable:!0,get:function(){return t.MiniSemaphore}});var s=i(139);Object.defineProperty(e,"vt",{enumerable:!0,get:function(){return s.create}}),Object.defineProperty(e,"Xz",{enumerable:!0,get:function(){return s.createWithAbort}});var n=i(761);Object.defineProperty(e,"Jj",{enumerable:!0,get:function(){return n.Deque}});var a=i(464);Object.defineProperty(e,"Ws",{enumerable:!0,get:function(){return a.restrictor}}),e.rE="v1.4.4"})();const s=r.Jj,n=r.C,a=r.BJ,c=r.vt,o=r.Xz,l=r.Ws,h=r.rE;export{s as Deque,n as MiniSemaphore,a as __esModule,c as create,o as createWithAbort,l as restrictor,h as version};