@zukhruf/async 0.3.14 → 0.3.16

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
@@ -1,6 +1,6 @@
1
1
  # @zukhruf/async
2
2
 
3
- Helpers for code that waits for promises. The package has one function: `untilAborted`. `@zukhruf/mutex` and `@zukhruf/single-flight` use it.
3
+ Helpers for code that waits for promises: `untilAborted` cancels a wait, and `Latch` holds callers until something happened. `@zukhruf/mutex` and `@zukhruf/single-flight` use them.
4
4
 
5
5
  The words in these documents have one meaning each. See the glossary in [CONTEXT.md](./CONTEXT.md).
6
6
 
@@ -35,3 +35,21 @@ An `AbortSignal` is an `EventTarget`. A listener of the `abort` event can call `
35
35
  ## No listener stays on the signal
36
36
 
37
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.
38
+
39
+ ## Wait until something happened, with a latch
40
+
41
+ A latch starts closed. It opens once, with a value. A wait on a closed latch ends when the latch opens, and gets the value. A wait on an open latch ends at once, with the same value. A latch never closes again, and a second `open` changes nothing.
42
+
43
+ ```ts
44
+ import { Latch } from '@zukhruf/async';
45
+
46
+ const released = new Latch(); // Carries no value.
47
+ const done = new Latch<string>(); // Carries a string.
48
+
49
+ done.open('report');
50
+ const value = await done.wait(); // 'report'
51
+ ```
52
+
53
+ A latch never rejects. It keeps its value in a box, so it never adopts a promise, whatever its type. Thus a class can keep a latch in a field: the latch cannot fail before somebody awaits it. A latch whose type names a promise refuses one at compile time, because a wait would adopt the promise and could then reject. To share the outcome of work that can fail, give the latch a value that tells how the work ended, for example the `PromiseSettledResult` of `Promise.allSettled`. Each caller then throws the error for itself. See [ADR 0002](./docs/adr/0002-a-latch-carries-a-value-never-a-failure.md).
54
+
55
+ To stop a wait on a latch, cancel it: `untilAborted(latch.wait(), signal)`.
package/dist/index.d.ts CHANGED
@@ -1,2 +1,3 @@
1
+ export { Latch } from './latch.ts';
1
2
  export { untilAborted } from './until-aborted.ts';
2
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js CHANGED
@@ -1,2 +1,3 @@
1
+ export { Latch } from "./latch.js";
1
2
  export { untilAborted } from "./until-aborted.js";
2
3
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * A gate that starts closed and opens once, with a value. It never closes
3
+ * again and never rejects, so a wait that starts after it opened ends at once
4
+ * with the same value.
5
+ */
6
+ export declare class Latch<T = void> {
7
+ #private;
8
+ /**
9
+ * A later open changes nothing. A type that names a promise is refused: a
10
+ * wait would adopt the promise, and could then reject.
11
+ */
12
+ open(value: T extends PromiseLike<unknown> ? never : T): void;
13
+ wait(): Promise<T>;
14
+ }
15
+ //# sourceMappingURL=latch.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latch.d.ts","sourceRoot":"","sources":["../src/latch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,qBAAa,KAAK,CAAC,CAAC,GAAG,IAAI;;IAKzB;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,CAAC,SAAS,WAAW,CAAC,OAAO,CAAC,GAAG,KAAK,GAAG,CAAC,GAAG,IAAI;IAI7D,IAAI,IAAI,OAAO,CAAC,CAAC,CAAC;CAGnB"}
package/dist/latch.js ADDED
@@ -0,0 +1,21 @@
1
+ /**
2
+ * A gate that starts closed and opens once, with a value. It never closes
3
+ * again and never rejects, so a wait that starts after it opened ends at once
4
+ * with the same value.
5
+ */
6
+ export class Latch {
7
+ /** Holds the value in a box, so it never adopts a promise and never rejects, whatever `T` is. */
8
+ // eslint-disable-next-line zukhruf/no-promise-field -- A latch never rejects and is never replaced, so no hazard of the rule applies; it is the primitive the rule recommends.
9
+ #opened = Promise.withResolvers();
10
+ /**
11
+ * A later open changes nothing. A type that names a promise is refused: a
12
+ * wait would adopt the promise, and could then reject.
13
+ */
14
+ open(value) {
15
+ this.#opened.resolve({ value });
16
+ }
17
+ wait() {
18
+ return this.#opened.promise.then(({ value }) => value);
19
+ }
20
+ }
21
+ //# sourceMappingURL=latch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"latch.js","sourceRoot":"","sources":["../src/latch.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,OAAO,KAAK;IAChB,iGAAiG;IACjG,+KAA+K;IACtK,OAAO,GAAG,OAAO,CAAC,aAAa,EAAgB,CAAC;IAEzD;;;OAGG;IACH,IAAI,CAAC,KAAiD;QACpD,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;IAClC,CAAC;IAED,IAAI;QACF,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;IACzD,CAAC;CACF"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zukhruf/async",
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.",
3
+ "version": "0.3.16",
4
+ "description": "Helpers for code that waits for promises: cancel a wait when an AbortSignal aborts, and hold callers on a one-shot latch that never rejects.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
@@ -17,7 +17,8 @@
17
17
  "abortsignal",
18
18
  "abortable",
19
19
  "promise",
20
- "async"
20
+ "async",
21
+ "latch"
21
22
  ],
22
23
  "type": "module",
23
24
  "types": "./dist/index.d.ts",