evnty 5.0.0 → 5.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 (69) hide show
  1. package/README.md +28 -28
  2. package/build/async.cjs +101 -0
  3. package/build/async.cjs.map +1 -0
  4. package/build/async.d.ts +37 -0
  5. package/build/async.js +83 -0
  6. package/build/async.js.map +1 -0
  7. package/build/broadcast.cjs +205 -0
  8. package/build/broadcast.cjs.map +1 -0
  9. package/build/broadcast.d.ts +164 -0
  10. package/build/broadcast.js +184 -0
  11. package/build/broadcast.js.map +1 -0
  12. package/build/dispatch-result.cjs +154 -0
  13. package/build/dispatch-result.cjs.map +1 -0
  14. package/build/dispatch-result.d.ts +49 -0
  15. package/build/dispatch-result.js +127 -0
  16. package/build/dispatch-result.js.map +1 -0
  17. package/build/event.cjs +92 -127
  18. package/build/event.cjs.map +1 -1
  19. package/build/event.d.ts +92 -167
  20. package/build/event.js +90 -122
  21. package/build/event.js.map +1 -1
  22. package/build/index.cjs +3 -1
  23. package/build/index.cjs.map +1 -1
  24. package/build/index.d.ts +3 -1
  25. package/build/index.js +3 -1
  26. package/build/index.js.map +1 -1
  27. package/build/iterator.cjs +578 -91
  28. package/build/iterator.cjs.map +1 -1
  29. package/build/iterator.d.ts +178 -7
  30. package/build/iterator.js +579 -92
  31. package/build/iterator.js.map +1 -1
  32. package/build/listener-registry.cjs +114 -0
  33. package/build/listener-registry.cjs.map +1 -0
  34. package/build/listener-registry.d.ts +54 -0
  35. package/build/listener-registry.js +104 -0
  36. package/build/listener-registry.js.map +1 -0
  37. package/build/ring-buffer.cjs +171 -0
  38. package/build/ring-buffer.cjs.map +1 -0
  39. package/build/ring-buffer.d.ts +80 -0
  40. package/build/ring-buffer.js +161 -0
  41. package/build/ring-buffer.js.map +1 -0
  42. package/build/sequence.cjs +34 -35
  43. package/build/sequence.cjs.map +1 -1
  44. package/build/sequence.d.ts +38 -24
  45. package/build/sequence.js +34 -35
  46. package/build/sequence.js.map +1 -1
  47. package/build/signal.cjs +26 -35
  48. package/build/signal.cjs.map +1 -1
  49. package/build/signal.d.ts +36 -39
  50. package/build/signal.js +26 -35
  51. package/build/signal.js.map +1 -1
  52. package/build/types.cjs +0 -11
  53. package/build/types.cjs.map +1 -1
  54. package/build/types.d.ts +86 -9
  55. package/build/types.js +1 -5
  56. package/build/types.js.map +1 -1
  57. package/build/utils.cjs +202 -22
  58. package/build/utils.cjs.map +1 -1
  59. package/build/utils.d.ts +85 -26
  60. package/build/utils.js +181 -22
  61. package/build/utils.js.map +1 -1
  62. package/package.json +27 -25
  63. package/src/__tests__/example.js +19 -24
  64. package/src/index.ts +3 -1
  65. package/build/callable.cjs +0 -72
  66. package/build/callable.cjs.map +0 -1
  67. package/build/callable.d.ts +0 -34
  68. package/build/callable.js +0 -51
  69. package/build/callable.js.map +0 -1
@@ -0,0 +1,164 @@
1
+ import { Signal } from './signal.js';
2
+ import { Action, Fn, Emitter, MaybePromise, Promiseable } from './types.js';
3
+ /**
4
+ * A handle representing a consumer's position in a Broadcast.
5
+ * Returned by `Broadcast.join()` and used to consume values.
6
+ * Implements Disposable for automatic cleanup via `using` keyword.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const broadcast = new Broadcast<number>();
11
+ * using handle = broadcast.join();
12
+ * broadcast.emit(42);
13
+ * const value = broadcast.consume(handle); // 42
14
+ * ```
15
+ */
16
+ export declare class ConsumerHandle<T> implements Disposable {
17
+ #private;
18
+ constructor(broadcast: Broadcast<T>);
19
+ /**
20
+ * The current position of this consumer in the buffer.
21
+ */
22
+ get cursor(): number;
23
+ /**
24
+ * Leaves the broadcast, releasing this consumer's position.
25
+ */
26
+ [Symbol.dispose](): void;
27
+ }
28
+ /**
29
+ * @internal
30
+ */
31
+ export declare class BroadcastIterator<T> implements AsyncIterator<T, void, void> {
32
+ #private;
33
+ constructor(broadcast: Broadcast<T>, signal: Signal<T>, handle: ConsumerHandle<T>);
34
+ next(): Promise<IteratorResult<T, void>>;
35
+ return(): Promise<IteratorResult<T, void>>;
36
+ }
37
+ /**
38
+ * A multi-consumer FIFO queue where each consumer maintains its own read position.
39
+ * Values are buffered and each consumer can read them independently at their own pace.
40
+ * The buffer automatically compacts when all consumers have read past a position.
41
+ *
42
+ * Key characteristics:
43
+ * - Multiple consumers - each gets their own cursor position
44
+ * - Buffered delivery - values are stored until all consumers read them
45
+ * - Late joiners only see values emitted after joining
46
+ * - Automatic cleanup via FinalizationRegistry when handles are garbage collected
47
+ *
48
+ * Differs from:
49
+ * - Event: Broadcast buffers values, Event does not
50
+ * - Sequence: Broadcast supports multiple consumers, Sequence is single-consumer
51
+ * - Signal: Broadcast buffers values, Signal only notifies current waiters
52
+ *
53
+ * @template T - The type of values in the broadcast
54
+ *
55
+ * @example
56
+ * ```typescript
57
+ * const broadcast = new Broadcast<number>();
58
+ *
59
+ * const handle1 = broadcast.join();
60
+ * const handle2 = broadcast.join();
61
+ *
62
+ * broadcast.emit(1);
63
+ * broadcast.emit(2);
64
+ *
65
+ * broadcast.consume(handle1); // 1
66
+ * broadcast.consume(handle2); // 1
67
+ * broadcast.consume(handle1); // 2
68
+ * ```
69
+ */
70
+ export declare class Broadcast<T> implements Emitter<T, boolean>, Promiseable<T>, Promise<T>, Disposable, AsyncIterable<T> {
71
+ #private;
72
+ readonly [Symbol.toStringTag] = "Broadcast";
73
+ constructor();
74
+ /**
75
+ * Returns a bound emit function for use as a callback.
76
+ */
77
+ get sink(): Fn<[T], boolean>;
78
+ /**
79
+ * DOM EventListener interface compatibility.
80
+ */
81
+ handleEvent(event: T): void;
82
+ /**
83
+ * The number of active consumers.
84
+ */
85
+ get size(): number;
86
+ /**
87
+ * Emits a value to all consumers. The value is buffered for consumption.
88
+ *
89
+ * @param value - The value to emit.
90
+ * @returns `true` if the value was emitted.
91
+ */
92
+ emit(value: T): boolean;
93
+ /**
94
+ * Waits for the next emitted value without joining as a consumer.
95
+ * Does not buffer - only receives values emitted after calling.
96
+ *
97
+ * @returns A promise that resolves with the next emitted value.
98
+ */
99
+ receive(): Promise<T>;
100
+ then<OK = T, ERR = never>(onfulfilled?: Fn<[T], MaybePromise<OK>> | null, onrejected?: Fn<[unknown], MaybePromise<ERR>> | null): Promise<OK | ERR>;
101
+ catch<ERR = never>(onrejected?: Fn<[unknown], MaybePromise<ERR>> | null): Promise<T | ERR>;
102
+ finally(onfinally?: Action | null): Promise<T>;
103
+ /**
104
+ * Joins the broadcast as a consumer. Returns a handle used to consume values.
105
+ * The consumer starts at the current buffer position and will only see
106
+ * values emitted after joining.
107
+ *
108
+ * @example
109
+ * ```typescript
110
+ * const handle = broadcast.join();
111
+ * // Use handle with consume(), readable(), leave()
112
+ * ```
113
+ */
114
+ join(): ConsumerHandle<T>;
115
+ /**
116
+ * Gets the current cursor position for a consumer handle.
117
+ *
118
+ * @param handle - The consumer handle.
119
+ * @returns The cursor position.
120
+ * @throws If the handle is invalid (already left or never joined).
121
+ */
122
+ getCursor(handle: ConsumerHandle<T>): number;
123
+ /**
124
+ * Removes a consumer from the broadcast. The handle becomes invalid after this call.
125
+ * Idempotent - calling multiple times has no effect.
126
+ *
127
+ * @param handle - The consumer handle to remove.
128
+ */
129
+ leave(handle: ConsumerHandle<T>): void;
130
+ /**
131
+ * Consumes and returns the next value for a consumer.
132
+ * Advances the consumer's cursor position.
133
+ *
134
+ * @param handle - The consumer handle.
135
+ * @throws If no value is available or the handle is invalid.
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * if (broadcast.readable(handle)) {
140
+ * const value = broadcast.consume(handle);
141
+ * }
142
+ * ```
143
+ */
144
+ consume(handle: ConsumerHandle<T>): T;
145
+ /**
146
+ * Attempts to consume the next value for a consumer.
147
+ * Returns `{ done: true }` when no value is currently available.
148
+ *
149
+ * @param handle - The consumer handle.
150
+ * @returns The next value, or `{ done: true }` when nothing is available.
151
+ * @throws If the handle is invalid.
152
+ */
153
+ tryConsume(handle: ConsumerHandle<T>): IteratorResult<T, void>;
154
+ /**
155
+ * Checks if there are values available for a consumer to read.
156
+ *
157
+ * @param handle - The consumer handle.
158
+ * @returns `true` if there are unread values, `false` otherwise.
159
+ */
160
+ readable(handle: ConsumerHandle<T>): boolean;
161
+ [Symbol.asyncIterator](): AsyncIterator<T, void, void>;
162
+ dispose(): void;
163
+ [Symbol.dispose](): void;
164
+ }
@@ -0,0 +1,184 @@
1
+ import { RingBuffer } from "./ring-buffer.js";
2
+ import { Signal } from "./signal.js";
3
+ import { Disposer } from "./async.js";
4
+ import { min } from "./utils.js";
5
+ export class ConsumerHandle {
6
+ #broadcast;
7
+ constructor(broadcast){
8
+ this.#broadcast = broadcast;
9
+ }
10
+ get cursor() {
11
+ return this.#broadcast.getCursor(this);
12
+ }
13
+ [Symbol.dispose]() {
14
+ this.#broadcast.leave(this);
15
+ }
16
+ }
17
+ export class BroadcastIterator {
18
+ #broadcast;
19
+ #signal;
20
+ #handle;
21
+ constructor(broadcast, signal, handle){
22
+ this.#broadcast = broadcast;
23
+ this.#signal = signal;
24
+ this.#handle = handle;
25
+ }
26
+ async next() {
27
+ try {
28
+ while(true){
29
+ const result = this.#broadcast.tryConsume(this.#handle);
30
+ if (!result.done) {
31
+ return {
32
+ value: result.value,
33
+ done: false
34
+ };
35
+ }
36
+ await this.#signal.receive();
37
+ }
38
+ } catch {
39
+ return {
40
+ value: undefined,
41
+ done: true
42
+ };
43
+ }
44
+ }
45
+ async return() {
46
+ this.#broadcast.leave(this.#handle);
47
+ return {
48
+ value: undefined,
49
+ done: true
50
+ };
51
+ }
52
+ }
53
+ export class Broadcast {
54
+ #buffer = new RingBuffer();
55
+ #signal = new Signal();
56
+ #disposer;
57
+ #sink;
58
+ #nextId = 0;
59
+ #cursors = new Map();
60
+ #handles = new WeakMap();
61
+ #minCursor = 0;
62
+ #registry = new FinalizationRegistry((id)=>{
63
+ const cursor = this.#cursors.get(id);
64
+ this.#cursors.delete(id);
65
+ if (cursor === this.#minCursor) {
66
+ this.#minCursor = min(this.#cursors.values(), this.#buffer.right);
67
+ const shift = this.#minCursor - this.#buffer.left;
68
+ if (shift > 0) this.#buffer.shiftN(shift);
69
+ }
70
+ });
71
+ [Symbol.toStringTag] = 'Broadcast';
72
+ constructor(){
73
+ this.#disposer = new Disposer(this);
74
+ }
75
+ get sink() {
76
+ return this.#sink ??= this.emit.bind(this);
77
+ }
78
+ handleEvent(event) {
79
+ this.emit(event);
80
+ }
81
+ get size() {
82
+ return this.#cursors.size;
83
+ }
84
+ emit(value) {
85
+ if (this.#disposer.disposed) {
86
+ return false;
87
+ }
88
+ this.#buffer.push(value);
89
+ this.#signal.emit(value);
90
+ return true;
91
+ }
92
+ receive() {
93
+ return this.#signal.receive();
94
+ }
95
+ then(onfulfilled, onrejected) {
96
+ return this.receive().then(onfulfilled, onrejected);
97
+ }
98
+ catch(onrejected) {
99
+ return this.receive().catch(onrejected);
100
+ }
101
+ finally(onfinally) {
102
+ return this.receive().finally(onfinally);
103
+ }
104
+ join() {
105
+ const id = this.#nextId++;
106
+ const cursor = this.#buffer.right;
107
+ const handle = new ConsumerHandle(this);
108
+ this.#handles.set(handle, id);
109
+ this.#cursors.set(id, cursor);
110
+ if (this.#cursors.size === 1 || cursor < this.#minCursor) {
111
+ this.#minCursor = cursor;
112
+ }
113
+ this.#registry.register(handle, id, handle);
114
+ return handle;
115
+ }
116
+ getCursor(handle) {
117
+ const id = this.#handles.get(handle);
118
+ if (id === undefined) throw new Error('Invalid handle');
119
+ const cursor = this.#cursors.get(id);
120
+ if (cursor === undefined) throw new Error('Invalid handle');
121
+ return cursor;
122
+ }
123
+ leave(handle) {
124
+ const id = this.#handles.get(handle);
125
+ if (id === undefined) return;
126
+ const cursor = this.#cursors.get(id);
127
+ this.#handles.delete(handle);
128
+ this.#cursors.delete(id);
129
+ this.#registry.unregister(handle);
130
+ if (cursor === this.#minCursor) {
131
+ this.#minCursor = min(this.#cursors.values(), this.#buffer.right);
132
+ const shift = this.#minCursor - this.#buffer.left;
133
+ if (shift > 0) this.#buffer.shiftN(shift);
134
+ }
135
+ }
136
+ consume(handle) {
137
+ const result = this.tryConsume(handle);
138
+ if (result.done) {
139
+ throw new Error('No value available');
140
+ }
141
+ return result.value;
142
+ }
143
+ tryConsume(handle) {
144
+ const id = this.#handles.get(handle);
145
+ if (id === undefined) throw new Error('Invalid handle');
146
+ const cursor = this.#cursors.get(id);
147
+ if (cursor === undefined) throw new Error('Invalid handle');
148
+ if (cursor >= this.#buffer.right) {
149
+ return {
150
+ value: undefined,
151
+ done: true
152
+ };
153
+ }
154
+ const value = this.#buffer.peekAt(cursor);
155
+ this.#cursors.set(id, cursor + 1);
156
+ if (cursor === this.#minCursor) {
157
+ this.#minCursor = min(this.#cursors.values(), this.#buffer.right);
158
+ const shift = this.#minCursor - this.#buffer.left;
159
+ if (shift > 0) this.#buffer.shiftN(shift);
160
+ }
161
+ return {
162
+ value,
163
+ done: false
164
+ };
165
+ }
166
+ readable(handle) {
167
+ return this.getCursor(handle) < this.#buffer.right;
168
+ }
169
+ [Symbol.asyncIterator]() {
170
+ return new BroadcastIterator(this, this.#signal, this.join());
171
+ }
172
+ dispose() {
173
+ this[Symbol.dispose]();
174
+ }
175
+ [Symbol.dispose]() {
176
+ if (this.#disposer[Symbol.dispose]()) {
177
+ this.#signal[Symbol.dispose]();
178
+ this.#buffer.clear();
179
+ this.#cursors.clear();
180
+ }
181
+ }
182
+ }
183
+
184
+ //# sourceMappingURL=broadcast.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/broadcast.ts"],"sourcesContent":["import { RingBuffer } from './ring-buffer.js';\nimport { Signal } from './signal.js';\nimport { Disposer } from './async.js';\nimport { min } from './utils.js';\nimport { Action, Fn, Emitter, MaybePromise, Promiseable } from './types.js';\n\n/**\n * A handle representing a consumer's position in a Broadcast.\n * Returned by `Broadcast.join()` and used to consume values.\n * Implements Disposable for automatic cleanup via `using` keyword.\n *\n * @example\n * ```typescript\n * const broadcast = new Broadcast<number>();\n * using handle = broadcast.join();\n * broadcast.emit(42);\n * const value = broadcast.consume(handle); // 42\n * ```\n */\nexport class ConsumerHandle<T> implements Disposable {\n #broadcast: Broadcast<T>;\n\n constructor(broadcast: Broadcast<T>) {\n this.#broadcast = broadcast;\n }\n\n /**\n * The current position of this consumer in the buffer.\n */\n get cursor(): number {\n return this.#broadcast.getCursor(this);\n }\n\n /**\n * Leaves the broadcast, releasing this consumer's position.\n */\n [Symbol.dispose](): void {\n this.#broadcast.leave(this);\n }\n}\n\n/**\n * @internal\n */\nexport class BroadcastIterator<T> implements AsyncIterator<T, void, void> {\n #broadcast: Broadcast<T>;\n #signal: Signal<T>;\n #handle: ConsumerHandle<T>;\n\n constructor(broadcast: Broadcast<T>, signal: Signal<T>, handle: ConsumerHandle<T>) {\n this.#broadcast = broadcast;\n this.#signal = signal;\n this.#handle = handle;\n }\n\n async next(): Promise<IteratorResult<T, void>> {\n try {\n while (true) {\n const result = this.#broadcast.tryConsume(this.#handle);\n if (!result.done) {\n return { value: result.value, done: false };\n }\n await this.#signal.receive();\n }\n } catch {\n return { value: undefined, done: true };\n }\n }\n\n async return(): Promise<IteratorResult<T, void>> {\n this.#broadcast.leave(this.#handle);\n return { value: undefined, done: true };\n }\n}\n\n/**\n * A multi-consumer FIFO queue where each consumer maintains its own read position.\n * Values are buffered and each consumer can read them independently at their own pace.\n * The buffer automatically compacts when all consumers have read past a position.\n *\n * Key characteristics:\n * - Multiple consumers - each gets their own cursor position\n * - Buffered delivery - values are stored until all consumers read them\n * - Late joiners only see values emitted after joining\n * - Automatic cleanup via FinalizationRegistry when handles are garbage collected\n *\n * Differs from:\n * - Event: Broadcast buffers values, Event does not\n * - Sequence: Broadcast supports multiple consumers, Sequence is single-consumer\n * - Signal: Broadcast buffers values, Signal only notifies current waiters\n *\n * @template T - The type of values in the broadcast\n *\n * @example\n * ```typescript\n * const broadcast = new Broadcast<number>();\n *\n * const handle1 = broadcast.join();\n * const handle2 = broadcast.join();\n *\n * broadcast.emit(1);\n * broadcast.emit(2);\n *\n * broadcast.consume(handle1); // 1\n * broadcast.consume(handle2); // 1\n * broadcast.consume(handle1); // 2\n * ```\n */\nexport class Broadcast<T> implements Emitter<T, boolean>, Promiseable<T>, Promise<T>, Disposable, AsyncIterable<T> {\n #buffer = new RingBuffer<T>();\n #signal = new Signal<T>();\n #disposer: Disposer;\n #sink?: Fn<[T], boolean>;\n #nextId = 0;\n #cursors = new Map<number, number>();\n #handles = new WeakMap<ConsumerHandle<T>, number>();\n #minCursor = 0;\n\n // Stryker disable all: FinalizationRegistry callback only testable via GC, excluded from mutation testing\n #registry = new FinalizationRegistry<number>((id) => {\n const cursor = this.#cursors.get(id)!;\n this.#cursors.delete(id);\n\n if (cursor === this.#minCursor) {\n this.#minCursor = min(this.#cursors.values(), this.#buffer.right);\n const shift = this.#minCursor - this.#buffer.left;\n if (shift > 0) this.#buffer.shiftN(shift);\n }\n });\n // Stryker restore all\n\n readonly [Symbol.toStringTag] = 'Broadcast';\n\n constructor() {\n this.#disposer = new Disposer(this);\n }\n\n /**\n * Returns a bound emit function for use as a callback.\n */\n get sink(): Fn<[T], boolean> {\n return (this.#sink ??= this.emit.bind(this));\n }\n\n /**\n * DOM EventListener interface compatibility.\n */\n handleEvent(event: T): void {\n this.emit(event);\n }\n\n /**\n * The number of active consumers.\n */\n get size(): number {\n return this.#cursors.size;\n }\n\n /**\n * Emits a value to all consumers. The value is buffered for consumption.\n *\n * @param value - The value to emit.\n * @returns `true` if the value was emitted.\n */\n emit(value: T): boolean {\n if (this.#disposer.disposed) {\n return false;\n }\n this.#buffer.push(value);\n this.#signal.emit(value);\n return true;\n }\n\n /**\n * Waits for the next emitted value without joining as a consumer.\n * Does not buffer - only receives values emitted after calling.\n *\n * @returns A promise that resolves with the next emitted value.\n */\n receive(): Promise<T> {\n return this.#signal.receive();\n }\n\n then<OK = T, ERR = never>(onfulfilled?: Fn<[T], MaybePromise<OK>> | null, onrejected?: Fn<[unknown], MaybePromise<ERR>> | null): Promise<OK | ERR> {\n return this.receive().then(onfulfilled, onrejected);\n }\n\n catch<ERR = never>(onrejected?: Fn<[unknown], MaybePromise<ERR>> | null): Promise<T | ERR> {\n return this.receive().catch(onrejected);\n }\n\n finally(onfinally?: Action | null): Promise<T> {\n return this.receive().finally(onfinally);\n }\n\n /**\n * Joins the broadcast as a consumer. Returns a handle used to consume values.\n * The consumer starts at the current buffer position and will only see\n * values emitted after joining.\n *\n * @example\n * ```typescript\n * const handle = broadcast.join();\n * // Use handle with consume(), readable(), leave()\n * ```\n */\n join(): ConsumerHandle<T> {\n // Stryker disable next-line UpdateOperator: IDs only need uniqueness, direction is irrelevant\n const id = this.#nextId++;\n const cursor = this.#buffer.right;\n const handle = new ConsumerHandle<T>(this);\n\n this.#handles.set(handle, id);\n this.#cursors.set(id, cursor);\n\n // Stryker disable all: minCursor is an optimization hint; tryConsume recalculates on use\n if (this.#cursors.size === 1 || cursor < this.#minCursor) {\n this.#minCursor = cursor;\n }\n // Stryker restore all\n\n this.#registry.register(handle, id, handle);\n return handle;\n }\n\n /**\n * Gets the current cursor position for a consumer handle.\n *\n * @param handle - The consumer handle.\n * @returns The cursor position.\n * @throws If the handle is invalid (already left or never joined).\n */\n getCursor(handle: ConsumerHandle<T>): number {\n const id = this.#handles.get(handle);\n // Stryker disable next-line ConditionalExpression: second cursor check catches invalid handles\n if (id === undefined) throw new Error('Invalid handle');\n const cursor = this.#cursors.get(id);\n if (cursor === undefined) throw new Error('Invalid handle');\n return cursor;\n }\n\n /**\n * Removes a consumer from the broadcast. The handle becomes invalid after this call.\n * Idempotent - calling multiple times has no effect.\n *\n * @param handle - The consumer handle to remove.\n */\n leave(handle: ConsumerHandle<T>): void {\n const id = this.#handles.get(handle);\n // Stryker disable next-line ConditionalExpression,EqualityOperator: subsequent ops are safe with undefined id\n if (id === undefined) return;\n\n const cursor = this.#cursors.get(id)!;\n this.#handles.delete(handle);\n this.#cursors.delete(id);\n this.#registry.unregister(handle);\n\n // Stryker disable all: compaction condition is optimization; buffer reads are correct regardless\n if (cursor === this.#minCursor) {\n this.#minCursor = min(this.#cursors.values(), this.#buffer.right);\n const shift = this.#minCursor - this.#buffer.left;\n if (shift > 0) this.#buffer.shiftN(shift);\n }\n // Stryker restore all\n }\n\n /**\n * Consumes and returns the next value for a consumer.\n * Advances the consumer's cursor position.\n *\n * @param handle - The consumer handle.\n * @throws If no value is available or the handle is invalid.\n *\n * @example\n * ```typescript\n * if (broadcast.readable(handle)) {\n * const value = broadcast.consume(handle);\n * }\n * ```\n */\n consume(handle: ConsumerHandle<T>): T {\n const result = this.tryConsume(handle);\n if (result.done) {\n throw new Error('No value available');\n }\n return result.value;\n }\n\n /**\n * Attempts to consume the next value for a consumer.\n * Returns `{ done: true }` when no value is currently available.\n *\n * @param handle - The consumer handle.\n * @returns The next value, or `{ done: true }` when nothing is available.\n * @throws If the handle is invalid.\n */\n tryConsume(handle: ConsumerHandle<T>): IteratorResult<T, void> {\n const id = this.#handles.get(handle);\n // Stryker disable next-line ConditionalExpression: second cursor check catches invalid handles\n if (id === undefined) throw new Error('Invalid handle');\n\n const cursor = this.#cursors.get(id);\n if (cursor === undefined) throw new Error('Invalid handle');\n if (cursor >= this.#buffer.right) {\n return { value: undefined, done: true };\n }\n\n const value = this.#buffer.peekAt(cursor)!;\n this.#cursors.set(id, cursor + 1);\n\n // Stryker disable all: compaction condition is optimization; buffer reads are correct regardless\n if (cursor === this.#minCursor) {\n this.#minCursor = min(this.#cursors.values(), this.#buffer.right);\n const shift = this.#minCursor - this.#buffer.left;\n if (shift > 0) this.#buffer.shiftN(shift);\n }\n // Stryker restore all\n\n return { value, done: false };\n }\n\n /**\n * Checks if there are values available for a consumer to read.\n *\n * @param handle - The consumer handle.\n * @returns `true` if there are unread values, `false` otherwise.\n */\n readable(handle: ConsumerHandle<T>): boolean {\n return this.getCursor(handle) < this.#buffer.right;\n }\n\n [Symbol.asyncIterator](): AsyncIterator<T, void, void> {\n return new BroadcastIterator(this, this.#signal, this.join());\n }\n\n dispose(): void {\n this[Symbol.dispose]();\n }\n\n [Symbol.dispose](): void {\n // Stryker disable next-line ConditionalExpression: double-dispose re-clears empty collections, no observable effect\n if (this.#disposer[Symbol.dispose]()) {\n this.#signal[Symbol.dispose]();\n this.#buffer.clear();\n this.#cursors.clear();\n }\n }\n}\n"],"names":["RingBuffer","Signal","Disposer","min","ConsumerHandle","broadcast","cursor","getCursor","Symbol","dispose","leave","BroadcastIterator","signal","handle","next","result","tryConsume","done","value","receive","undefined","return","Broadcast","Map","WeakMap","FinalizationRegistry","id","get","delete","values","right","shift","left","shiftN","toStringTag","sink","emit","bind","handleEvent","event","size","disposed","push","then","onfulfilled","onrejected","catch","finally","onfinally","join","set","register","Error","unregister","consume","peekAt","readable","asyncIterator","clear"],"mappings":"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"}
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", {
3
+ value: true
4
+ });
5
+ function _export(target, all) {
6
+ for(var name in all)Object.defineProperty(target, name, {
7
+ enumerable: true,
8
+ get: Object.getOwnPropertyDescriptor(all, name).get
9
+ });
10
+ }
11
+ _export(exports, {
12
+ get DispatchResult () {
13
+ return DispatchResult;
14
+ },
15
+ get err () {
16
+ return err;
17
+ },
18
+ get isErr () {
19
+ return isErr;
20
+ },
21
+ get isOk () {
22
+ return isOk;
23
+ },
24
+ get unwrap () {
25
+ return unwrap;
26
+ }
27
+ });
28
+ const _utilscjs = require("./utils.cjs");
29
+ const ERR_BRAND = Symbol.for('evnty.ResultError');
30
+ function ResultError(error) {
31
+ this.error = error;
32
+ }
33
+ ResultError.prototype[ERR_BRAND] = true;
34
+ function err(error) {
35
+ return new ResultError(error);
36
+ }
37
+ function isErr(result) {
38
+ return typeof result === 'object' && result !== null && result[ERR_BRAND] === true;
39
+ }
40
+ function isOk(result) {
41
+ return typeof result !== 'object' || result === null || !result[ERR_BRAND];
42
+ }
43
+ function unwrap(results) {
44
+ const len = results.length;
45
+ const unwrapped = new Array(len);
46
+ for(let i = 0; i < len; i++){
47
+ const r = results[i];
48
+ unwrapped[i] = isErr(r) ? Promise.reject(r.error) : r;
49
+ }
50
+ return unwrapped;
51
+ }
52
+ async function resolveMaybePromises(items, asyncIndices) {
53
+ const pending = new Array(asyncIndices.length);
54
+ for(let j = 0; j < asyncIndices.length; j++){
55
+ pending[j] = items[asyncIndices[j]];
56
+ }
57
+ const resolved = await Promise.all(pending);
58
+ for(let j = 0; j < asyncIndices.length; j++){
59
+ items[asyncIndices[j]] = resolved[j];
60
+ }
61
+ return items;
62
+ }
63
+ function resolveAll(results) {
64
+ const len = results.length;
65
+ if (len === 0) return results;
66
+ let firstError;
67
+ let hasError = false;
68
+ let asyncIndices = null;
69
+ for(let i = 0; i < len; i++){
70
+ const r = results[i];
71
+ if (isErr(r)) {
72
+ if (!hasError) {
73
+ hasError = true;
74
+ firstError = r.error;
75
+ }
76
+ } else try {
77
+ if ((0, _utilscjs.isThenable)(r)) (asyncIndices ??= []).push(i);
78
+ } catch (e) {
79
+ if (!hasError) {
80
+ hasError = true;
81
+ firstError = e;
82
+ }
83
+ }
84
+ }
85
+ if (hasError) {
86
+ if (asyncIndices !== null) {
87
+ for(let j = 0; j < asyncIndices.length; j++){
88
+ results[asyncIndices[j]].then(_utilscjs.noop, _utilscjs.noop);
89
+ }
90
+ }
91
+ return Promise.reject(firstError);
92
+ }
93
+ if (asyncIndices === null) return results;
94
+ return resolveMaybePromises(results, asyncIndices);
95
+ }
96
+ function settleAll(results) {
97
+ const len = results.length;
98
+ if (len === 0) return [];
99
+ let asyncIndices = null;
100
+ const settled = new Array(len);
101
+ for(let i = 0; i < len; i++){
102
+ const r = results[i];
103
+ if (isErr(r)) {
104
+ settled[i] = {
105
+ status: 'rejected',
106
+ reason: r.error
107
+ };
108
+ } else try {
109
+ if ((0, _utilscjs.isThenable)(r)) {
110
+ const wrapped = r.then((value)=>({
111
+ status: 'fulfilled',
112
+ value
113
+ }), (reason)=>({
114
+ status: 'rejected',
115
+ reason
116
+ }));
117
+ (asyncIndices ??= []).push(i);
118
+ settled[i] = wrapped;
119
+ } else {
120
+ settled[i] = {
121
+ status: 'fulfilled',
122
+ value: r
123
+ };
124
+ }
125
+ } catch (e) {
126
+ settled[i] = {
127
+ status: 'rejected',
128
+ reason: e
129
+ };
130
+ }
131
+ }
132
+ if (asyncIndices === null) return settled;
133
+ return resolveMaybePromises(settled, asyncIndices);
134
+ }
135
+ class DispatchResult {
136
+ #results;
137
+ [Symbol.toStringTag] = 'DispatchResult';
138
+ constructor(results){
139
+ this.#results = results;
140
+ }
141
+ then(onfulfilled, onrejected) {
142
+ const resolved = this.all();
143
+ if (resolved instanceof Promise) return resolved.then(onfulfilled, onrejected);
144
+ return Promise.resolve(resolved).then(onfulfilled, onrejected);
145
+ }
146
+ all() {
147
+ return resolveAll(this.#results);
148
+ }
149
+ settled() {
150
+ return settleAll(this.#results);
151
+ }
152
+ }
153
+
154
+ //# sourceMappingURL=dispatch-result.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dispatch-result.ts"],"sourcesContent":["import { Fn, MaybePromise } from './types.js';\nimport { isThenable, noop } from './utils.js';\n\nconst ERR_BRAND = Symbol.for('evnty.ResultError');\n\n/**\n * @internal\n */\nexport interface ResultError<E = unknown> {\n readonly error: E;\n readonly [ERR_BRAND]: true;\n}\n\nfunction ResultError<E>(this: ResultError<E>, error: E): void {\n (this as { error: E }).error = error;\n}\n(ResultError.prototype as { [ERR_BRAND]: true })[ERR_BRAND] = true;\n\n/**\n * @internal\n */\nexport function err<E>(error: E): ResultError<E> {\n return new (ResultError as unknown as new (error: E) => ResultError<E>)(error);\n}\n\n/**\n * @internal\n */\nexport function isErr(result: unknown): result is ResultError<unknown> {\n return typeof result === 'object' && result !== null && (result as Record<symbol, boolean>)[ERR_BRAND] === true;\n}\n\n/**\n * @internal\n */\nexport function isOk(result: unknown): boolean {\n return typeof result !== 'object' || result === null || !(result as Record<symbol, boolean>)[ERR_BRAND];\n}\n\n/**\n * @internal\n */\nexport type DispatchResultItem<T> = MaybePromise<T> | ResultError;\n\n/**\n * @internal\n */\nexport function unwrap<T>(results: DispatchResultItem<T>[]): MaybePromise<T>[] {\n const len = results.length;\n const unwrapped = new Array<MaybePromise<T>>(len);\n for (let i = 0; i < len; i++) {\n const r = results[i];\n unwrapped[i] = isErr(r) ? Promise.reject(r.error) : r;\n }\n return unwrapped;\n}\n\nasync function resolveMaybePromises<T>(items: MaybePromise<T>[], asyncIndices: number[]): Promise<T[]> {\n const pending = new Array<PromiseLike<T>>(asyncIndices.length);\n for (let j = 0; j < asyncIndices.length; j++) {\n pending[j] = items[asyncIndices[j]] as PromiseLike<T>;\n }\n const resolved = await Promise.all(pending);\n for (let j = 0; j < asyncIndices.length; j++) {\n items[asyncIndices[j]] = resolved[j];\n }\n return items as T[];\n}\n\nfunction resolveAll<T>(results: DispatchResultItem<T>[]): T[] | Promise<T[]> {\n const len = results.length;\n if (len === 0) return results as T[];\n\n let firstError: unknown;\n let hasError = false;\n let asyncIndices: number[] | null = null;\n\n for (let i = 0; i < len; i++) {\n const r = results[i];\n if (isErr(r)) {\n if (!hasError) {\n hasError = true;\n firstError = r.error;\n }\n } else\n try {\n if (isThenable(r)) (asyncIndices ??= []).push(i);\n } catch (e) {\n if (!hasError) {\n hasError = true;\n firstError = e;\n }\n }\n }\n\n if (hasError) {\n if (asyncIndices !== null) {\n for (let j = 0; j < asyncIndices.length; j++) {\n (results[asyncIndices[j]] as PromiseLike<T>).then(noop, noop);\n }\n }\n return Promise.reject(firstError);\n }\n if (asyncIndices === null) return results as T[];\n\n return resolveMaybePromises(results as MaybePromise<T>[], asyncIndices);\n}\n\nfunction settleAll<T>(results: DispatchResultItem<T>[]): PromiseSettledResult<T>[] | Promise<PromiseSettledResult<T>[]> {\n const len = results.length;\n if (len === 0) return [] as PromiseSettledResult<T>[];\n\n let asyncIndices: number[] | null = null;\n const settled = new Array<MaybePromise<PromiseSettledResult<T>>>(len);\n\n for (let i = 0; i < len; i++) {\n const r = results[i];\n if (isErr(r)) {\n settled[i] = { status: 'rejected', reason: r.error };\n } else\n try {\n if (isThenable(r)) {\n const wrapped = r.then(\n (value: T): PromiseFulfilledResult<T> => ({ status: 'fulfilled', value }),\n (reason: unknown): PromiseRejectedResult => ({ status: 'rejected', reason }),\n );\n (asyncIndices ??= []).push(i);\n settled[i] = wrapped;\n } else {\n settled[i] = { status: 'fulfilled', value: r };\n }\n } catch (e) {\n settled[i] = { status: 'rejected', reason: e };\n }\n }\n\n if (asyncIndices === null) return settled as PromiseSettledResult<T>[];\n\n return resolveMaybePromises(settled, asyncIndices);\n}\n\n/**\n * Wraps an array of values or promises (typically listener results) and provides batch resolution.\n *\n * @template T\n */\nexport class DispatchResult<T> implements PromiseLike<T[]> {\n #results: DispatchResultItem<T>[];\n\n readonly [Symbol.toStringTag] = 'DispatchResult';\n\n constructor(results: DispatchResultItem<T>[]) {\n this.#results = results;\n }\n\n then<TResult1 = T, TResult2 = never>(\n onfulfilled?: Fn<[T[]], MaybePromise<TResult1>> | null,\n onrejected?: Fn<[any], MaybePromise<TResult2>> | null,\n ): PromiseLike<TResult1 | TResult2> {\n const resolved = this.all();\n if (resolved instanceof Promise) return resolved.then(onfulfilled, onrejected);\n return Promise.resolve(resolved).then(onfulfilled, onrejected);\n }\n\n /**\n * Resolves all listener results, rejecting if any promise rejects or any ResultError exists.\n */\n all(): T[] | Promise<T[]> {\n return resolveAll(this.#results);\n }\n\n /**\n * Waits for all listener results to settle, regardless of fulfillment or rejection.\n */\n settled(): PromiseSettledResult<T>[] | Promise<PromiseSettledResult<T>[]> {\n return settleAll(this.#results);\n }\n}\n"],"names":["DispatchResult","err","isErr","isOk","unwrap","ERR_BRAND","Symbol","for","ResultError","error","prototype","result","results","len","length","unwrapped","Array","i","r","Promise","reject","resolveMaybePromises","items","asyncIndices","pending","j","resolved","all","resolveAll","firstError","hasError","isThenable","push","e","then","noop","settleAll","settled","status","reason","wrapped","value","toStringTag","onfulfilled","onrejected","resolve"],"mappings":";;;;;;;;;;;QAkJaA;eAAAA;;QA7HGC;eAAAA;;QAOAC;eAAAA;;QAOAC;eAAAA;;QAYAC;eAAAA;;;0BA9CiB;AAEjC,MAAMC,YAAYC,OAAOC,GAAG,CAAC;AAU7B,SAASC,YAAqCC,KAAQ;IACpD,AAAC,IAAI,CAAkBA,KAAK,GAAGA;AACjC;AACCD,YAAYE,SAAS,AAA0B,CAACL,UAAU,GAAG;AAKvD,SAASJ,IAAOQ,KAAQ;IAC7B,OAAO,IAAKD,YAA4DC;AAC1E;AAKO,SAASP,MAAMS,MAAe;IACnC,OAAO,OAAOA,WAAW,YAAYA,WAAW,QAAQ,AAACA,MAAkC,CAACN,UAAU,KAAK;AAC7G;AAKO,SAASF,KAAKQ,MAAe;IAClC,OAAO,OAAOA,WAAW,YAAYA,WAAW,QAAQ,CAAC,AAACA,MAAkC,CAACN,UAAU;AACzG;AAUO,SAASD,OAAUQ,OAAgC;IACxD,MAAMC,MAAMD,QAAQE,MAAM;IAC1B,MAAMC,YAAY,IAAIC,MAAuBH;IAC7C,IAAK,IAAII,IAAI,GAAGA,IAAIJ,KAAKI,IAAK;QAC5B,MAAMC,IAAIN,OAAO,CAACK,EAAE;QACpBF,SAAS,CAACE,EAAE,GAAGf,MAAMgB,KAAKC,QAAQC,MAAM,CAACF,EAAET,KAAK,IAAIS;IACtD;IACA,OAAOH;AACT;AAEA,eAAeM,qBAAwBC,KAAwB,EAAEC,YAAsB;IACrF,MAAMC,UAAU,IAAIR,MAAsBO,aAAaT,MAAM;IAC7D,IAAK,IAAIW,IAAI,GAAGA,IAAIF,aAAaT,MAAM,EAAEW,IAAK;QAC5CD,OAAO,CAACC,EAAE,GAAGH,KAAK,CAACC,YAAY,CAACE,EAAE,CAAC;IACrC;IACA,MAAMC,WAAW,MAAMP,QAAQQ,GAAG,CAACH;IACnC,IAAK,IAAIC,IAAI,GAAGA,IAAIF,aAAaT,MAAM,EAAEW,IAAK;QAC5CH,KAAK,CAACC,YAAY,CAACE,EAAE,CAAC,GAAGC,QAAQ,CAACD,EAAE;IACtC;IACA,OAAOH;AACT;AAEA,SAASM,WAAchB,OAAgC;IACrD,MAAMC,MAAMD,QAAQE,MAAM;IAC1B,IAAID,QAAQ,GAAG,OAAOD;IAEtB,IAAIiB;IACJ,IAAIC,WAAW;IACf,IAAIP,eAAgC;IAEpC,IAAK,IAAIN,IAAI,GAAGA,IAAIJ,KAAKI,IAAK;QAC5B,MAAMC,IAAIN,OAAO,CAACK,EAAE;QACpB,IAAIf,MAAMgB,IAAI;YACZ,IAAI,CAACY,UAAU;gBACbA,WAAW;gBACXD,aAAaX,EAAET,KAAK;YACtB;QACF,OACE,IAAI;YACF,IAAIsB,IAAAA,oBAAU,EAACb,IAAI,AAACK,CAAAA,iBAAiB,EAAE,AAAD,EAAGS,IAAI,CAACf;QAChD,EAAE,OAAOgB,GAAG;YACV,IAAI,CAACH,UAAU;gBACbA,WAAW;gBACXD,aAAaI;YACf;QACF;IACJ;IAEA,IAAIH,UAAU;QACZ,IAAIP,iBAAiB,MAAM;YACzB,IAAK,IAAIE,IAAI,GAAGA,IAAIF,aAAaT,MAAM,EAAEW,IAAK;gBAC3Cb,OAAO,CAACW,YAAY,CAACE,EAAE,CAAC,CAAoBS,IAAI,CAACC,cAAI,EAAEA,cAAI;YAC9D;QACF;QACA,OAAOhB,QAAQC,MAAM,CAACS;IACxB;IACA,IAAIN,iBAAiB,MAAM,OAAOX;IAElC,OAAOS,qBAAqBT,SAA8BW;AAC5D;AAEA,SAASa,UAAaxB,OAAgC;IACpD,MAAMC,MAAMD,QAAQE,MAAM;IAC1B,IAAID,QAAQ,GAAG,OAAO,EAAE;IAExB,IAAIU,eAAgC;IACpC,MAAMc,UAAU,IAAIrB,MAA6CH;IAEjE,IAAK,IAAII,IAAI,GAAGA,IAAIJ,KAAKI,IAAK;QAC5B,MAAMC,IAAIN,OAAO,CAACK,EAAE;QACpB,IAAIf,MAAMgB,IAAI;YACZmB,OAAO,CAACpB,EAAE,GAAG;gBAAEqB,QAAQ;gBAAYC,QAAQrB,EAAET,KAAK;YAAC;QACrD,OACE,IAAI;YACF,IAAIsB,IAAAA,oBAAU,EAACb,IAAI;gBACjB,MAAMsB,UAAUtB,EAAEgB,IAAI,CACpB,CAACO,QAAyC,CAAA;wBAAEH,QAAQ;wBAAaG;oBAAM,CAAA,GACvE,CAACF,SAA4C,CAAA;wBAAED,QAAQ;wBAAYC;oBAAO,CAAA;gBAE3EhB,CAAAA,iBAAiB,EAAE,AAAD,EAAGS,IAAI,CAACf;gBAC3BoB,OAAO,CAACpB,EAAE,GAAGuB;YACf,OAAO;gBACLH,OAAO,CAACpB,EAAE,GAAG;oBAAEqB,QAAQ;oBAAaG,OAAOvB;gBAAE;YAC/C;QACF,EAAE,OAAOe,GAAG;YACVI,OAAO,CAACpB,EAAE,GAAG;gBAAEqB,QAAQ;gBAAYC,QAAQN;YAAE;QAC/C;IACJ;IAEA,IAAIV,iBAAiB,MAAM,OAAOc;IAElC,OAAOhB,qBAAqBgB,SAASd;AACvC;AAOO,MAAMvB;IACX,CAAA,OAAQ,CAA0B;IAEzB,CAACM,OAAOoC,WAAW,CAAC,GAAG,iBAAiB;IAEjD,YAAY9B,OAAgC,CAAE;QAC5C,IAAI,CAAC,CAAA,OAAQ,GAAGA;IAClB;IAEAsB,KACES,WAAsD,EACtDC,UAAqD,EACnB;QAClC,MAAMlB,WAAW,IAAI,CAACC,GAAG;QACzB,IAAID,oBAAoBP,SAAS,OAAOO,SAASQ,IAAI,CAACS,aAAaC;QACnE,OAAOzB,QAAQ0B,OAAO,CAACnB,UAAUQ,IAAI,CAACS,aAAaC;IACrD;IAKAjB,MAA0B;QACxB,OAAOC,WAAW,IAAI,CAAC,CAAA,OAAQ;IACjC;IAKAS,UAA0E;QACxE,OAAOD,UAAU,IAAI,CAAC,CAAA,OAAQ;IAChC;AACF"}
@@ -0,0 +1,49 @@
1
+ import { Fn, MaybePromise } from './types.js';
2
+ declare const ERR_BRAND: unique symbol;
3
+ /**
4
+ * @internal
5
+ */
6
+ export interface ResultError<E = unknown> {
7
+ readonly error: E;
8
+ readonly [ERR_BRAND]: true;
9
+ }
10
+ /**
11
+ * @internal
12
+ */
13
+ export declare function err<E>(error: E): ResultError<E>;
14
+ /**
15
+ * @internal
16
+ */
17
+ export declare function isErr(result: unknown): result is ResultError<unknown>;
18
+ /**
19
+ * @internal
20
+ */
21
+ export declare function isOk(result: unknown): boolean;
22
+ /**
23
+ * @internal
24
+ */
25
+ export type DispatchResultItem<T> = MaybePromise<T> | ResultError;
26
+ /**
27
+ * @internal
28
+ */
29
+ export declare function unwrap<T>(results: DispatchResultItem<T>[]): MaybePromise<T>[];
30
+ /**
31
+ * Wraps an array of values or promises (typically listener results) and provides batch resolution.
32
+ *
33
+ * @template T
34
+ */
35
+ export declare class DispatchResult<T> implements PromiseLike<T[]> {
36
+ #private;
37
+ readonly [Symbol.toStringTag] = "DispatchResult";
38
+ constructor(results: DispatchResultItem<T>[]);
39
+ then<TResult1 = T, TResult2 = never>(onfulfilled?: Fn<[T[]], MaybePromise<TResult1>> | null, onrejected?: Fn<[any], MaybePromise<TResult2>> | null): PromiseLike<TResult1 | TResult2>;
40
+ /**
41
+ * Resolves all listener results, rejecting if any promise rejects or any ResultError exists.
42
+ */
43
+ all(): T[] | Promise<T[]>;
44
+ /**
45
+ * Waits for all listener results to settle, regardless of fulfillment or rejection.
46
+ */
47
+ settled(): PromiseSettledResult<T>[] | Promise<PromiseSettledResult<T>[]>;
48
+ }
49
+ export {};