@zukhruf/async 0.0.0-stage → 0.3.14

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ezzabuzaid
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,37 @@
1
- # Temporary Holding Version
1
+ # @zukhruf/async
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Helpers for code that waits for promises. The package has one function: `untilAborted`. `@zukhruf/mutex` and `@zukhruf/single-flight` use it.
4
+
5
+ The words in these documents have one meaning each. See the glossary in [CONTEXT.md](./CONTEXT.md).
6
+
7
+ ## Cancel a wait
8
+
9
+ A caller waits for a promise. The caller wants to stop the wait when a signal aborts, for example after a time limit, or when the user stops the program. `untilAborted` gives a promise that settles in the same way as the promise of the caller. When the signal aborts first, it rejects with the reason of the signal.
10
+
11
+ ```ts
12
+ import { untilAborted } from '@zukhruf/async';
13
+
14
+ const report = buildReport(); // The work. It does not take a signal.
15
+ const value = await untilAborted(report, AbortSignal.timeout(5_000));
16
+ ```
17
+
18
+ - When `report` settles first, `value` is its value, or the call rejects with its error.
19
+ - When the 5 seconds end first, the call rejects with the reason of the signal: a `TimeoutError`.
20
+ - When the signal aborted before the call, the call rejects at once.
21
+ - When the signal is `undefined`, the call settles in the same way as `report`.
22
+
23
+ ## A cancel stops the wait, not the work
24
+
25
+ `untilAborted` cannot stop the work. In the example, `buildReport` continues after the cancel. Thus a caller that cancels must deal with the work that continues. For example, a caller of `MemoryStore` that cancels keeps its place in the line, and its place passes the key on when its turn comes.
26
+
27
+ To stop the work too, give the signal to the work, for example `fetch(url, { signal })`.
28
+
29
+ ## The wait ends also when another listener stops the event
30
+
31
+ An `AbortSignal` is an `EventTarget`. A listener of the `abort` event can call `event.stopImmediatePropagation()`. Then the listeners that were added after it do not run. A caller often shares its signal with other code. Thus a wait that listens with `addEventListener` can stay pending after the abort.
32
+
33
+ `untilAborted` listens through `events.addAbortListener` of Node.js. That listener runs also on a stopped event. See [ADR 0001](./docs/adr/0001-a-wait-listens-for-the-abort-through-addabortlistener.md).
34
+
35
+ ## No listener stays on the signal
36
+
37
+ When the promise settles, `untilAborted` removes its listener. Thus many waits on one signal that lives long, for example a signal that stops a server, do not add listeners to it.
@@ -0,0 +1,2 @@
1
+ export { untilAborted } from './until-aborted.ts';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { untilAborted } from "./until-aborted.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Settles like `promise`, or rejects with `signal.reason` first if `signal` aborts.
3
+ * Listens through `addAbortListener`, so a listener that stops the abort event
4
+ * cannot leave the wait pending.
5
+ */
6
+ export declare function untilAborted<T>(promise: Promise<T>, signal: AbortSignal | undefined): Promise<T>;
7
+ //# sourceMappingURL=until-aborted.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"until-aborted.d.ts","sourceRoot":"","sources":["../src/until-aborted.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAC5B,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,EACnB,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,CAAC,CAAC,CAgBZ"}
@@ -0,0 +1,22 @@
1
+ import { addAbortListener } from 'node:events';
2
+ /**
3
+ * Settles like `promise`, or rejects with `signal.reason` first if `signal` aborts.
4
+ * Listens through `addAbortListener`, so a listener that stops the abort event
5
+ * cannot leave the wait pending.
6
+ */
7
+ export function untilAborted(promise, signal) {
8
+ if (!signal)
9
+ return promise;
10
+ return new Promise((resolve, reject) => {
11
+ // Also calls the listener when the signal aborted before the call.
12
+ const listening = addAbortListener(signal, () => reject(signal.reason));
13
+ promise.then((value) => {
14
+ listening[Symbol.dispose]();
15
+ resolve(value);
16
+ }, (error) => {
17
+ listening[Symbol.dispose]();
18
+ reject(error);
19
+ });
20
+ });
21
+ }
22
+ //# sourceMappingURL=until-aborted.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"until-aborted.js","sourceRoot":"","sources":["../src/until-aborted.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,OAAmB,EACnB,MAA+B;IAE/B,IAAI,CAAC,MAAM;QAAE,OAAO,OAAO,CAAC;IAC5B,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACxC,mEAAmE;QACnE,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CACV,CAAC,KAAK,EAAE,EAAE;YACR,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,EACD,CAAC,KAAc,EAAE,EAAE;YACjB,SAAS,CAAC,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,MAAM,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,CACF,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,42 @@
1
1
  {
2
2
  "name": "@zukhruf/async",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.3.14",
4
+ "description": "Stop a wait for a promise when an AbortSignal aborts, also when another listener stops the abort event, and leave no listener on the signal.",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/JanuaryLabs/zukhruf",
9
+ "directory": "packages/async"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/JanuaryLabs/zukhruf/issues"
13
+ },
14
+ "homepage": "https://github.com/JanuaryLabs/zukhruf/tree/main/packages/async#readme",
15
+ "keywords": [
16
+ "abort",
17
+ "abortsignal",
18
+ "abortable",
19
+ "promise",
20
+ "async"
21
+ ],
22
+ "type": "module",
23
+ "types": "./dist/index.d.ts",
24
+ "exports": {
25
+ "./package.json": "./package.json",
26
+ ".": {
27
+ "@zukhruf/source": "./src/index.ts",
28
+ "types": "./dist/index.d.ts",
29
+ "import": "./dist/index.js",
30
+ "default": "./dist/index.js"
31
+ }
32
+ },
33
+ "files": [
34
+ "dist",
35
+ "!dist/spec/**",
36
+ "!**/*.tsbuildinfo",
37
+ "!**/*.test.*"
38
+ ],
39
+ "publishConfig": {
40
+ "access": "public"
41
+ }
42
+ }