rockbed 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +143 -0
  2. package/dist/assert/index.d.ts +6 -0
  3. package/dist/assert/index.js +27 -0
  4. package/dist/assert/index.js.map +1 -0
  5. package/dist/async/index.d.ts +105 -0
  6. package/dist/async/index.js +380 -0
  7. package/dist/async/index.js.map +1 -0
  8. package/dist/dispose/index.d.ts +47 -0
  9. package/dist/dispose/index.js +166 -0
  10. package/dist/dispose/index.js.map +1 -0
  11. package/dist/dispose-base-CAeXDpjg.d.ts +6 -0
  12. package/dist/error/index.d.ts +46 -0
  13. package/dist/error/index.js +150 -0
  14. package/dist/error/index.js.map +1 -0
  15. package/dist/error-base-BWuBlS2k.d.ts +28 -0
  16. package/dist/event/index.d.ts +57 -0
  17. package/dist/event/index.js +167 -0
  18. package/dist/event/index.js.map +1 -0
  19. package/dist/index.d.ts +10 -0
  20. package/dist/index.js +989 -0
  21. package/dist/index.js.map +1 -0
  22. package/dist/json/index.d.ts +4 -0
  23. package/dist/json/index.js +20 -0
  24. package/dist/json/index.js.map +1 -0
  25. package/dist/lock/index.d.ts +106 -0
  26. package/dist/lock/index.js +404 -0
  27. package/dist/lock/index.js.map +1 -0
  28. package/dist/response/index.d.ts +17 -0
  29. package/dist/response/index.js +19 -0
  30. package/dist/response/index.js.map +1 -0
  31. package/package.json +80 -0
  32. package/src/assert/assert.ts +24 -0
  33. package/src/assert/index.ts +2 -0
  34. package/src/async/barrier.ts +47 -0
  35. package/src/async/index.ts +8 -0
  36. package/src/async/promise.ts +316 -0
  37. package/src/async/wait.ts +7 -0
  38. package/src/dispose/disposable-store.ts +68 -0
  39. package/src/dispose/disposable-t.ts +85 -0
  40. package/src/dispose/disposable-utils.ts +13 -0
  41. package/src/dispose/dispose-base.ts +9 -0
  42. package/src/dispose/index.ts +8 -0
  43. package/src/dispose/logger.ts +41 -0
  44. package/src/error/error-base.ts +39 -0
  45. package/src/error/error-code.ts +48 -0
  46. package/src/error/error-const.ts +16 -0
  47. package/src/error/error-or.ts +2 -0
  48. package/src/error/error-t.ts +93 -0
  49. package/src/error/index.ts +5 -0
  50. package/src/event/emitter.ts +193 -0
  51. package/src/event/index.ts +10 -0
  52. package/src/index.ts +8 -0
  53. package/src/json/index.ts +1 -0
  54. package/src/json/json.ts +15 -0
  55. package/src/lock/README.md +11 -0
  56. package/src/lock/capability.ts +89 -0
  57. package/src/lock/index.ts +2 -0
  58. package/src/lock/semaphore.ts +21 -0
  59. package/src/lock/shared-mutex.ts +256 -0
  60. package/src/response/index.ts +1 -0
  61. package/src/response/response.ts +27 -0
  62. package/tsconfig.json +23 -0
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # rockbed
2
+
3
+ `rockbed` is a small TypeScript utility package extracted from `template-commander/src/bedrock`.
4
+ It keeps only the core primitives that are useful across projects.
5
+
6
+ The package is designed for subpath imports:
7
+
8
+ ```ts
9
+ import { ILvErrorOr, makeOkWith, makeError } from 'rockbed/error';
10
+ import { Emitter } from 'rockbed/event';
11
+ ```
12
+
13
+ ## Module Map
14
+
15
+ | Import path | Main exports | Use it for |
16
+ | --- | --- | --- |
17
+ | `rockbed/assert` | `lvAssert`, `lvAssertNotNil`, `lvAssertNever`, `lvAssertNotHere` | Runtime invariants and TypeScript narrowing. |
18
+ | `rockbed/async` | `wait`, `Barrier`, `makeBarrierByPromise`, `defer`, `makeCancelablePromise`, `parallelPromise`, `makePromiseWithTimeout`, `CancellationTokenSource` | Timers, promise coordination, cancellation-aware promise helpers. |
19
+ | `rockbed/dispose` | `IDisposable`, `Disposable`, `DisposableStore`, `MutableDisposable`, `SafeDisposable`, `makeSafeDisposable`, `disposeWithLog` | Ownership and cleanup of resources or subscriptions. |
20
+ | `rockbed/error` | `ILvErrorOr<T>`, `ILvErrorRef`, `makeOk`, `makeOkWith`, `makeError`, `makeErrorBy`, `lvErrorConst`, `isLvErrorRef`, `GenericError` | Typed result objects instead of throwing for expected failures. |
21
+ | `rockbed/event` | `Emitter`, `Event`, `listenOnce`, listener error handlers | Lightweight typed event emitters that return disposables. |
22
+ | `rockbed/json` | `safeJsonParse`, `safeJsonStringify` | JSON helpers that never throw. |
23
+ | `rockbed/lock` | `SharedMutex` | Async read/write locking with writer priority. |
24
+ | `rockbed/response` | `IResponse<T>`, `makeSuccessResponse`, `makeErrorResponse` | Simple `{ code, msg, data }` API response objects. |
25
+
26
+ ## Error Result Pattern
27
+
28
+ `ILvErrorOr<T>` is the central result type.
29
+
30
+ ```ts
31
+ import { ILvErrorOr, makeError, makeOkWith } from 'rockbed/error';
32
+
33
+ function parsePort(value: string): ILvErrorOr<number> {
34
+ const port = Number(value);
35
+ if (!Number.isInteger(port)) {
36
+ return makeError(400, 'port must be an integer');
37
+ }
38
+ return makeOkWith(port);
39
+ }
40
+
41
+ const result = parsePort('8080');
42
+ if (result.ok) {
43
+ console.log(result.value);
44
+ } else {
45
+ console.error(result.code, result.msg);
46
+ }
47
+ ```
48
+
49
+ Every result also has `pair()` for tuple-style control flow:
50
+
51
+ ```ts
52
+ const [err, value] = parsePort('8080').pair();
53
+ if (err) {
54
+ throw new Error(err.toString());
55
+ }
56
+ console.log(value);
57
+ ```
58
+
59
+ ## Event Pattern
60
+
61
+ `Emitter<TArgs>` produces an `Event<TArgs>`. Subscribing returns `IDisposable`.
62
+
63
+ ```ts
64
+ import { Emitter, listenOnce } from 'rockbed/event';
65
+
66
+ const emitter = new Emitter<[message: string]>();
67
+ const subscription = emitter.event((message) => console.log(message));
68
+
69
+ emitter.fire('ready');
70
+ subscription.dispose();
71
+
72
+ listenOnce(emitter.event)((message) => console.log('only once', message));
73
+ ```
74
+
75
+ ## Dispose Pattern
76
+
77
+ Use `DisposableStore` when one owner needs to clean up multiple resources.
78
+ Use `Disposable` as a base class when a class owns a store.
79
+
80
+ ```ts
81
+ import { Disposable, makeSafeDisposable } from 'rockbed/dispose';
82
+
83
+ class Session extends Disposable {
84
+ start() {
85
+ this._register(makeSafeDisposable(() => console.log('cleanup')));
86
+ }
87
+ }
88
+ ```
89
+
90
+ ## Async Pattern
91
+
92
+ ```ts
93
+ import { Barrier, makePromiseWithTimeout, wait } from 'rockbed/async';
94
+
95
+ await wait(100);
96
+
97
+ const barrier = new Barrier();
98
+ queueMicrotask(() => barrier.open());
99
+ await barrier.wait();
100
+
101
+ const result = await makePromiseWithTimeout(async (token) => {
102
+ if (token.isCancellationRequested) {
103
+ return 'cancelled';
104
+ }
105
+ return 'done';
106
+ }, 1000);
107
+ ```
108
+
109
+ ## Lock Pattern
110
+
111
+ `SharedMutex` supports exclusive writes and shared reads.
112
+
113
+ ```ts
114
+ import { SharedMutex } from 'rockbed/lock';
115
+
116
+ const mutex = new SharedMutex();
117
+
118
+ await mutex.lock();
119
+ try {
120
+ // write
121
+ } finally {
122
+ mutex.unlock();
123
+ }
124
+
125
+ await mutex.lockShared();
126
+ try {
127
+ // read
128
+ } finally {
129
+ mutex.unlockShared();
130
+ }
131
+ ```
132
+
133
+ ## Publishing
134
+
135
+ ```sh
136
+ npm install
137
+ npm run typecheck
138
+ npm run build
139
+ npm publish --registry=https://registry.npmjs.org
140
+ ```
141
+
142
+ The npm package includes `dist`, `src`, and this README. Keeping source files in the published
143
+ package makes the available primitives easier for humans and AI coding agents to inspect.
@@ -0,0 +1,6 @@
1
+ declare function lvAssert(expr: unknown, reason?: string): asserts expr;
2
+ declare function lvAssertNotHere(reason?: string): never;
3
+ declare function lvAssertNever(member: never, message?: string): never;
4
+ declare function lvAssertNotNil<T>(val: T, reason?: string): asserts val is NonNullable<T>;
5
+
6
+ export { lvAssert, lvAssertNever, lvAssertNotHere, lvAssertNotNil };
@@ -0,0 +1,27 @@
1
+ // src/assert/assert.ts
2
+ function abort(reason) {
3
+ throw new Error(`lvAssert(${reason})`);
4
+ }
5
+ function lvAssert(expr, reason) {
6
+ if (!expr) {
7
+ abort(reason ?? "#expr is false");
8
+ }
9
+ }
10
+ function lvAssertNotHere(reason) {
11
+ abort(reason ?? "unreachable code flow");
12
+ }
13
+ function lvAssertNever(member, message = "Illegal value:") {
14
+ abort(`${message}: ${member}`);
15
+ }
16
+ function lvAssertNotNil(val, reason) {
17
+ if (val === null || val === void 0) {
18
+ abort(reason ?? "#val is nil");
19
+ }
20
+ }
21
+ export {
22
+ lvAssert,
23
+ lvAssertNever,
24
+ lvAssertNotHere,
25
+ lvAssertNotNil
26
+ };
27
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/assert/assert.ts"],"sourcesContent":["function abort(reason: string): never {\n throw new Error(`lvAssert(${reason})`);\n}\n\nexport function lvAssert(expr: unknown, reason?: string): asserts expr {\n if (!expr) {\n abort(reason ?? '#expr is false');\n }\n}\n\nexport function lvAssertNotHere(reason?: string): never {\n abort(reason ?? 'unreachable code flow');\n}\n\nexport function lvAssertNever(member: never, message = 'Illegal value:'): never {\n // eslint-disable-next-line @typescript-eslint/restrict-template-expressions\n abort(`${message}: ${member}`);\n}\n\nexport function lvAssertNotNil<T>(val: T, reason?: string): asserts val is NonNullable<T> {\n if (val === null || val === undefined) {\n abort(reason ?? '#val is nil');\n }\n}\n"],"mappings":";AAAA,SAAS,MAAM,QAAuB;AACpC,QAAM,IAAI,MAAM,YAAY,MAAM,GAAG;AACvC;AAEO,SAAS,SAAS,MAAe,QAA+B;AACrE,MAAI,CAAC,MAAM;AACT,UAAM,UAAU,gBAAgB;AAAA,EAClC;AACF;AAEO,SAAS,gBAAgB,QAAwB;AACtD,QAAM,UAAU,uBAAuB;AACzC;AAEO,SAAS,cAAc,QAAe,UAAU,kBAAyB;AAE9E,QAAM,GAAG,OAAO,KAAK,MAAM,EAAE;AAC/B;AAEO,SAAS,eAAkB,KAAQ,QAAgD;AACxF,MAAI,QAAQ,QAAQ,QAAQ,QAAW;AACrC,UAAM,UAAU,aAAa;AAAA,EAC/B;AACF;","names":[]}
@@ -0,0 +1,105 @@
1
+ import { I as ILvErrorOr, a as ILvErrorRef } from '../error-base-BWuBlS2k.js';
2
+ import { I as IDisposable } from '../dispose-base-CAeXDpjg.js';
3
+
4
+ interface ICancellationToken {
5
+ readonly isCancellationRequested: boolean;
6
+ readonly reason?: string;
7
+ readonly onCancellationRequested: (listener: () => any, thisArgs?: any) => IDisposable;
8
+ }
9
+ declare class CancellationToken {
10
+ static None: Readonly<ICancellationToken>;
11
+ static Cancelled: Readonly<ICancellationToken>;
12
+ static Make(reason: string): ICancellationToken;
13
+ }
14
+ declare class CancellationTokenSource implements IDisposable {
15
+ private _token?;
16
+ private _abortController?;
17
+ get token(): ICancellationToken;
18
+ get signal(): AbortSignal;
19
+ cancel(reason?: string): void;
20
+ dispose(cancel?: boolean): void;
21
+ }
22
+ /**
23
+ * 一般来说Promise常用的场景有:
24
+ * 1. 单次异步调用(new Promise)
25
+ * 2. 批量promise调用(Promise.all)
26
+ * 3. promise竞速调用(Promise.race)
27
+ *
28
+ * 但是原生能力有如下的缺陷
29
+ * 1. 不支持取消某一次promise调用
30
+ * 2. 不支持错误语义,promise.catch的重视程度比try catch还低
31
+ * 3. 超时行为需要基于race封装
32
+ *
33
+ * 针对这三点,基建侧提供了高阶的promise能力
34
+ * 1. makeCancelablePromise 返回一个可取消的promise
35
+ * const promise = makeCancelablePromise(() => { ... });
36
+ * promise.then((res) => {
37
+ * // res是一个ILvErrorRef对象
38
+ * });
39
+ * // 可以直接取消promise
40
+ * promise.cancel();
41
+ *
42
+ * 2. parallelPromise 并发执行promise,会自动观测ILvErrorRef语义
43
+ * 当单个promise出现错误返回时,promise执行失败,尽可能调用所有cancelablePromise
44
+ * 当单个promise出现reject时,promise执行失败,尽可能调用所有cancelablePromise,并且将reject继续上抛
45
+ *
46
+ * 3. makePromiseWithTimeout 让promise支持超时,可以提供默认值
47
+ *
48
+ * ——————————————————
49
+ * Promise.allSettled和Promise.any在实际使用中场景较少,暂不提供错误语义包装
50
+ */
51
+ interface CancelablePromise<T> extends Promise<T> {
52
+ cancel: () => void;
53
+ }
54
+ /**
55
+ * 快速生成一个CancelablePromise对象
56
+ */
57
+ declare function makeCancelablePromise<T>(callback: (token: ICancellationToken) => Promise<T | ILvErrorOr<T>>): CancelablePromise<ILvErrorOr<T>>;
58
+ /**
59
+ * 并行执行promise,当某一个失败,本次调用失败
60
+ * 本质上和Promise.all差不多,相比较之下
61
+ * 1. 包装了错误语义判断
62
+ * 2. 当失败时,会尽可能尝试cancel其他promise
63
+ *
64
+ * 注意:某一个promise失败时,会尽可能尝试调用其他promise的cancel,但不保证一定有效
65
+ * (有可能promiseA已经成功,但是primiseB在之后失败了)
66
+ */
67
+ declare function parallelPromise(promiseList: Promise<any>[]): Promise<ILvErrorRef>;
68
+ /**
69
+ * 包装一个promise,提供超时能力
70
+ */
71
+ declare function makePromiseWithTimeout<T>(callback: (token: ICancellationToken) => Promise<T | ILvErrorOr<T>>, timeout: number, defaultValue?: T): Promise<ILvErrorOr<T>>;
72
+ interface Deferred<T> {
73
+ resolve: (value: T | PromiseLike<T>) => void;
74
+ reject: (reason: unknown) => void;
75
+ promise: Promise<T>;
76
+ }
77
+ declare function defer<T = void>(): Deferred<T>;
78
+
79
+ /**
80
+ * 等待一段时间
81
+ * @param ms 单位毫秒
82
+ */
83
+ declare function wait(ms: number): Promise<void>;
84
+
85
+ interface IBarrier {
86
+ isOpen: () => boolean;
87
+ open: () => void;
88
+ wait: () => Promise<boolean>;
89
+ }
90
+ /**
91
+ * A barrier that is initially closed and then becomes opened permanently after a certain period of
92
+ * time or when open is called explicitly
93
+ */
94
+ declare class Barrier {
95
+ private _isOpen;
96
+ private readonly _promise;
97
+ private _completePromise;
98
+ constructor();
99
+ isOpen(): boolean;
100
+ open(): void;
101
+ wait(): Promise<boolean>;
102
+ }
103
+ declare function makeBarrierByPromise(promise: Promise<any>, openWhenReject?: boolean): Barrier;
104
+
105
+ export { Barrier, type CancelablePromise, CancellationToken, CancellationTokenSource, type Deferred, type IBarrier, type ICancellationToken, defer, makeBarrierByPromise, makeCancelablePromise, makePromiseWithTimeout, parallelPromise, wait };
@@ -0,0 +1,380 @@
1
+ // src/error/error-t.ts
2
+ var lvErrorRefSymbol = /* @__PURE__ */ Symbol("lvErrorRef");
3
+ function makeOk() {
4
+ return {
5
+ ok: true,
6
+ value: null,
7
+ pair() {
8
+ return [null, null];
9
+ },
10
+ code: 0,
11
+ msg: "",
12
+ ...{ [lvErrorRefSymbol]: true }
13
+ // 跳过类型检测
14
+ };
15
+ }
16
+ function makeOkWith(value) {
17
+ return {
18
+ ok: true,
19
+ value,
20
+ pair() {
21
+ return [null, value];
22
+ },
23
+ code: 0,
24
+ msg: "",
25
+ ...{ [lvErrorRefSymbol]: true }
26
+ // 跳过类型检测
27
+ };
28
+ }
29
+ function printCause(cause) {
30
+ if (cause === void 0) {
31
+ return "";
32
+ } else if (cause instanceof Error) {
33
+ return `
34
+ caused by [jsError]${cause.name}-${cause.message}`;
35
+ } else {
36
+ return `
37
+ caused by [${cause.code}]${cause.msg}${cause.ok ? "" : printCause(cause.cause)}`;
38
+ }
39
+ }
40
+ function internalMakeError(code, msg, cause, errorInfo) {
41
+ const errorRef = {
42
+ ok: false,
43
+ code,
44
+ msg,
45
+ cause,
46
+ errorInfo,
47
+ toString() {
48
+ return `[${code}]${msg}.${cause ? printCause(cause) : ""}`;
49
+ },
50
+ pair() {
51
+ return [errorRef, null];
52
+ },
53
+ ...{ [lvErrorRefSymbol]: true }
54
+ // 跳过类型检测
55
+ };
56
+ return errorRef;
57
+ }
58
+ function makeError(code, msg, errorInfo) {
59
+ return internalMakeError(code, msg, void 0, errorInfo);
60
+ }
61
+ function makeErrorBy(code, msg, cause, errorInfo) {
62
+ return internalMakeError(code, msg, cause, errorInfo);
63
+ }
64
+ function isLvErrorRef(val) {
65
+ return typeof val === "object" && val !== null && lvErrorRefSymbol in val;
66
+ }
67
+
68
+ // src/error/error-const.ts
69
+ function lvErrorConst(code, msg) {
70
+ return (rewrite) => {
71
+ if (!rewrite) {
72
+ return makeError(code, msg);
73
+ }
74
+ if (typeof rewrite === "string") {
75
+ return makeError(code, rewrite);
76
+ }
77
+ return makeErrorBy(code, rewrite.message, rewrite);
78
+ };
79
+ }
80
+
81
+ // src/error/error-code.ts
82
+ var cancelledError = lvErrorConst(1 /* Cancelled */, "operation(s) cancelled.");
83
+ var timeoutError = lvErrorConst(2 /* TimedOut */, "operation(s) timed out.");
84
+ var permissionDeniedError = lvErrorConst(
85
+ 3 /* PermissionDenied */,
86
+ "permission denied."
87
+ );
88
+ var alreadyExistsError = lvErrorConst(4 /* AlreadyExists */, "already exists.");
89
+ var notSupportedError = lvErrorConst(
90
+ 5 /* NotSupported */,
91
+ "operation(s) not supported."
92
+ );
93
+ var resourceUnavailableError = lvErrorConst(
94
+ 6 /* ResourceUnavailable */,
95
+ "resource is unavailable."
96
+ );
97
+ var outOfRangeError = lvErrorConst(7 /* OutOfRange */, "out of range.");
98
+ var invalidArgumentError = lvErrorConst(
99
+ 8 /* InvalidArgument */,
100
+ "invalid arguments."
101
+ );
102
+ var networkFailedError = lvErrorConst(9 /* NetworkFailed */, "network failed.");
103
+ var interruptedError = lvErrorConst(10 /* Interrupted */, "interrupted.");
104
+ var resultNilError = lvErrorConst(11 /* ResultNil */, "result is nil.");
105
+
106
+ // src/dispose/dispose-base.ts
107
+ var EmptyDispose = Object.freeze({ dispose() {
108
+ } });
109
+
110
+ // src/dispose/disposable-t.ts
111
+ var SafeDisposable = class {
112
+ _value = null;
113
+ constructor(value) {
114
+ this._value = value;
115
+ }
116
+ isEmpty() {
117
+ return this._value === null;
118
+ }
119
+ dispose() {
120
+ if (!this._value) {
121
+ return;
122
+ }
123
+ this._value.dispose();
124
+ this._value = null;
125
+ }
126
+ };
127
+
128
+ // src/dispose/disposable-utils.ts
129
+ function makeSafeDisposable(fn) {
130
+ const disposable = new SafeDisposable({
131
+ dispose: fn
132
+ });
133
+ return disposable;
134
+ }
135
+
136
+ // src/async/promise.ts
137
+ var shortcutCancellationEvent = (callback, context) => {
138
+ const handle = setTimeout(callback.bind(context), 0);
139
+ return makeSafeDisposable(() => clearTimeout(handle));
140
+ };
141
+ var MutableToken = class {
142
+ _isCancelled = false;
143
+ _reason;
144
+ _listeners = /* @__PURE__ */ new Set();
145
+ get isCancellationRequested() {
146
+ return this._isCancelled;
147
+ }
148
+ get reason() {
149
+ return this._reason;
150
+ }
151
+ onCancellationRequested(listener, thisArgs) {
152
+ if (this._isCancelled) {
153
+ return shortcutCancellationEvent(listener, thisArgs);
154
+ }
155
+ const wrappedListener = listener.bind(thisArgs);
156
+ this._listeners.add(wrappedListener);
157
+ return makeSafeDisposable(() => {
158
+ this._listeners.delete(wrappedListener);
159
+ });
160
+ }
161
+ cancel(reason) {
162
+ if (this._isCancelled) {
163
+ return;
164
+ }
165
+ this._reason = reason;
166
+ this._isCancelled = true;
167
+ for (const listener of this._listeners) {
168
+ listener();
169
+ }
170
+ this._listeners.clear();
171
+ }
172
+ dispose() {
173
+ this._listeners.clear();
174
+ }
175
+ };
176
+ var CancellationToken = class {
177
+ static None = Object.freeze({
178
+ isCancellationRequested: false,
179
+ onCancellationRequested: () => EmptyDispose
180
+ });
181
+ static Cancelled = Object.freeze({
182
+ isCancellationRequested: true,
183
+ onCancellationRequested: shortcutCancellationEvent
184
+ });
185
+ static Make(reason) {
186
+ return Object.freeze({
187
+ isCancellationRequested: true,
188
+ onCancellationRequested: shortcutCancellationEvent,
189
+ reason
190
+ });
191
+ }
192
+ };
193
+ var CancellationTokenSource = class {
194
+ _token;
195
+ _abortController;
196
+ get token() {
197
+ if (!this._token) {
198
+ this._token = new MutableToken();
199
+ }
200
+ return this._token;
201
+ }
202
+ get signal() {
203
+ if (!this._abortController) {
204
+ this._abortController = new AbortController();
205
+ }
206
+ if (this._token?.isCancellationRequested) {
207
+ this._abortController.abort(this._token.reason);
208
+ }
209
+ return this._abortController.signal;
210
+ }
211
+ cancel(reason) {
212
+ if (!this._token) {
213
+ this._token = reason === void 0 ? CancellationToken.Cancelled : CancellationToken.Make(reason);
214
+ } else if (this._token instanceof MutableToken) {
215
+ this._token.cancel(reason);
216
+ }
217
+ this._abortController?.abort(reason);
218
+ }
219
+ dispose(cancel = false) {
220
+ if (cancel) {
221
+ this.cancel();
222
+ }
223
+ if (!this._token) {
224
+ this._token = CancellationToken.None;
225
+ } else if (this._token instanceof MutableToken) {
226
+ this._token.dispose();
227
+ }
228
+ }
229
+ };
230
+ function makeCancelablePromise(callback) {
231
+ const source = new CancellationTokenSource();
232
+ const thenable = callback(source.token);
233
+ const promise = new Promise((resolve, reject) => {
234
+ const subscription = source.token.onCancellationRequested(() => {
235
+ subscription.dispose();
236
+ source.dispose();
237
+ resolve(cancelledError());
238
+ });
239
+ Promise.resolve(thenable).then(
240
+ (value) => {
241
+ subscription.dispose();
242
+ source.dispose();
243
+ if (isLvErrorRef(value)) {
244
+ resolve(value);
245
+ } else {
246
+ resolve(makeOkWith(value));
247
+ }
248
+ },
249
+ (err) => {
250
+ subscription.dispose();
251
+ source.dispose();
252
+ reject(err);
253
+ }
254
+ );
255
+ });
256
+ return new class {
257
+ cancel() {
258
+ source.cancel();
259
+ }
260
+ then(resolve, reject) {
261
+ return promise.then(resolve, reject);
262
+ }
263
+ catch(reject) {
264
+ return this.then(void 0, reject);
265
+ }
266
+ finally(onfinally) {
267
+ return promise.finally(onfinally);
268
+ }
269
+ }();
270
+ }
271
+ function parallelPromise(promiseList) {
272
+ if (promiseList.length === 0) {
273
+ return Promise.resolve(makeOk());
274
+ }
275
+ let todo = promiseList.length;
276
+ const finish = () => {
277
+ todo = -1;
278
+ for (const promise of promiseList) {
279
+ promise.cancel?.();
280
+ }
281
+ };
282
+ return new Promise((resolve, reject) => {
283
+ for (const promise of promiseList) {
284
+ promise.then((res) => {
285
+ if (isLvErrorRef(res) && !res.ok) {
286
+ finish();
287
+ resolve(res);
288
+ return;
289
+ }
290
+ todo--;
291
+ if (todo === 0) {
292
+ resolve(makeOk());
293
+ }
294
+ }).catch((err) => {
295
+ finish();
296
+ reject(err);
297
+ });
298
+ }
299
+ });
300
+ }
301
+ function makePromiseWithTimeout(callback, timeout, defaultValue) {
302
+ const cancellable = makeCancelablePromise(callback);
303
+ const timer = setTimeout(() => {
304
+ cancellable.cancel();
305
+ }, timeout);
306
+ return cancellable.then((res) => {
307
+ clearTimeout(timer);
308
+ if (res.ok) {
309
+ return res;
310
+ }
311
+ if (res.code === 1 /* Cancelled */) {
312
+ if (defaultValue !== void 0) {
313
+ return makeOkWith(defaultValue);
314
+ }
315
+ return timeoutError();
316
+ } else {
317
+ return res;
318
+ }
319
+ });
320
+ }
321
+ function defer() {
322
+ let resolve;
323
+ let reject;
324
+ const promise = new Promise((_resolve, _reject) => {
325
+ resolve = _resolve;
326
+ reject = _reject;
327
+ });
328
+ return { resolve, reject, promise };
329
+ }
330
+
331
+ // src/async/wait.ts
332
+ function wait(ms) {
333
+ return new Promise((resolve) => setTimeout(resolve, ms));
334
+ }
335
+
336
+ // src/async/barrier.ts
337
+ var Barrier = class {
338
+ _isOpen;
339
+ _promise;
340
+ _completePromise;
341
+ constructor() {
342
+ this._isOpen = false;
343
+ this._promise = new Promise((c, e) => {
344
+ this._completePromise = c;
345
+ });
346
+ }
347
+ isOpen() {
348
+ return this._isOpen;
349
+ }
350
+ open() {
351
+ this._isOpen = true;
352
+ this._completePromise(true);
353
+ }
354
+ wait() {
355
+ return this._promise;
356
+ }
357
+ };
358
+ function makeBarrierByPromise(promise, openWhenReject = false) {
359
+ const barrier = new Barrier();
360
+ promise.then(() => barrier.open());
361
+ if (openWhenReject) {
362
+ promise.catch((err) => {
363
+ barrier.open();
364
+ throw err;
365
+ });
366
+ }
367
+ return barrier;
368
+ }
369
+ export {
370
+ Barrier,
371
+ CancellationToken,
372
+ CancellationTokenSource,
373
+ defer,
374
+ makeBarrierByPromise,
375
+ makeCancelablePromise,
376
+ makePromiseWithTimeout,
377
+ parallelPromise,
378
+ wait
379
+ };
380
+ //# sourceMappingURL=index.js.map