@kikiutils/shared 13.2.0 → 13.4.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.
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * This class allows multiple consumers to `wait` for a specific key
6
6
  * and be resolved when `trigger` is called for that key, or automatically
7
- * resolved with `undefined` if a timeout occurs.
7
+ * resolved with `undefined` if a timeout occurs or an AbortSignal is triggered.
8
8
  *
9
9
  * Typical use cases include long-polling, request coordination,
10
10
  * or implementing event-driven primitives in applications or services.
@@ -17,17 +17,28 @@ declare class EventAwaiter<T> {
17
17
  * Triggers all pending promises waiting for the given key.
18
18
  * Each promise will be resolved with the provided value.
19
19
  *
20
- * @param {string} [key] - Identifier for the awaited event
20
+ * @param {string} key - Identifier for the awaited event
21
21
  * @param {T | undefined} value - The value to resolve the awaiting promises with.
22
22
  * May be `undefined` to indicate no result or a timeout-like behavior.
23
23
  */
24
24
  trigger(key: string, value: T | undefined): void;
25
+ /**
26
+ * Triggers and resolves all pending promises across all keys.
27
+ *
28
+ * This is typically used during shutdown or cleanup to ensure that
29
+ * no consumer is left waiting indefinitely.
30
+ *
31
+ * @param {T | undefined} [value] - Optional value to resolve all waiters with.
32
+ * Defaults to `undefined`, which usually indicates cancellation or shutdown.
33
+ */
34
+ triggerAll(value?: T | undefined): void;
25
35
  /**
26
36
  * Waits for an event associated with the given key.
27
37
  *
28
38
  * The returned promise will resolve when:
29
39
  * - `trigger(key)` is called, in which case it resolves with the provided value.
30
40
  * - The optional timeout is reached, in which case it resolves with `undefined`.
41
+ * - The optional `AbortSignal` is aborted, in which case it resolves with `undefined`.
31
42
  *
32
43
  * Behavior when multiple waiters exist for the same key:
33
44
  * - Default (no mode): multiple waiters are allowed, all will be resolved when triggered.
@@ -38,12 +49,13 @@ declare class EventAwaiter<T> {
38
49
  * @param {string} key - Identifier for the awaited event
39
50
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
40
51
  * If reached, the promise resolves with `undefined`.
41
- * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters.
52
+ * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters
53
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
42
54
  *
43
- * @returns {Promise<T | undefined>} A promise that resolves with the triggered value
44
- * or `undefined` if timeout occurs
55
+ * @returns {Promise<T | undefined>} A promise that resolves with the triggered value,
56
+ * or `undefined` if timeout or abort occurs
45
57
  */
46
- wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict'): Promise<T | undefined>;
58
+ wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict', signal?: AbortSignal): Promise<T | undefined>;
47
59
  /**
48
60
  * Waits for an event in strict mode.
49
61
  * Only one waiter is allowed per key. If another waiter already exists,
@@ -52,8 +64,9 @@ declare class EventAwaiter<T> {
52
64
  * @param {string} key - Identifier for the awaited event
53
65
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
54
66
  * If reached, the promise resolves with `undefined`.
67
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
55
68
  */
56
- waitExclusive(key: string, timeoutMs?: number): Promise<T | undefined>;
69
+ waitExclusive(key: string, timeoutMs?: number, signal?: AbortSignal): Promise<T | undefined>;
57
70
  /**
58
71
  * Waits for an event in override mode.
59
72
  * If another waiter already exists for the given key, it will be canceled
@@ -62,8 +75,9 @@ declare class EventAwaiter<T> {
62
75
  * @param {string} key - Identifier for the awaited event
63
76
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
64
77
  * If reached, the promise resolves with `undefined`.
78
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
65
79
  */
66
- waitLatest(key: string, timeoutMs?: number): Promise<T | undefined>;
80
+ waitLatest(key: string, timeoutMs?: number, signal?: AbortSignal): Promise<T | undefined>;
67
81
  }
68
82
  //#endregion
69
83
  export { EventAwaiter };
@@ -1 +1 @@
1
- {"version":3,"file":"event-awaiter.d.ts","names":[],"sources":["../src/event-awaiter.ts"],"sourcesContent":[],"mappings":";;AAYA;;;;;;;;;;;cAAa;;;;;;;;;;8BAWmB;;;;;;;;;;;;;;;;;;;;;;uEA6BsC,QAAA;;;;;;;;;;kDA0CrB,QAAA;;;;;;;;;;+CAaH,QAAA"}
1
+ {"version":3,"file":"event-awaiter.d.ts","names":[],"sources":["../src/event-awaiter.ts"],"sourcesContent":[],"mappings":";;AAYA;;;;;;;;;;;AAiIoE,cAjIvD,YAiIuD,CAAA,CAAA,CAAA,CAAA;UAAA;EAAA;;;;;;;;8BAtHpC;;;;;;;;;;qBAiBV;;;;;;;;;;;;;;;;;;;;;;;;+EA4B2D,cAAW,QAAA;;;;;;;;;;;0DA2DhC,cAAW,QAAA;;;;;;;;;;;uDAcd,cAAW,QAAA"}
@@ -4,7 +4,7 @@
4
4
  *
5
5
  * This class allows multiple consumers to `wait` for a specific key
6
6
  * and be resolved when `trigger` is called for that key, or automatically
7
- * resolved with `undefined` if a timeout occurs.
7
+ * resolved with `undefined` if a timeout occurs or an AbortSignal is triggered.
8
8
  *
9
9
  * Typical use cases include long-polling, request coordination,
10
10
  * or implementing event-driven primitives in applications or services.
@@ -17,7 +17,7 @@ var EventAwaiter = class {
17
17
  * Triggers all pending promises waiting for the given key.
18
18
  * Each promise will be resolved with the provided value.
19
19
  *
20
- * @param {string} [key] - Identifier for the awaited event
20
+ * @param {string} key - Identifier for the awaited event
21
21
  * @param {T | undefined} value - The value to resolve the awaiting promises with.
22
22
  * May be `undefined` to indicate no result or a timeout-like behavior.
23
23
  */
@@ -29,11 +29,25 @@ var EventAwaiter = class {
29
29
  }
30
30
  }
31
31
  /**
32
+ * Triggers and resolves all pending promises across all keys.
33
+ *
34
+ * This is typically used during shutdown or cleanup to ensure that
35
+ * no consumer is left waiting indefinitely.
36
+ *
37
+ * @param {T | undefined} [value] - Optional value to resolve all waiters with.
38
+ * Defaults to `undefined`, which usually indicates cancellation or shutdown.
39
+ */
40
+ triggerAll(value = void 0) {
41
+ for (const [_, resolvers] of this.#promiseResolvers.entries()) resolvers.forEach((resolve) => resolve(value));
42
+ this.#promiseResolvers.clear();
43
+ }
44
+ /**
32
45
  * Waits for an event associated with the given key.
33
46
  *
34
47
  * The returned promise will resolve when:
35
48
  * - `trigger(key)` is called, in which case it resolves with the provided value.
36
49
  * - The optional timeout is reached, in which case it resolves with `undefined`.
50
+ * - The optional `AbortSignal` is aborted, in which case it resolves with `undefined`.
37
51
  *
38
52
  * Behavior when multiple waiters exist for the same key:
39
53
  * - Default (no mode): multiple waiters are allowed, all will be resolved when triggered.
@@ -44,12 +58,13 @@ var EventAwaiter = class {
44
58
  * @param {string} key - Identifier for the awaited event
45
59
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
46
60
  * If reached, the promise resolves with `undefined`.
47
- * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters.
61
+ * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters
62
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
48
63
  *
49
- * @returns {Promise<T | undefined>} A promise that resolves with the triggered value
50
- * or `undefined` if timeout occurs
64
+ * @returns {Promise<T | undefined>} A promise that resolves with the triggered value,
65
+ * or `undefined` if timeout or abort occurs
51
66
  */
52
- wait(key, timeoutMs, mode) {
67
+ wait(key, timeoutMs, mode, signal) {
53
68
  return new Promise((resolve) => {
54
69
  const resolvers = this.#promiseResolvers.get(key) || [];
55
70
  if (resolvers.length) switch (mode) {
@@ -70,6 +85,15 @@ var EventAwaiter = class {
70
85
  else this.#promiseResolvers.delete(key);
71
86
  }
72
87
  }, timeoutMs);
88
+ if (signal) signal.addEventListener("abort", () => {
89
+ const resolvers$1 = this.#promiseResolvers.get(key);
90
+ if (resolvers$1?.includes(resolve)) {
91
+ resolve(void 0);
92
+ const newResolvers = resolvers$1.filter((r) => r !== resolve);
93
+ if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);
94
+ else this.#promiseResolvers.delete(key);
95
+ }
96
+ }, { once: true });
73
97
  });
74
98
  }
75
99
  /**
@@ -80,9 +104,10 @@ var EventAwaiter = class {
80
104
  * @param {string} key - Identifier for the awaited event
81
105
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
82
106
  * If reached, the promise resolves with `undefined`.
107
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
83
108
  */
84
- waitExclusive(key, timeoutMs) {
85
- return this.wait(key, timeoutMs, "strict");
109
+ waitExclusive(key, timeoutMs, signal) {
110
+ return this.wait(key, timeoutMs, "strict", signal);
86
111
  }
87
112
  /**
88
113
  * Waits for an event in override mode.
@@ -92,9 +117,10 @@ var EventAwaiter = class {
92
117
  * @param {string} key - Identifier for the awaited event
93
118
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
94
119
  * If reached, the promise resolves with `undefined`.
120
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
95
121
  */
96
- waitLatest(key, timeoutMs) {
97
- return this.wait(key, timeoutMs, "override");
122
+ waitLatest(key, timeoutMs, signal) {
123
+ return this.wait(key, timeoutMs, "override", signal);
98
124
  }
99
125
  };
100
126
 
@@ -1 +1 @@
1
- {"version":3,"file":"event-awaiter.js","names":["#promiseResolvers","resolvers"],"sources":["../src/event-awaiter.ts"],"sourcesContent":["/**\n * EventAwaiter provides a mechanism to wait for events (by key) asynchronously.\n *\n * This class allows multiple consumers to `wait` for a specific key\n * and be resolved when `trigger` is called for that key, or automatically\n * resolved with `undefined` if a timeout occurs.\n *\n * Typical use cases include long-polling, request coordination,\n * or implementing event-driven primitives in applications or services.\n *\n * @template T - The type of value that will be resolved when the event is triggered\n */\nexport class EventAwaiter<T> {\n #promiseResolvers = new Map<string, ((value: PromiseLike<T | undefined> | T | undefined) => void)[]>();\n\n /**\n * Triggers all pending promises waiting for the given key.\n * Each promise will be resolved with the provided value.\n *\n * @param {string} [key] - Identifier for the awaited event\n * @param {T | undefined} value - The value to resolve the awaiting promises with.\n * May be `undefined` to indicate no result or a timeout-like behavior.\n */\n trigger(key: string, value: T | undefined) {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers) {\n this.#promiseResolvers.delete(key);\n resolvers?.forEach((resolve) => resolve(value));\n }\n }\n\n /**\n * Waits for an event associated with the given key.\n *\n * The returned promise will resolve when:\n * - `trigger(key)` is called, in which case it resolves with the provided value.\n * - The optional timeout is reached, in which case it resolves with `undefined`.\n *\n * Behavior when multiple waiters exist for the same key:\n * - Default (no mode): multiple waiters are allowed, all will be resolved when triggered.\n * - `strict` mode: throws an error if a waiter already exists for the given key.\n * - `override` mode: cancels all existing waiters (resolving them with `undefined`)\n * and only keeps the latest one.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters.\n *\n * @returns {Promise<T | undefined>} A promise that resolves with the triggered value\n * or `undefined` if timeout occurs\n */\n wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict') {\n return new Promise<T | undefined>((resolve) => {\n const resolvers = this.#promiseResolvers.get(key) || [];\n if (resolvers.length) {\n switch (mode) {\n case 'override':\n resolvers.forEach((r) => r(undefined));\n resolvers.length = 0;\n break;\n case 'strict':\n throw new Error(`Duplicate wait detected for key: ${key}`);\n }\n }\n\n resolvers.push(resolve);\n this.#promiseResolvers.set(key, resolvers);\n if (timeoutMs) {\n setTimeout(\n () => {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers?.includes(resolve)) {\n resolve(undefined);\n const newResolvers = resolvers.filter((r) => r !== resolve);\n if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);\n else this.#promiseResolvers.delete(key);\n }\n },\n timeoutMs,\n );\n }\n });\n }\n\n /**\n * Waits for an event in strict mode.\n * Only one waiter is allowed per key. If another waiter already exists,\n * this method will throw an error.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n */\n waitExclusive(key: string, timeoutMs?: number) {\n return this.wait(key, timeoutMs, 'strict');\n }\n\n /**\n * Waits for an event in override mode.\n * If another waiter already exists for the given key, it will be canceled\n * (resolved with `undefined`) and replaced by the new waiter.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n */\n waitLatest(key: string, timeoutMs?: number) {\n return this.wait(key, timeoutMs, 'override');\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAa,eAAb,MAA6B;CACzB,oCAAoB,IAAI,KAA8E;;;;;;;;;CAUtG,QAAQ,KAAa,OAAsB;EACvC,MAAM,YAAY,MAAKA,iBAAkB,IAAI,IAAI;AACjD,MAAI,WAAW;AACX,SAAKA,iBAAkB,OAAO,IAAI;AAClC,cAAW,SAAS,YAAY,QAAQ,MAAM,CAAC;;;;;;;;;;;;;;;;;;;;;;;;CAyBvD,KAAK,KAAa,WAAoB,MAA8B;AAChE,SAAO,IAAI,SAAwB,YAAY;GAC3C,MAAM,YAAY,MAAKA,iBAAkB,IAAI,IAAI,IAAI,EAAE;AACvD,OAAI,UAAU,OACV,SAAQ,MAAR;IACI,KAAK;AACD,eAAU,SAAS,MAAM,EAAE,OAAU,CAAC;AACtC,eAAU,SAAS;AACnB;IACJ,KAAK,SACD,OAAM,IAAI,MAAM,oCAAoC,MAAM;;AAItE,aAAU,KAAK,QAAQ;AACvB,SAAKA,iBAAkB,IAAI,KAAK,UAAU;AAC1C,OAAI,UACA,kBACU;IACF,MAAMC,cAAY,MAAKD,iBAAkB,IAAI,IAAI;AACjD,QAAIC,aAAW,SAAS,QAAQ,EAAE;AAC9B,aAAQ,OAAU;KAClB,MAAM,eAAeA,YAAU,QAAQ,MAAM,MAAM,QAAQ;AAC3D,SAAI,aAAa,OAAQ,OAAKD,iBAAkB,IAAI,KAAK,aAAa;SACjE,OAAKA,iBAAkB,OAAO,IAAI;;MAG/C,UACH;IAEP;;;;;;;;;;;CAYN,cAAc,KAAa,WAAoB;AAC3C,SAAO,KAAK,KAAK,KAAK,WAAW,SAAS;;;;;;;;;;;CAY9C,WAAW,KAAa,WAAoB;AACxC,SAAO,KAAK,KAAK,KAAK,WAAW,WAAW"}
1
+ {"version":3,"file":"event-awaiter.js","names":["#promiseResolvers","resolvers"],"sources":["../src/event-awaiter.ts"],"sourcesContent":["/**\n * EventAwaiter provides a mechanism to wait for events (by key) asynchronously.\n *\n * This class allows multiple consumers to `wait` for a specific key\n * and be resolved when `trigger` is called for that key, or automatically\n * resolved with `undefined` if a timeout occurs or an AbortSignal is triggered.\n *\n * Typical use cases include long-polling, request coordination,\n * or implementing event-driven primitives in applications or services.\n *\n * @template T - The type of value that will be resolved when the event is triggered\n */\nexport class EventAwaiter<T> {\n #promiseResolvers = new Map<string, ((value: PromiseLike<T | undefined> | T | undefined) => void)[]>();\n\n /**\n * Triggers all pending promises waiting for the given key.\n * Each promise will be resolved with the provided value.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {T | undefined} value - The value to resolve the awaiting promises with.\n * May be `undefined` to indicate no result or a timeout-like behavior.\n */\n trigger(key: string, value: T | undefined) {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers) {\n this.#promiseResolvers.delete(key);\n resolvers?.forEach((resolve) => resolve(value));\n }\n }\n\n /**\n * Triggers and resolves all pending promises across all keys.\n *\n * This is typically used during shutdown or cleanup to ensure that\n * no consumer is left waiting indefinitely.\n *\n * @param {T | undefined} [value] - Optional value to resolve all waiters with.\n * Defaults to `undefined`, which usually indicates cancellation or shutdown.\n */\n triggerAll(value: T | undefined = undefined) {\n for (const [_, resolvers] of this.#promiseResolvers.entries()) resolvers.forEach((resolve) => resolve(value));\n this.#promiseResolvers.clear();\n }\n\n /**\n * Waits for an event associated with the given key.\n *\n * The returned promise will resolve when:\n * - `trigger(key)` is called, in which case it resolves with the provided value.\n * - The optional timeout is reached, in which case it resolves with `undefined`.\n * - The optional `AbortSignal` is aborted, in which case it resolves with `undefined`.\n *\n * Behavior when multiple waiters exist for the same key:\n * - Default (no mode): multiple waiters are allowed, all will be resolved when triggered.\n * - `strict` mode: throws an error if a waiter already exists for the given key.\n * - `override` mode: cancels all existing waiters (resolving them with `undefined`)\n * and only keeps the latest one.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n *\n * @returns {Promise<T | undefined>} A promise that resolves with the triggered value,\n * or `undefined` if timeout or abort occurs\n */\n wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict', signal?: AbortSignal) {\n return new Promise<T | undefined>((resolve) => {\n const resolvers = this.#promiseResolvers.get(key) || [];\n if (resolvers.length) {\n switch (mode) {\n case 'override':\n resolvers.forEach((r) => r(undefined));\n resolvers.length = 0;\n break;\n case 'strict':\n throw new Error(`Duplicate wait detected for key: ${key}`);\n }\n }\n\n resolvers.push(resolve);\n this.#promiseResolvers.set(key, resolvers);\n if (timeoutMs) {\n setTimeout(\n () => {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers?.includes(resolve)) {\n resolve(undefined);\n const newResolvers = resolvers.filter((r) => r !== resolve);\n if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);\n else this.#promiseResolvers.delete(key);\n }\n },\n timeoutMs,\n );\n }\n\n if (signal) {\n signal.addEventListener(\n 'abort',\n () => {\n const resolvers = this.#promiseResolvers.get(key);\n if (resolvers?.includes(resolve)) {\n resolve(undefined);\n const newResolvers = resolvers.filter((r) => r !== resolve);\n if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);\n else this.#promiseResolvers.delete(key);\n }\n },\n { once: true },\n );\n }\n });\n }\n\n /**\n * Waits for an event in strict mode.\n * Only one waiter is allowed per key. If another waiter already exists,\n * this method will throw an error.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n */\n waitExclusive(key: string, timeoutMs?: number, signal?: AbortSignal) {\n return this.wait(key, timeoutMs, 'strict', signal);\n }\n\n /**\n * Waits for an event in override mode.\n * If another waiter already exists for the given key, it will be canceled\n * (resolved with `undefined`) and replaced by the new waiter.\n *\n * @param {string} key - Identifier for the awaited event\n * @param {number} [timeoutMs] - Optional timeout (in milliseconds).\n * If reached, the promise resolves with `undefined`.\n * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`\n */\n waitLatest(key: string, timeoutMs?: number, signal?: AbortSignal) {\n return this.wait(key, timeoutMs, 'override', signal);\n }\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAa,eAAb,MAA6B;CACzB,oCAAoB,IAAI,KAA8E;;;;;;;;;CAUtG,QAAQ,KAAa,OAAsB;EACvC,MAAM,YAAY,MAAKA,iBAAkB,IAAI,IAAI;AACjD,MAAI,WAAW;AACX,SAAKA,iBAAkB,OAAO,IAAI;AAClC,cAAW,SAAS,YAAY,QAAQ,MAAM,CAAC;;;;;;;;;;;;CAavD,WAAW,QAAuB,QAAW;AACzC,OAAK,MAAM,CAAC,GAAG,cAAc,MAAKA,iBAAkB,SAAS,CAAE,WAAU,SAAS,YAAY,QAAQ,MAAM,CAAC;AAC7G,QAAKA,iBAAkB,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;CA0BlC,KAAK,KAAa,WAAoB,MAA8B,QAAsB;AACtF,SAAO,IAAI,SAAwB,YAAY;GAC3C,MAAM,YAAY,MAAKA,iBAAkB,IAAI,IAAI,IAAI,EAAE;AACvD,OAAI,UAAU,OACV,SAAQ,MAAR;IACI,KAAK;AACD,eAAU,SAAS,MAAM,EAAE,OAAU,CAAC;AACtC,eAAU,SAAS;AACnB;IACJ,KAAK,SACD,OAAM,IAAI,MAAM,oCAAoC,MAAM;;AAItE,aAAU,KAAK,QAAQ;AACvB,SAAKA,iBAAkB,IAAI,KAAK,UAAU;AAC1C,OAAI,UACA,kBACU;IACF,MAAMC,cAAY,MAAKD,iBAAkB,IAAI,IAAI;AACjD,QAAIC,aAAW,SAAS,QAAQ,EAAE;AAC9B,aAAQ,OAAU;KAClB,MAAM,eAAeA,YAAU,QAAQ,MAAM,MAAM,QAAQ;AAC3D,SAAI,aAAa,OAAQ,OAAKD,iBAAkB,IAAI,KAAK,aAAa;SACjE,OAAKA,iBAAkB,OAAO,IAAI;;MAG/C,UACH;AAGL,OAAI,OACA,QAAO,iBACH,eACM;IACF,MAAMC,cAAY,MAAKD,iBAAkB,IAAI,IAAI;AACjD,QAAIC,aAAW,SAAS,QAAQ,EAAE;AAC9B,aAAQ,OAAU;KAClB,MAAM,eAAeA,YAAU,QAAQ,MAAM,MAAM,QAAQ;AAC3D,SAAI,aAAa,OAAQ,OAAKD,iBAAkB,IAAI,KAAK,aAAa;SACjE,OAAKA,iBAAkB,OAAO,IAAI;;MAG/C,EAAE,MAAM,MAAM,CACjB;IAEP;;;;;;;;;;;;CAaN,cAAc,KAAa,WAAoB,QAAsB;AACjE,SAAO,KAAK,KAAK,KAAK,WAAW,UAAU,OAAO;;;;;;;;;;;;CAatD,WAAW,KAAa,WAAoB,QAAsB;AAC9D,SAAO,KAAK,KAAK,KAAK,WAAW,YAAY,OAAO"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@kikiutils/shared",
3
3
  "type": "module",
4
- "version": "13.2.0",
4
+ "version": "13.4.0",
5
5
  "description": "A lightweight and modular utility library for modern JavaScript and TypeScript — includes secure hashing, flexible logging, datetime tools, Vue/web helpers, storage abstraction, and more.",
6
6
  "author": "kiki-kanri",
7
7
  "license": "MIT",
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * This class allows multiple consumers to `wait` for a specific key
5
5
  * and be resolved when `trigger` is called for that key, or automatically
6
- * resolved with `undefined` if a timeout occurs.
6
+ * resolved with `undefined` if a timeout occurs or an AbortSignal is triggered.
7
7
  *
8
8
  * Typical use cases include long-polling, request coordination,
9
9
  * or implementing event-driven primitives in applications or services.
@@ -17,7 +17,7 @@ export class EventAwaiter<T> {
17
17
  * Triggers all pending promises waiting for the given key.
18
18
  * Each promise will be resolved with the provided value.
19
19
  *
20
- * @param {string} [key] - Identifier for the awaited event
20
+ * @param {string} key - Identifier for the awaited event
21
21
  * @param {T | undefined} value - The value to resolve the awaiting promises with.
22
22
  * May be `undefined` to indicate no result or a timeout-like behavior.
23
23
  */
@@ -29,12 +29,27 @@ export class EventAwaiter<T> {
29
29
  }
30
30
  }
31
31
 
32
+ /**
33
+ * Triggers and resolves all pending promises across all keys.
34
+ *
35
+ * This is typically used during shutdown or cleanup to ensure that
36
+ * no consumer is left waiting indefinitely.
37
+ *
38
+ * @param {T | undefined} [value] - Optional value to resolve all waiters with.
39
+ * Defaults to `undefined`, which usually indicates cancellation or shutdown.
40
+ */
41
+ triggerAll(value: T | undefined = undefined) {
42
+ for (const [_, resolvers] of this.#promiseResolvers.entries()) resolvers.forEach((resolve) => resolve(value));
43
+ this.#promiseResolvers.clear();
44
+ }
45
+
32
46
  /**
33
47
  * Waits for an event associated with the given key.
34
48
  *
35
49
  * The returned promise will resolve when:
36
50
  * - `trigger(key)` is called, in which case it resolves with the provided value.
37
51
  * - The optional timeout is reached, in which case it resolves with `undefined`.
52
+ * - The optional `AbortSignal` is aborted, in which case it resolves with `undefined`.
38
53
  *
39
54
  * Behavior when multiple waiters exist for the same key:
40
55
  * - Default (no mode): multiple waiters are allowed, all will be resolved when triggered.
@@ -45,12 +60,13 @@ export class EventAwaiter<T> {
45
60
  * @param {string} key - Identifier for the awaited event
46
61
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
47
62
  * If reached, the promise resolves with `undefined`.
48
- * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters.
63
+ * @param {'override' | 'strict'} [mode] - Optional behavior mode for handling multiple waiters
64
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
49
65
  *
50
- * @returns {Promise<T | undefined>} A promise that resolves with the triggered value
51
- * or `undefined` if timeout occurs
66
+ * @returns {Promise<T | undefined>} A promise that resolves with the triggered value,
67
+ * or `undefined` if timeout or abort occurs
52
68
  */
53
- wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict') {
69
+ wait(key: string, timeoutMs?: number, mode?: 'override' | 'strict', signal?: AbortSignal) {
54
70
  return new Promise<T | undefined>((resolve) => {
55
71
  const resolvers = this.#promiseResolvers.get(key) || [];
56
72
  if (resolvers.length) {
@@ -80,6 +96,22 @@ export class EventAwaiter<T> {
80
96
  timeoutMs,
81
97
  );
82
98
  }
99
+
100
+ if (signal) {
101
+ signal.addEventListener(
102
+ 'abort',
103
+ () => {
104
+ const resolvers = this.#promiseResolvers.get(key);
105
+ if (resolvers?.includes(resolve)) {
106
+ resolve(undefined);
107
+ const newResolvers = resolvers.filter((r) => r !== resolve);
108
+ if (newResolvers.length) this.#promiseResolvers.set(key, newResolvers);
109
+ else this.#promiseResolvers.delete(key);
110
+ }
111
+ },
112
+ { once: true },
113
+ );
114
+ }
83
115
  });
84
116
  }
85
117
 
@@ -91,9 +123,10 @@ export class EventAwaiter<T> {
91
123
  * @param {string} key - Identifier for the awaited event
92
124
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
93
125
  * If reached, the promise resolves with `undefined`.
126
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
94
127
  */
95
- waitExclusive(key: string, timeoutMs?: number) {
96
- return this.wait(key, timeoutMs, 'strict');
128
+ waitExclusive(key: string, timeoutMs?: number, signal?: AbortSignal) {
129
+ return this.wait(key, timeoutMs, 'strict', signal);
97
130
  }
98
131
 
99
132
  /**
@@ -104,8 +137,9 @@ export class EventAwaiter<T> {
104
137
  * @param {string} key - Identifier for the awaited event
105
138
  * @param {number} [timeoutMs] - Optional timeout (in milliseconds).
106
139
  * If reached, the promise resolves with `undefined`.
140
+ * @param {AbortSignal} [signal] - Optional AbortSignal. If aborted, the promise resolves with `undefined`
107
141
  */
108
- waitLatest(key: string, timeoutMs?: number) {
109
- return this.wait(key, timeoutMs, 'override');
142
+ waitLatest(key: string, timeoutMs?: number, signal?: AbortSignal) {
143
+ return this.wait(key, timeoutMs, 'override', signal);
110
144
  }
111
145
  }