mini-semaphore 1.4.2 → 1.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +63 -0
- package/cjs/class.d.ts +85 -0
- package/cjs/core.d.ts +107 -0
- package/cjs/core.js +13 -14
- package/cjs/deque.d.ts +28 -0
- package/cjs/flow-restrictor.d.ts +21 -0
- package/cjs/index.d.ts +6 -0
- package/cjs/index.js +1 -1
- package/cjs/object.d.ts +86 -0
- package/cjs/object.js +46 -10
- package/esm/core.mjs +13 -14
- package/esm/index.d.mts +6 -0
- package/esm/index.mjs +1 -1
- package/esm/object.mjs +46 -10
- package/index.d.ts +6 -0
- package/package.json +38 -1
- package/umd/index.d.ts +6 -0
- package/umd/index.js +7 -6
- package/webpack/index.d.ts +6 -0
- package/webpack/index.js +6 -6
- package/webpack-esm/index.d.mts +6 -0
- package/webpack-esm/index.mjs +7 -6
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/class.d.ts
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
3
|
+
Copyright (C) 2020 jeffy-g <hirotom1107@gmail.com>
|
|
4
|
+
Released under the MIT license
|
|
5
|
+
https://opensource.org/licenses/mit-license.php
|
|
6
|
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @file minimal implementation of semaphore (class implementation
|
|
10
|
+
* @author jeffy-g <hirotom1107@gmail.com>
|
|
11
|
+
* @version 1.0
|
|
12
|
+
*/
|
|
13
|
+
import * as core from "./core";
|
|
14
|
+
import { Deque } from "./deque";
|
|
15
|
+
export type * from "./core";
|
|
16
|
+
/**
|
|
17
|
+
* #### Mini Semaphore
|
|
18
|
+
*
|
|
19
|
+
* + minimal implementation of semaphore
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* import { MiniSemaphore } from "mini-semaphore";
|
|
23
|
+
*
|
|
24
|
+
* const s = new MiniSemaphore(10);
|
|
25
|
+
* async function fetchTypeData(type_id) {
|
|
26
|
+
* await s.acquire();
|
|
27
|
+
* try {
|
|
28
|
+
* return fetch(`https://esi.evetech.net/latest/universe/types/${type_id}/`);
|
|
29
|
+
* } finally {
|
|
30
|
+
* s.release();
|
|
31
|
+
* }
|
|
32
|
+
* }
|
|
33
|
+
*
|
|
34
|
+
* //
|
|
35
|
+
* // or automatic acquire/release
|
|
36
|
+
* //
|
|
37
|
+
* async function fetchTypeData(type_id) {
|
|
38
|
+
* return s.flow(async () => fetch(`https://esi.evetech.net/latest/universe/types/${type_id}/`));
|
|
39
|
+
* }
|
|
40
|
+
*
|
|
41
|
+
* @date 2020/2/7
|
|
42
|
+
* @version 1.0
|
|
43
|
+
*/
|
|
44
|
+
export declare class MiniSemaphore implements core.TFlowableLock {
|
|
45
|
+
/**
|
|
46
|
+
* spare capacity
|
|
47
|
+
*/
|
|
48
|
+
capacity: number;
|
|
49
|
+
/**
|
|
50
|
+
* limitation
|
|
51
|
+
*/
|
|
52
|
+
limit: number;
|
|
53
|
+
/**
|
|
54
|
+
* queue of Promise's `resolve`
|
|
55
|
+
*/
|
|
56
|
+
q: Deque<core.TVoidFunction>;
|
|
57
|
+
/**
|
|
58
|
+
* constructs a semaphore instance limited at `capacity`
|
|
59
|
+
*
|
|
60
|
+
* @param {number} capacity limitation of concurrent async by `capacity`
|
|
61
|
+
*/
|
|
62
|
+
constructor(capacity: number);
|
|
63
|
+
/**
|
|
64
|
+
* If there is enough capacity, execute the `resolve` immediately
|
|
65
|
+
*
|
|
66
|
+
* If not, put it in a queue and wait for the currently pending process to execute `release`
|
|
67
|
+
*
|
|
68
|
+
* @param {boolean=} lazy
|
|
69
|
+
*/
|
|
70
|
+
acquire(lazy?: boolean): Promise<void>;
|
|
71
|
+
release(): void;
|
|
72
|
+
/**
|
|
73
|
+
* @param {number} restriction
|
|
74
|
+
*/
|
|
75
|
+
setRestriction(restriction: number): void;
|
|
76
|
+
get pending(): number;
|
|
77
|
+
/**
|
|
78
|
+
* automatic acquire/release
|
|
79
|
+
*
|
|
80
|
+
* @template {any} T description
|
|
81
|
+
* @param {() => Promise<T>} process
|
|
82
|
+
* @param {boolean=} lazy
|
|
83
|
+
*/
|
|
84
|
+
flow<T>(process: () => Promise<T>, lazy?: boolean): Promise<T>;
|
|
85
|
+
}
|
package/cjs/core.d.ts
ADDED
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
3
|
+
Copyright (C) 2020 jeffy-g <hirotom1107@gmail.com>
|
|
4
|
+
Released under the MIT license
|
|
5
|
+
https://opensource.org/licenses/mit-license.php
|
|
6
|
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @file minimal implementation of semaphore (core
|
|
10
|
+
* @author jeffy-g <hirotom1107@gmail.com>
|
|
11
|
+
* @version 1.0
|
|
12
|
+
*/
|
|
13
|
+
import type { Deque } from "./deque";
|
|
14
|
+
/**
|
|
15
|
+
* basic of simplified lock interface
|
|
16
|
+
*/
|
|
17
|
+
export interface ISimplifiedLock {
|
|
18
|
+
/**
|
|
19
|
+
* acquire the process rights
|
|
20
|
+
*
|
|
21
|
+
* @param {boolean} lazy Whether the privilege acquisition process is deffer. default `true`
|
|
22
|
+
*/
|
|
23
|
+
acquire(lazy?: boolean): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* release the pending of one
|
|
26
|
+
*/
|
|
27
|
+
release(): void;
|
|
28
|
+
/**
|
|
29
|
+
* Change sharing restrictions to the value of `restriction`
|
|
30
|
+
* @param {number} restriction
|
|
31
|
+
*/
|
|
32
|
+
setRestriction(restriction: number): void;
|
|
33
|
+
/**
|
|
34
|
+
* Get the number of currently pending processes
|
|
35
|
+
* @type {number}
|
|
36
|
+
*/
|
|
37
|
+
readonly pending: number;
|
|
38
|
+
/**
|
|
39
|
+
* limitation
|
|
40
|
+
* @type {number}
|
|
41
|
+
*/
|
|
42
|
+
limit: number;
|
|
43
|
+
/**
|
|
44
|
+
* capacity
|
|
45
|
+
* @type {number}
|
|
46
|
+
*/
|
|
47
|
+
capacity: number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* extention of `ISimplifiedLock` interface
|
|
51
|
+
*/
|
|
52
|
+
export interface IFlowableLock extends ISimplifiedLock {
|
|
53
|
+
/**
|
|
54
|
+
* combination of acquire/release
|
|
55
|
+
*
|
|
56
|
+
* + acquire/release is automatic
|
|
57
|
+
*
|
|
58
|
+
* @param lazy Whether the privilege acquisition process is deffer. default `true`
|
|
59
|
+
*/
|
|
60
|
+
flow<T>(f: () => Promise<T>, lazy?: boolean): Promise<T>;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* internal type for `createMiniSemaphore`
|
|
64
|
+
*/
|
|
65
|
+
export type TFlowableLock<T = TVoidFunction> = IFlowableLock & {
|
|
66
|
+
/**
|
|
67
|
+
* pending
|
|
68
|
+
*/
|
|
69
|
+
readonly q: Deque<T>;
|
|
70
|
+
};
|
|
71
|
+
export type TResolver = {
|
|
72
|
+
resolve: () => void;
|
|
73
|
+
reject: (reason: any) => void;
|
|
74
|
+
};
|
|
75
|
+
export type TAbortListener = (reason: IProcessAbortedError) => void;
|
|
76
|
+
export type TFlowableLockWithAbort = IFlowableLock & {
|
|
77
|
+
readonly q: Deque<TResolver>;
|
|
78
|
+
abort(): void;
|
|
79
|
+
onAbort(listener: TAbortListener): void;
|
|
80
|
+
offAbort(listener: TAbortListener): void;
|
|
81
|
+
};
|
|
82
|
+
export declare interface IProcessAbortedError {
|
|
83
|
+
readonly message: "Process Aborted";
|
|
84
|
+
}
|
|
85
|
+
export type TVoidFunction = () => void;
|
|
86
|
+
/**
|
|
87
|
+
*
|
|
88
|
+
* @param {TFlowableLock} dis
|
|
89
|
+
* @param {boolean} [lazy] default: true
|
|
90
|
+
* @returns {Promise<void>}
|
|
91
|
+
*/
|
|
92
|
+
export declare const acquire: (dis: TFlowableLock, lazy?: boolean) => Promise<void>;
|
|
93
|
+
/**
|
|
94
|
+
* @param {TFlowableLock} dis
|
|
95
|
+
* @returns {void}
|
|
96
|
+
*/
|
|
97
|
+
export declare const release: (dis: TFlowableLock) => void;
|
|
98
|
+
/**
|
|
99
|
+
* @param {TFlowableLockWithAbort} dis
|
|
100
|
+
* @returns {Promise<void>}
|
|
101
|
+
*/
|
|
102
|
+
export declare const acquireWithAbort: (dis: TFlowableLockWithAbort) => Promise<void>;
|
|
103
|
+
/**
|
|
104
|
+
* @param {TFlowableLockWithAbort} dis
|
|
105
|
+
* @returns {void}
|
|
106
|
+
*/
|
|
107
|
+
export declare const releaseWithAbort: (dis: TFlowableLockWithAbort) => void;
|
package/cjs/core.js
CHANGED
|
@@ -2,13 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.releaseWithAbort = exports.acquireWithAbort = exports.release = exports.acquire = void 0;
|
|
4
4
|
/**
|
|
5
|
-
* @
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
5
|
+
* @import {
|
|
6
|
+
* TResolver,
|
|
7
|
+
* TVoidFunction,
|
|
8
|
+
* TFlowableLockWithAbort,
|
|
9
|
+
* ISimplifiedLock,
|
|
10
|
+
* TFlowableLock,
|
|
11
|
+
* IFlowableLock,
|
|
12
|
+
* Deque,
|
|
13
|
+
* } from "./index.mjs";
|
|
14
|
+
* @typedef {Deque<TResolver>} DequeWithAbort
|
|
12
15
|
*/
|
|
13
16
|
/**
|
|
14
17
|
* Throws an error indicating an inconsistent state in mini-semaphore.
|
|
@@ -51,7 +54,7 @@ exports.acquire = acquire;
|
|
|
51
54
|
* @returns {void}
|
|
52
55
|
*/
|
|
53
56
|
const release = (dis) => {
|
|
54
|
-
/** @type {Deque} */
|
|
57
|
+
/** @type {Deque<TVoidFunction>} */
|
|
55
58
|
let dq;
|
|
56
59
|
if ((dq = dis.q).length) {
|
|
57
60
|
(dq.shift() || /* istanbul ignore next */ THROW)();
|
|
@@ -91,13 +94,9 @@ const releaseWithAbort = (dis) => {
|
|
|
91
94
|
let dq;
|
|
92
95
|
if ((dq = dis.q).length) {
|
|
93
96
|
const resolver = dq.shift();
|
|
97
|
+
resolver && resolver.resolve() || (
|
|
94
98
|
/* istanbul ignore next */
|
|
95
|
-
|
|
96
|
-
THROW();
|
|
97
|
-
}
|
|
98
|
-
else {
|
|
99
|
-
resolver.resolve();
|
|
100
|
-
}
|
|
99
|
+
THROW());
|
|
101
100
|
}
|
|
102
101
|
else {
|
|
103
102
|
if (dis.capacity < dis.limit) {
|
package/cjs/deque.d.ts
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ### Implementation restricted to FIFO
|
|
3
|
+
*
|
|
4
|
+
* This class uses a ring buffer for efficient FIFO operations.
|
|
5
|
+
* The maximum buffer size is **`1073741824`**.
|
|
6
|
+
*
|
|
7
|
+
* This class is based on https://github.com/petkaantonov/deque/blob/master/js/deque.js
|
|
8
|
+
* Released under the MIT License: https://github.com/petkaantonov/deque/blob/master/LICENSE
|
|
9
|
+
*
|
|
10
|
+
* @template {any} T
|
|
11
|
+
*/
|
|
12
|
+
export declare class Deque<T extends any> {
|
|
13
|
+
_c: number;
|
|
14
|
+
_l: number;
|
|
15
|
+
_f: number;
|
|
16
|
+
_a: T[];
|
|
17
|
+
length: number;
|
|
18
|
+
/**
|
|
19
|
+
* default capacity `16`
|
|
20
|
+
* @param {number=} ic initial capacity
|
|
21
|
+
*/
|
|
22
|
+
constructor(ic?: number);
|
|
23
|
+
/**
|
|
24
|
+
* @param {T} s subject
|
|
25
|
+
*/
|
|
26
|
+
push(s: T): void;
|
|
27
|
+
shift(): T | undefined;
|
|
28
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { IFlowableLock } from "./class";
|
|
2
|
+
/**
|
|
3
|
+
* @internal
|
|
4
|
+
* @date 2020/6/18
|
|
5
|
+
*/
|
|
6
|
+
type TFlowableLockWithTimeStamp = IFlowableLock & {
|
|
7
|
+
last?: number;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {import("./index").IFlowableLock & { last?: number }} TFlowableLockWithTimeStamp
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Flow Restriction
|
|
14
|
+
*/
|
|
15
|
+
export declare const restrictor: {
|
|
16
|
+
getLockByKey: (key: PropertyKey) => Promise<TFlowableLockWithTimeStamp>;
|
|
17
|
+
cleanup: (timeSpan: number, debug?: true) => Promise<number>;
|
|
18
|
+
multi: <T>(key: PropertyKey, restriction: number, pb: () => Promise<T>) => Promise<T>;
|
|
19
|
+
one: <T>(key: PropertyKey, pb: () => Promise<T>) => Promise<T>;
|
|
20
|
+
};
|
|
21
|
+
export {};
|
package/cjs/index.d.ts
CHANGED
|
@@ -100,9 +100,15 @@ export declare type TResolver = {
|
|
|
100
100
|
resolve: () => void;
|
|
101
101
|
reject: (reason: any) => void;
|
|
102
102
|
};
|
|
103
|
+
export declare interface IProcessAbortedError {
|
|
104
|
+
readonly message: "Process Aborted";
|
|
105
|
+
}
|
|
106
|
+
export type TAbortListener = (reason: IProcessAbortedError) => void;
|
|
103
107
|
export declare type TFlowableLockWithAbort = IFlowableLock & {
|
|
104
108
|
readonly q: Deque<TResolver>;
|
|
105
109
|
abort(): void;
|
|
110
|
+
onAbort(listener: TAbortListener): void;
|
|
111
|
+
offAbort(listener: TAbortListener): void;
|
|
106
112
|
};
|
|
107
113
|
|
|
108
114
|
/**
|
package/cjs/index.js
CHANGED
|
@@ -10,4 +10,4 @@ var deque_1 = require("./deque");
|
|
|
10
10
|
Object.defineProperty(exports, "Deque", { enumerable: true, get: function () { return deque_1.Deque; } });
|
|
11
11
|
var flow_restrictor_1 = require("./flow-restrictor");
|
|
12
12
|
Object.defineProperty(exports, "restrictor", { enumerable: true, get: function () { return flow_restrictor_1.restrictor; } });
|
|
13
|
-
exports.version = "v1.
|
|
13
|
+
exports.version = "v1.5.1";
|
package/cjs/object.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
3
|
+
Copyright (C) 2020 jeffy-g <hirotom1107@gmail.com>
|
|
4
|
+
Released under the MIT license
|
|
5
|
+
https://opensource.org/licenses/mit-license.php
|
|
6
|
+
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @file minimal implementation of semaphore (object implementation
|
|
10
|
+
* @author jeffy-g <hirotom1107@gmail.com>
|
|
11
|
+
* @version 1.0
|
|
12
|
+
*/
|
|
13
|
+
import * as core from "./core";
|
|
14
|
+
import { Deque } from "./deque";
|
|
15
|
+
export type * from "./core";
|
|
16
|
+
/**
|
|
17
|
+
* object implementation of `IFlowableLock`
|
|
18
|
+
*
|
|
19
|
+
* + constructs a semaphore object limited at `capacity`
|
|
20
|
+
*
|
|
21
|
+
* @param {number} capacity limitation of concurrent async by `capacity`
|
|
22
|
+
* @date 2020/2/7
|
|
23
|
+
* @version 1.0
|
|
24
|
+
*/
|
|
25
|
+
export declare const create: (capacity: number) => {
|
|
26
|
+
pending: number;
|
|
27
|
+
/**
|
|
28
|
+
*
|
|
29
|
+
* @param {boolean} [lazy]
|
|
30
|
+
* @returns {Promise<void>}
|
|
31
|
+
*/
|
|
32
|
+
acquire(lazy?: boolean): Promise<void>;
|
|
33
|
+
release(): void;
|
|
34
|
+
/**
|
|
35
|
+
* @template {any} T
|
|
36
|
+
* @param {() => Promise<T>} process
|
|
37
|
+
* @param {boolean} [lazy]
|
|
38
|
+
* @returns {Promise<T>}
|
|
39
|
+
*/
|
|
40
|
+
flow<T>(process: () => Promise<T>, lazy?: boolean): Promise<T>;
|
|
41
|
+
setRestriction(restriction: number): void;
|
|
42
|
+
limit: number;
|
|
43
|
+
capacity: number;
|
|
44
|
+
q: Deque<core.TVoidFunction>;
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* object implementation of `TFlowableLockWithAbort`
|
|
48
|
+
*
|
|
49
|
+
* + constructs a semaphore object limited at `capacity`
|
|
50
|
+
*
|
|
51
|
+
* @param {number} capacity limitation of concurrent async by `capacity`
|
|
52
|
+
* @date 2025/5/12
|
|
53
|
+
* @version 1.4
|
|
54
|
+
*/
|
|
55
|
+
export declare const createWithAbort: (capacity: number) => {
|
|
56
|
+
pending: number;
|
|
57
|
+
/**
|
|
58
|
+
* @returns {Promise<void>}
|
|
59
|
+
*/
|
|
60
|
+
acquire(): Promise<void>;
|
|
61
|
+
release(): void;
|
|
62
|
+
/**
|
|
63
|
+
* @template {any} T
|
|
64
|
+
* @param {() => Promise<T>} process
|
|
65
|
+
* @returns {Promise<T>}
|
|
66
|
+
*/
|
|
67
|
+
flow<T>(process: () => Promise<T>): Promise<T>;
|
|
68
|
+
/**
|
|
69
|
+
* @throws {AggregateError} description
|
|
70
|
+
*/
|
|
71
|
+
abort(): void;
|
|
72
|
+
/**
|
|
73
|
+
* Registers an event listener for the "abort" event.
|
|
74
|
+
* @param {TAbortListener} listener
|
|
75
|
+
*/
|
|
76
|
+
onAbort(listener: core.TAbortListener): void;
|
|
77
|
+
/**
|
|
78
|
+
* Removes an event listener for the "abort" event.
|
|
79
|
+
* @param {TAbortListener} listener
|
|
80
|
+
*/
|
|
81
|
+
offAbort(listener: core.TAbortListener): void;
|
|
82
|
+
setRestriction(restriction: number): void;
|
|
83
|
+
limit: number;
|
|
84
|
+
capacity: number;
|
|
85
|
+
q: Deque<core.TResolver>;
|
|
86
|
+
};
|
package/cjs/object.js
CHANGED
|
@@ -20,7 +20,17 @@ const r = core.release;
|
|
|
20
20
|
const aa = core.acquireWithAbort;
|
|
21
21
|
const ra = core.releaseWithAbort;
|
|
22
22
|
/**
|
|
23
|
-
* @
|
|
23
|
+
* @import {
|
|
24
|
+
* TResolver,
|
|
25
|
+
* TFlowableLock,
|
|
26
|
+
* IFlowableLock,
|
|
27
|
+
* TAbortListener,
|
|
28
|
+
* IProcessAbortedError,
|
|
29
|
+
* TFlowableLockWithAbort,
|
|
30
|
+
* } from "./index.mjs";
|
|
31
|
+
*/
|
|
32
|
+
/**
|
|
33
|
+
* @template {IFlowableLock & { q: Deque<unknown>}} T
|
|
24
34
|
* @param {number} capacity
|
|
25
35
|
* @returns
|
|
26
36
|
*/
|
|
@@ -47,9 +57,9 @@ const createBase = (capacity) => {
|
|
|
47
57
|
* @version 1.0
|
|
48
58
|
*/
|
|
49
59
|
const create = (capacity) => {
|
|
50
|
-
/** @type {
|
|
60
|
+
/** @type {TFlowableLock} */
|
|
51
61
|
const base = createBase(capacity);
|
|
52
|
-
return /** @satisfies {
|
|
62
|
+
return /** @satisfies {TFlowableLock} */ ({
|
|
53
63
|
...base,
|
|
54
64
|
get pending() {
|
|
55
65
|
return this.q.length;
|
|
@@ -93,9 +103,11 @@ exports.create = create;
|
|
|
93
103
|
* @version 1.4
|
|
94
104
|
*/
|
|
95
105
|
const createWithAbort = (capacity) => {
|
|
96
|
-
/** @type {
|
|
106
|
+
/** @type {TFlowableLockWithAbort} */
|
|
97
107
|
const base = createBase(capacity);
|
|
98
|
-
|
|
108
|
+
/** @type {TAbortListener[]} */
|
|
109
|
+
const abortListeners = [];
|
|
110
|
+
return /** @satisfies {TFlowableLockWithAbort} */ ({
|
|
99
111
|
...base,
|
|
100
112
|
get pending() {
|
|
101
113
|
return this.q.length;
|
|
@@ -115,27 +127,51 @@ const createWithAbort = (capacity) => {
|
|
|
115
127
|
* @returns {Promise<T>}
|
|
116
128
|
*/
|
|
117
129
|
async flow(process) {
|
|
118
|
-
|
|
130
|
+
/** @type {T | undefined} */
|
|
131
|
+
let result;
|
|
119
132
|
try {
|
|
120
|
-
|
|
133
|
+
await aa(this);
|
|
134
|
+
result = await process();
|
|
135
|
+
ra(this);
|
|
121
136
|
}
|
|
122
137
|
finally {
|
|
123
|
-
|
|
138
|
+
return /** @type {T} */ (result);
|
|
124
139
|
}
|
|
125
140
|
},
|
|
126
141
|
/**
|
|
127
142
|
* @throws {AggregateError} description
|
|
128
143
|
*/
|
|
129
144
|
abort() {
|
|
130
|
-
|
|
131
|
-
let resolver;
|
|
145
|
+
/** @type {IProcessAbortedError} */
|
|
132
146
|
const reason = {
|
|
133
147
|
message: "Process Aborted"
|
|
134
148
|
};
|
|
149
|
+
abortListeners.forEach(listener => listener(reason));
|
|
150
|
+
const dq = this.q;
|
|
151
|
+
let resolver;
|
|
135
152
|
while (resolver = dq.shift()) {
|
|
136
153
|
resolver.reject(reason);
|
|
137
154
|
}
|
|
138
155
|
this.capacity = this.limit;
|
|
156
|
+
},
|
|
157
|
+
/**
|
|
158
|
+
* Registers an event listener for the "abort" event.
|
|
159
|
+
* @param {TAbortListener} listener
|
|
160
|
+
*/
|
|
161
|
+
onAbort(listener) {
|
|
162
|
+
if (!abortListeners.includes(listener)) {
|
|
163
|
+
abortListeners.push(listener);
|
|
164
|
+
}
|
|
165
|
+
},
|
|
166
|
+
/**
|
|
167
|
+
* Removes an event listener for the "abort" event.
|
|
168
|
+
* @param {TAbortListener} listener
|
|
169
|
+
*/
|
|
170
|
+
offAbort(listener) {
|
|
171
|
+
const idx = abortListeners.findIndex(ls => listener === ls);
|
|
172
|
+
if (idx !== -1) {
|
|
173
|
+
/*return */ abortListeners.splice(idx, 1);
|
|
174
|
+
}
|
|
139
175
|
}
|
|
140
176
|
});
|
|
141
177
|
};
|
package/esm/core.mjs
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
2
|
+
* @import {
|
|
3
|
+
* TResolver,
|
|
4
|
+
* TVoidFunction,
|
|
5
|
+
* TFlowableLockWithAbort,
|
|
6
|
+
* ISimplifiedLock,
|
|
7
|
+
* TFlowableLock,
|
|
8
|
+
* IFlowableLock,
|
|
9
|
+
* Deque,
|
|
10
|
+
* } from "./index.mjs";
|
|
11
|
+
* @typedef {Deque<TResolver>} DequeWithAbort
|
|
9
12
|
*/
|
|
10
13
|
/**
|
|
11
14
|
* Throws an error indicating an inconsistent state in mini-semaphore.
|
|
@@ -47,7 +50,7 @@ export const acquire = (dis, lazy = true) => {
|
|
|
47
50
|
* @returns {void}
|
|
48
51
|
*/
|
|
49
52
|
export const release = (dis) => {
|
|
50
|
-
/** @type {Deque} */
|
|
53
|
+
/** @type {Deque<TVoidFunction>} */
|
|
51
54
|
let dq;
|
|
52
55
|
if ((dq = dis.q).length) {
|
|
53
56
|
(dq.shift() || /* istanbul ignore next */ THROW)();
|
|
@@ -85,13 +88,9 @@ export const releaseWithAbort = (dis) => {
|
|
|
85
88
|
let dq;
|
|
86
89
|
if ((dq = dis.q).length) {
|
|
87
90
|
const resolver = dq.shift();
|
|
91
|
+
resolver && resolver.resolve() || (
|
|
88
92
|
/* istanbul ignore next */
|
|
89
|
-
|
|
90
|
-
THROW();
|
|
91
|
-
}
|
|
92
|
-
else {
|
|
93
|
-
resolver.resolve();
|
|
94
|
-
}
|
|
93
|
+
THROW());
|
|
95
94
|
}
|
|
96
95
|
else {
|
|
97
96
|
if (dis.capacity < dis.limit) {
|
package/esm/index.d.mts
CHANGED
|
@@ -100,9 +100,15 @@ export declare type TResolver = {
|
|
|
100
100
|
resolve: () => void;
|
|
101
101
|
reject: (reason: any) => void;
|
|
102
102
|
};
|
|
103
|
+
export declare interface IProcessAbortedError {
|
|
104
|
+
readonly message: "Process Aborted";
|
|
105
|
+
}
|
|
106
|
+
export type TAbortListener = (reason: IProcessAbortedError) => void;
|
|
103
107
|
export declare type TFlowableLockWithAbort = IFlowableLock & {
|
|
104
108
|
readonly q: Deque<TResolver>;
|
|
105
109
|
abort(): void;
|
|
110
|
+
onAbort(listener: TAbortListener): void;
|
|
111
|
+
offAbort(listener: TAbortListener): void;
|
|
106
112
|
};
|
|
107
113
|
|
|
108
114
|
/**
|
package/esm/index.mjs
CHANGED
package/esm/object.mjs
CHANGED
|
@@ -17,7 +17,17 @@ const r = core.release;
|
|
|
17
17
|
const aa = core.acquireWithAbort;
|
|
18
18
|
const ra = core.releaseWithAbort;
|
|
19
19
|
/**
|
|
20
|
-
* @
|
|
20
|
+
* @import {
|
|
21
|
+
* TResolver,
|
|
22
|
+
* TFlowableLock,
|
|
23
|
+
* IFlowableLock,
|
|
24
|
+
* TAbortListener,
|
|
25
|
+
* IProcessAbortedError,
|
|
26
|
+
* TFlowableLockWithAbort,
|
|
27
|
+
* } from "./index.mjs";
|
|
28
|
+
*/
|
|
29
|
+
/**
|
|
30
|
+
* @template {IFlowableLock & { q: Deque<unknown>}} T
|
|
21
31
|
* @param {number} capacity
|
|
22
32
|
* @returns
|
|
23
33
|
*/
|
|
@@ -44,9 +54,9 @@ const createBase = (capacity) => {
|
|
|
44
54
|
* @version 1.0
|
|
45
55
|
*/
|
|
46
56
|
export const create = (capacity) => {
|
|
47
|
-
/** @type {
|
|
57
|
+
/** @type {TFlowableLock} */
|
|
48
58
|
const base = createBase(capacity);
|
|
49
|
-
return /** @satisfies {
|
|
59
|
+
return /** @satisfies {TFlowableLock} */ ({
|
|
50
60
|
...base,
|
|
51
61
|
get pending() {
|
|
52
62
|
return this.q.length;
|
|
@@ -89,9 +99,11 @@ export const create = (capacity) => {
|
|
|
89
99
|
* @version 1.4
|
|
90
100
|
*/
|
|
91
101
|
export const createWithAbort = (capacity) => {
|
|
92
|
-
/** @type {
|
|
102
|
+
/** @type {TFlowableLockWithAbort} */
|
|
93
103
|
const base = createBase(capacity);
|
|
94
|
-
|
|
104
|
+
/** @type {TAbortListener[]} */
|
|
105
|
+
const abortListeners = [];
|
|
106
|
+
return /** @satisfies {TFlowableLockWithAbort} */ ({
|
|
95
107
|
...base,
|
|
96
108
|
get pending() {
|
|
97
109
|
return this.q.length;
|
|
@@ -111,27 +123,51 @@ export const createWithAbort = (capacity) => {
|
|
|
111
123
|
* @returns {Promise<T>}
|
|
112
124
|
*/
|
|
113
125
|
async flow(process) {
|
|
114
|
-
|
|
126
|
+
/** @type {T | undefined} */
|
|
127
|
+
let result;
|
|
115
128
|
try {
|
|
116
|
-
|
|
129
|
+
await aa(this);
|
|
130
|
+
result = await process();
|
|
131
|
+
ra(this);
|
|
117
132
|
}
|
|
118
133
|
finally {
|
|
119
|
-
|
|
134
|
+
return /** @type {T} */ (result);
|
|
120
135
|
}
|
|
121
136
|
},
|
|
122
137
|
/**
|
|
123
138
|
* @throws {AggregateError} description
|
|
124
139
|
*/
|
|
125
140
|
abort() {
|
|
126
|
-
|
|
127
|
-
let resolver;
|
|
141
|
+
/** @type {IProcessAbortedError} */
|
|
128
142
|
const reason = {
|
|
129
143
|
message: "Process Aborted"
|
|
130
144
|
};
|
|
145
|
+
abortListeners.forEach(listener => listener(reason));
|
|
146
|
+
const dq = this.q;
|
|
147
|
+
let resolver;
|
|
131
148
|
while (resolver = dq.shift()) {
|
|
132
149
|
resolver.reject(reason);
|
|
133
150
|
}
|
|
134
151
|
this.capacity = this.limit;
|
|
152
|
+
},
|
|
153
|
+
/**
|
|
154
|
+
* Registers an event listener for the "abort" event.
|
|
155
|
+
* @param {TAbortListener} listener
|
|
156
|
+
*/
|
|
157
|
+
onAbort(listener) {
|
|
158
|
+
if (!abortListeners.includes(listener)) {
|
|
159
|
+
abortListeners.push(listener);
|
|
160
|
+
}
|
|
161
|
+
},
|
|
162
|
+
/**
|
|
163
|
+
* Removes an event listener for the "abort" event.
|
|
164
|
+
* @param {TAbortListener} listener
|
|
165
|
+
*/
|
|
166
|
+
offAbort(listener) {
|
|
167
|
+
const idx = abortListeners.findIndex(ls => listener === ls);
|
|
168
|
+
if (idx !== -1) {
|
|
169
|
+
/*return */ abortListeners.splice(idx, 1);
|
|
170
|
+
}
|
|
135
171
|
}
|
|
136
172
|
});
|
|
137
173
|
};
|
package/index.d.ts
CHANGED
|
@@ -100,9 +100,15 @@ export declare type TResolver = {
|
|
|
100
100
|
resolve: () => void;
|
|
101
101
|
reject: (reason: any) => void;
|
|
102
102
|
};
|
|
103
|
+
export declare interface IProcessAbortedError {
|
|
104
|
+
readonly message: "Process Aborted";
|
|
105
|
+
}
|
|
106
|
+
export type TAbortListener = (reason: IProcessAbortedError) => void;
|
|
103
107
|
export declare type TFlowableLockWithAbort = IFlowableLock & {
|
|
104
108
|
readonly q: Deque<TResolver>;
|
|
105
109
|
abort(): void;
|
|
110
|
+
onAbort(listener: TAbortListener): void;
|
|
111
|
+
offAbort(listener: TAbortListener): void;
|
|
106
112
|
};
|
|
107
113
|
|
|
108
114
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mini-semaphore",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.5.1",
|
|
4
4
|
"description": "A lightweight version of Semaphore",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "./cjs/index.js",
|
|
@@ -8,6 +8,43 @@
|
|
|
8
8
|
"unpkg": "./umd/index.js",
|
|
9
9
|
"sideEffects": false,
|
|
10
10
|
"types": "./index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./index.d.ts",
|
|
14
|
+
"import": "./esm/index.mjs",
|
|
15
|
+
"require": "./cjs/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./class": {
|
|
18
|
+
"import": "./esm/class.mjs",
|
|
19
|
+
"require": "./cjs/class.js"
|
|
20
|
+
},
|
|
21
|
+
"./object": {
|
|
22
|
+
"import": "./esm/object.mjs",
|
|
23
|
+
"require": "./cjs/object.js"
|
|
24
|
+
},
|
|
25
|
+
"./deque": {
|
|
26
|
+
"import": "./esm/deque.mjs",
|
|
27
|
+
"require": "./cjs/deque.js"
|
|
28
|
+
},
|
|
29
|
+
"./flow-restrictor": {
|
|
30
|
+
"import": "./esm/flow-restrictor.mjs",
|
|
31
|
+
"require": "./cjs/flow-restrictor.js"
|
|
32
|
+
},
|
|
33
|
+
"./umd": {
|
|
34
|
+
"import": "./umd/index.js",
|
|
35
|
+
"require": "./umd/index.js",
|
|
36
|
+
"types": "./umd/index.d.ts"
|
|
37
|
+
},
|
|
38
|
+
"./webpack": {
|
|
39
|
+
"import": "./webpack/index.js",
|
|
40
|
+
"require": "./webpack/index.js",
|
|
41
|
+
"types": "./webpack/index.d.ts"
|
|
42
|
+
},
|
|
43
|
+
"./webpack-esm": {
|
|
44
|
+
"import": "./webpack-esm/index.mjs",
|
|
45
|
+
"types": "./webpack-esm/index.d.mts"
|
|
46
|
+
}
|
|
47
|
+
},
|
|
11
48
|
"author": "jeffy-g",
|
|
12
49
|
"license": "MIT",
|
|
13
50
|
"bugs": {
|
package/umd/index.d.ts
CHANGED
|
@@ -100,9 +100,15 @@ export declare type TResolver = {
|
|
|
100
100
|
resolve: () => void;
|
|
101
101
|
reject: (reason: any) => void;
|
|
102
102
|
};
|
|
103
|
+
export declare interface IProcessAbortedError {
|
|
104
|
+
readonly message: "Process Aborted";
|
|
105
|
+
}
|
|
106
|
+
export type TAbortListener = (reason: IProcessAbortedError) => void;
|
|
103
107
|
export declare type TFlowableLockWithAbort = IFlowableLock & {
|
|
104
108
|
readonly q: Deque<TResolver>;
|
|
105
109
|
abort(): void;
|
|
110
|
+
onAbort(listener: TAbortListener): void;
|
|
111
|
+
offAbort(listener: TAbortListener): void;
|
|
106
112
|
};
|
|
107
113
|
|
|
108
114
|
/**
|
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,(
|
|
3
|
-
c(this)},async flow(e){await
|
|
4
|
-
|
|
5
|
-
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(),
|
|
6
|
-
|
|
7
|
-
;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(
|
|
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=[,,(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MiniSemaphore=void 0;const r=i(6),n=i(4),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)}}}},(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createWithAbort=t.create=void 0
|
|
3
|
+
;const r=i(6),n=i(4),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(){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)
|
|
4
|
+
;-1!==t&&i.splice(t,1)}}}},(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)}}},(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),
|
|
5
|
+
t.restrictor=void 0;const r=i(2);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),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(),
|
|
6
|
+
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)}}})()},(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})})
|
|
7
|
+
;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++}}],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(2);Object.defineProperty(e,"MiniSemaphore",{enumerable:!0,get:function(){return t.MiniSemaphore}});var n=i(3);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(4);Object.defineProperty(e,"Deque",{enumerable:!0,get:function(){return s.Deque}})
|
|
8
|
+
;var a=i(5);Object.defineProperty(e,"restrictor",{enumerable:!0,get:function(){return a.restrictor}}),e.version="v1.5.1"})(),r})());
|
package/webpack/index.d.ts
CHANGED
|
@@ -100,9 +100,15 @@ export declare type TResolver = {
|
|
|
100
100
|
resolve: () => void;
|
|
101
101
|
reject: (reason: any) => void;
|
|
102
102
|
};
|
|
103
|
+
export declare interface IProcessAbortedError {
|
|
104
|
+
readonly message: "Process Aborted";
|
|
105
|
+
}
|
|
106
|
+
export type TAbortListener = (reason: IProcessAbortedError) => void;
|
|
103
107
|
export declare type TFlowableLockWithAbort = IFlowableLock & {
|
|
104
108
|
readonly q: Deque<TResolver>;
|
|
105
109
|
abort(): void;
|
|
110
|
+
onAbort(listener: TAbortListener): void;
|
|
111
|
+
offAbort(listener: TAbortListener): void;
|
|
106
112
|
};
|
|
107
113
|
|
|
108
114
|
/**
|
package/webpack/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*! For license information please see index.js.LICENSE.txt */
|
|
2
|
-
(()=>{"use strict";var e=
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r=i(
|
|
5
|
-
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)}}})()},
|
|
6
|
-
|
|
7
|
-
e.version=e.restrictor=e.Deque=e.createWithAbort=e.create=e.MiniSemaphore=void 0;var t=i(
|
|
2
|
+
(()=>{"use strict";var e=[,,(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MiniSemaphore=void 0;const r=i(6),n=i(4),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)}}}},(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createWithAbort=t.create=void 0;const r=i(6),n=i(4),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)},
|
|
3
|
+
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;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)}}}},(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,
|
|
4
|
+
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)}}},(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r=i(2);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),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);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)}}})()},(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),
|
|
6
|
+
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})});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++}}],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(2);Object.defineProperty(e,"MiniSemaphore",{enumerable:!0,get:function(){return t.MiniSemaphore}});var n=i(3);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(4);Object.defineProperty(e,"Deque",{enumerable:!0,get:function(){return s.Deque}});var a=i(5);Object.defineProperty(e,"restrictor",{enumerable:!0,get:function(){return a.restrictor}}),e.version="v1.5.1"})(),module.exports=r})();
|
package/webpack-esm/index.d.mts
CHANGED
|
@@ -100,9 +100,15 @@ export declare type TResolver = {
|
|
|
100
100
|
resolve: () => void;
|
|
101
101
|
reject: (reason: any) => void;
|
|
102
102
|
};
|
|
103
|
+
export declare interface IProcessAbortedError {
|
|
104
|
+
readonly message: "Process Aborted";
|
|
105
|
+
}
|
|
106
|
+
export type TAbortListener = (reason: IProcessAbortedError) => void;
|
|
103
107
|
export declare type TFlowableLockWithAbort = IFlowableLock & {
|
|
104
108
|
readonly q: Deque<TResolver>;
|
|
105
109
|
abort(): void;
|
|
110
|
+
onAbort(listener: TAbortListener): void;
|
|
111
|
+
offAbort(listener: TAbortListener): void;
|
|
106
112
|
};
|
|
107
113
|
|
|
108
114
|
/**
|
package/webpack-esm/index.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
/*! For license information please see index.js.LICENSE.txt */
|
|
2
|
-
var e=
|
|
3
|
-
|
|
4
|
-
Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const r
|
|
5
|
-
r&&c.push(
|
|
6
|
-
|
|
7
|
-
;var
|
|
2
|
+
var e=[,,(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.MiniSemaphore=void 0;const i=r(6),s=r(4),n=i.acquire,a=i.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)}}}},(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createWithAbort=t.create=void 0;const i=r(6),s=r(4),n=i.acquire,a=i.release,c=i.acquireWithAbort,o=i.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)},
|
|
3
|
+
async flow(e,t){await n(this,t);try{return await e()}finally{a(this)}}});t.createWithAbort=e=>{const t=l(e),r=[];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"};r.forEach(t=>t(e));const t=this.q;let i;for(;i=t.shift();)i.reject(e);this.capacity=this.limit},onAbort(e){r.includes(e)||r.push(e)},offAbort(e){const t=r.findIndex(t=>e===t);-1!==t&&r.splice(t,1)}}}},(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Deque=void 0;const r=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=r(e||16),this._l=0,this._f=0,this._a=[],
|
|
4
|
+
this.length=0}push(e){const t=this._l;this._c<t+1&&i(this,r(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,r=this._a[t];return this._a[t]=void 0,this._f=t+1&this._c-1,this.length=this._l=e-1,r}};const i=(e,t)=>{const r=e._c;e._c=t;const i=e._f+e._l;if(i>r){const t=i&r-1;((e,t,r,i,s)=>{for(let n=0;n<s;++n)r[n+i]=e[n+t],e[n+t]=void 0})(e._a,0,e._a,r,t)}}},(e,t,r)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.restrictor=void 0;const i=r(2);t.restrictor=(()=>{const{MiniSemaphore:e}=i,t=new e(1);let r=Object.create(null);async function s(i,s,n){const a=await(async(i,s)=>{await t.acquire(!1);let n=r[i];if(n||(r[i]=n=new e(s)),n.limit!==s)throw t.release(),
|
|
5
|
+
new ReferenceError(`Cannot get object with different restriction: key: '${String(i)}', lock.limit: ${n.limit} <-> restriction: ${s},`);return t.release(),n})(i,s),c=a.flow(n);return a.last=Date.now(),c}return{getLockByKey:async e=>{await t.acquire(!1);const i=r[e];return t.release(),i},cleanup:async(e,i)=>{await t.acquire(!1);const s=r,n=Object.create(null),a=Object.keys(s);let c,o=0;!e&&(e=1),e*=1e3,i&&(c=[]);for(let t=0,r=a.length;t<r;){const r=a[t++],l=s[r];l.last&&Date.now()-l.last>=e?(o++,i&&c.push(r)):n[r]=l}return r=n,t.release(),i&&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)}}})()},(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),
|
|
6
|
+
t.releaseWithAbort=t.acquireWithAbort=t.release=t.acquire=void 0;const r=()=>{throw new Error("mini-semaphore: Detected an inconsistent state, possibly due to a logic error or unexpected behavior.")},i=(e,t)=>{e.capacity>0?(e.capacity--,t()):e.q.push(t)};t.acquire=(e,t=!0)=>new Promise(r=>{t?setTimeout(()=>i(e,r),4):i(e,r)});t.release=e=>{let t;(t=e.q).length?(t.shift()||r)():e.capacity++,e.capacity>e.limit&&(console.warn("inconsistent release!"),e.capacity=e.limit)};t.acquireWithAbort=e=>new Promise((t,r)=>{e.capacity>0?(e.capacity--,t()):e.q.push({resolve:t,reject:r})});t.releaseWithAbort=e=>{let t;if((t=e.q).length){const e=t.shift();e&&e.resolve()||r()}else e.capacity<e.limit&&e.capacity++}}],t={};function r(i){var s=t[i];if(void 0!==s)return s.exports;var n=t[i]={exports:{}}
|
|
7
|
+
;return e[i](n,n.exports,r),n.exports}var i={};(()=>{var e=i;Object.defineProperty(e,"__esModule",{value:!0}),e.version=e.restrictor=e.Deque=e.createWithAbort=e.create=e.MiniSemaphore=void 0;var t=r(2);Object.defineProperty(e,"MiniSemaphore",{enumerable:!0,get:function(){return t.MiniSemaphore}});var s=r(3);Object.defineProperty(e,"create",{enumerable:!0,get:function(){return s.create}}),Object.defineProperty(e,"createWithAbort",{enumerable:!0,get:function(){return s.createWithAbort}});var n=r(4);Object.defineProperty(e,"Deque",{enumerable:!0,get:function(){return n.Deque}});var a=r(5);Object.defineProperty(e,"restrictor",{enumerable:!0,get:function(){return a.restrictor}}),e.version="v1.5.1"})()
|
|
8
|
+
;const s=i.Deque,n=i.MiniSemaphore,a=i.__esModule,c=i.create,o=i.createWithAbort,l=i.restrictor,h=i.version;export{s as Deque,n as MiniSemaphore,a as __esModule,c as create,o as createWithAbort,l as restrictor,h as version,i as default};
|