@vielzeug/flux 1.0.3
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 +50 -0
- package/dist/_dev.cjs +2 -0
- package/dist/_dev.cjs.map +1 -0
- package/dist/_dev.d.ts +2 -0
- package/dist/_dev.d.ts.map +1 -0
- package/dist/_dev.js +12 -0
- package/dist/_dev.js.map +1 -0
- package/dist/_iterator.cjs +2 -0
- package/dist/_iterator.cjs.map +1 -0
- package/dist/_iterator.d.ts +2 -0
- package/dist/_iterator.d.ts.map +1 -0
- package/dist/_iterator.js +53 -0
- package/dist/_iterator.js.map +1 -0
- package/dist/_numeric.cjs +2 -0
- package/dist/_numeric.cjs.map +1 -0
- package/dist/_numeric.d.ts +2 -0
- package/dist/_numeric.d.ts.map +1 -0
- package/dist/_numeric.js +12 -0
- package/dist/_numeric.js.map +1 -0
- package/dist/_pipe.cjs +2 -0
- package/dist/_pipe.cjs.map +1 -0
- package/dist/_pipe.d.ts +2 -0
- package/dist/_pipe.d.ts.map +1 -0
- package/dist/_pipe.js +8 -0
- package/dist/_pipe.js.map +1 -0
- package/dist/_safe.cjs +2 -0
- package/dist/_safe.cjs.map +1 -0
- package/dist/_safe.d.ts +2 -0
- package/dist/_safe.d.ts.map +1 -0
- package/dist/_safe.js +12 -0
- package/dist/_safe.js.map +1 -0
- package/dist/_scheduler.cjs +2 -0
- package/dist/_scheduler.cjs.map +1 -0
- package/dist/_scheduler.d.ts +3 -0
- package/dist/_scheduler.d.ts.map +1 -0
- package/dist/_scheduler.js +15 -0
- package/dist/_scheduler.js.map +1 -0
- package/dist/adapters/courier.cjs +2 -0
- package/dist/adapters/courier.cjs.map +1 -0
- package/dist/adapters/courier.d.ts +22 -0
- package/dist/adapters/courier.d.ts.map +1 -0
- package/dist/adapters/courier.js +14 -0
- package/dist/adapters/courier.js.map +1 -0
- package/dist/adapters/herald.cjs +2 -0
- package/dist/adapters/herald.cjs.map +1 -0
- package/dist/adapters/herald.d.ts +19 -0
- package/dist/adapters/herald.d.ts.map +1 -0
- package/dist/adapters/herald.js +18 -0
- package/dist/adapters/herald.js.map +1 -0
- package/dist/adapters/pulse.cjs +2 -0
- package/dist/adapters/pulse.cjs.map +1 -0
- package/dist/adapters/pulse.d.ts +22 -0
- package/dist/adapters/pulse.d.ts.map +1 -0
- package/dist/adapters/pulse.js +22 -0
- package/dist/adapters/pulse.js.map +1 -0
- package/dist/adapters/ripple.cjs +2 -0
- package/dist/adapters/ripple.cjs.map +1 -0
- package/dist/adapters/ripple.d.ts +53 -0
- package/dist/adapters/ripple.d.ts.map +1 -0
- package/dist/adapters/ripple.js +47 -0
- package/dist/adapters/ripple.js.map +1 -0
- package/dist/core.cjs +2 -0
- package/dist/core.cjs.map +1 -0
- package/dist/core.d.ts +17 -0
- package/dist/core.d.ts.map +1 -0
- package/dist/core.js +87 -0
- package/dist/core.js.map +1 -0
- package/dist/errors.cjs +2 -0
- package/dist/errors.cjs.map +1 -0
- package/dist/errors.d.ts +10 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +18 -0
- package/dist/errors.js.map +1 -0
- package/dist/flux.cjs +2 -0
- package/dist/flux.cjs.map +1 -0
- package/dist/flux.iife.js +2 -0
- package/dist/flux.iife.js.map +1 -0
- package/dist/flux.js +2 -0
- package/dist/flux.js.map +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/operators/combination.cjs +2 -0
- package/dist/operators/combination.cjs.map +1 -0
- package/dist/operators/combination.d.ts +65 -0
- package/dist/operators/combination.d.ts.map +1 -0
- package/dist/operators/combination.js +187 -0
- package/dist/operators/combination.js.map +1 -0
- package/dist/operators/creation.cjs +2 -0
- package/dist/operators/creation.cjs.map +1 -0
- package/dist/operators/creation.d.ts +50 -0
- package/dist/operators/creation.d.ts.map +1 -0
- package/dist/operators/creation.js +90 -0
- package/dist/operators/creation.js.map +1 -0
- package/dist/operators/filtering.cjs +2 -0
- package/dist/operators/filtering.cjs.map +1 -0
- package/dist/operators/filtering.d.ts +62 -0
- package/dist/operators/filtering.d.ts.map +1 -0
- package/dist/operators/filtering.js +140 -0
- package/dist/operators/filtering.js.map +1 -0
- package/dist/operators/transformation.cjs +2 -0
- package/dist/operators/transformation.cjs.map +1 -0
- package/dist/operators/transformation.d.ts +64 -0
- package/dist/operators/transformation.d.ts.map +1 -0
- package/dist/operators/transformation.js +185 -0
- package/dist/operators/transformation.js.map +1 -0
- package/dist/operators/utility.cjs +2 -0
- package/dist/operators/utility.cjs.map +1 -0
- package/dist/operators/utility.d.ts +98 -0
- package/dist/operators/utility.d.ts.map +1 -0
- package/dist/operators/utility.js +226 -0
- package/dist/operators/utility.js.map +1 -0
- package/dist/subject.cjs +2 -0
- package/dist/subject.cjs.map +1 -0
- package/dist/subject.d.ts +67 -0
- package/dist/subject.d.ts.map +1 -0
- package/dist/subject.js +181 -0
- package/dist/subject.js.map +1 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.d.ts.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import { error as e, warn as t } from "../_dev.js";
|
|
2
|
+
import { flux as n } from "../core.js";
|
|
3
|
+
import { DEFAULT_SCHEDULER as r } from "../_scheduler.js";
|
|
4
|
+
import { FluxTimeoutError as i } from "../errors.js";
|
|
5
|
+
import { guard as a } from "../_safe.js";
|
|
6
|
+
import { clampPositiveInt as o } from "../_numeric.js";
|
|
7
|
+
//#region src/operators/utility.ts
|
|
8
|
+
function s(e, t) {
|
|
9
|
+
let r = /* @__PURE__ */ new Set(), i = [], a, o = !1, s, c = !1;
|
|
10
|
+
return n((n) => {
|
|
11
|
+
if (c) {
|
|
12
|
+
n.error?.(s);
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
for (let e of i) n.next(e);
|
|
16
|
+
if (o) {
|
|
17
|
+
n.complete?.();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
let l = {
|
|
21
|
+
complete: n.complete,
|
|
22
|
+
error: n.error,
|
|
23
|
+
next: n.next
|
|
24
|
+
};
|
|
25
|
+
return r.add(l), r.size === 1 && (a = e.subscribe({
|
|
26
|
+
complete() {
|
|
27
|
+
o = !0;
|
|
28
|
+
for (let e of [...r]) e.complete?.();
|
|
29
|
+
r.clear();
|
|
30
|
+
},
|
|
31
|
+
error(e) {
|
|
32
|
+
c = !0, s = e;
|
|
33
|
+
for (let t of [...r]) t.error?.(e);
|
|
34
|
+
r.clear();
|
|
35
|
+
},
|
|
36
|
+
next(e) {
|
|
37
|
+
t > 0 && (i.length >= t && i.shift(), i.push(e));
|
|
38
|
+
for (let t of [...r]) t.next(e);
|
|
39
|
+
}
|
|
40
|
+
})), () => {
|
|
41
|
+
r.delete(l), r.size === 0 && (a?.(), a = void 0);
|
|
42
|
+
};
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
function c() {
|
|
46
|
+
return (e) => s(e, 0);
|
|
47
|
+
}
|
|
48
|
+
function l(e = 1) {
|
|
49
|
+
let { clamped: n, value: r } = o(e);
|
|
50
|
+
return n && t(`shareReplay: bufferSize must be a finite integer >= 1, got ${e} — clamped to ${r}`), (e) => s(e, r);
|
|
51
|
+
}
|
|
52
|
+
function u(e) {
|
|
53
|
+
return (t) => n((n) => t.subscribe({
|
|
54
|
+
complete: n.complete,
|
|
55
|
+
error: n.error,
|
|
56
|
+
next(t) {
|
|
57
|
+
a(() => {
|
|
58
|
+
e(t), n.next(t);
|
|
59
|
+
}, n.error);
|
|
60
|
+
}
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
63
|
+
function d(e, t = r) {
|
|
64
|
+
return (r) => n((n) => {
|
|
65
|
+
let i = [], a = r.subscribe({
|
|
66
|
+
complete() {
|
|
67
|
+
i.push(t.delay(() => n.complete?.(), e));
|
|
68
|
+
},
|
|
69
|
+
error: n.error,
|
|
70
|
+
next(r) {
|
|
71
|
+
i.push(t.delay(() => n.next(r), e));
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
return () => {
|
|
75
|
+
a();
|
|
76
|
+
for (let e of i) e();
|
|
77
|
+
};
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
function f(e, t = r) {
|
|
81
|
+
return (r) => n((n) => {
|
|
82
|
+
let a, o = () => {
|
|
83
|
+
a = t.delay(() => {
|
|
84
|
+
n.error?.(new i(e));
|
|
85
|
+
}, e);
|
|
86
|
+
};
|
|
87
|
+
o();
|
|
88
|
+
let s = r.subscribe({
|
|
89
|
+
complete() {
|
|
90
|
+
a(), n.complete?.();
|
|
91
|
+
},
|
|
92
|
+
error(e) {
|
|
93
|
+
a(), n.error?.(e);
|
|
94
|
+
},
|
|
95
|
+
next(e) {
|
|
96
|
+
a(), o(), n.next(e);
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
return () => {
|
|
100
|
+
a(), s();
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
function p(e) {
|
|
105
|
+
return (t) => n((n) => {
|
|
106
|
+
let r, i = t.subscribe({
|
|
107
|
+
complete: n.complete,
|
|
108
|
+
error(t) {
|
|
109
|
+
a(() => {
|
|
110
|
+
r = e(t).subscribe({
|
|
111
|
+
complete: n.complete,
|
|
112
|
+
error: n.error,
|
|
113
|
+
next: n.next
|
|
114
|
+
});
|
|
115
|
+
}, n.error);
|
|
116
|
+
},
|
|
117
|
+
next: n.next
|
|
118
|
+
});
|
|
119
|
+
return () => {
|
|
120
|
+
i(), r?.();
|
|
121
|
+
};
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
function m(e, t, i = r) {
|
|
125
|
+
return (r) => n((n) => {
|
|
126
|
+
let o = 0, s, c;
|
|
127
|
+
function l() {
|
|
128
|
+
s = r.subscribe({
|
|
129
|
+
complete: n.complete,
|
|
130
|
+
error(r) {
|
|
131
|
+
if (o < e) {
|
|
132
|
+
let e = o++;
|
|
133
|
+
t === void 0 ? l() : a(() => {
|
|
134
|
+
let n = typeof t == "function" ? t(e) : t;
|
|
135
|
+
c = i.delay(l, Math.max(0, n));
|
|
136
|
+
}, n.error);
|
|
137
|
+
} else n.error?.(r);
|
|
138
|
+
},
|
|
139
|
+
next: n.next
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return l(), () => {
|
|
143
|
+
c?.(), s?.();
|
|
144
|
+
};
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
function h(t) {
|
|
148
|
+
return (r) => n((n) => {
|
|
149
|
+
let i = !1, a = () => {
|
|
150
|
+
if (!i) {
|
|
151
|
+
i = !0;
|
|
152
|
+
try {
|
|
153
|
+
t();
|
|
154
|
+
} catch (t) {
|
|
155
|
+
e("finalize: cleanup callback threw", t);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}, o = r.subscribe({
|
|
159
|
+
complete() {
|
|
160
|
+
a(), n.complete?.();
|
|
161
|
+
},
|
|
162
|
+
error(e) {
|
|
163
|
+
a(), n.error?.(e);
|
|
164
|
+
},
|
|
165
|
+
next: n.next
|
|
166
|
+
});
|
|
167
|
+
return () => {
|
|
168
|
+
a(), o();
|
|
169
|
+
};
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
function g(e) {
|
|
173
|
+
return e.reason ?? new DOMException("Aborted", "AbortError");
|
|
174
|
+
}
|
|
175
|
+
function _(e, t) {
|
|
176
|
+
return new Promise((n, r) => {
|
|
177
|
+
if (t?.aborted) {
|
|
178
|
+
r(g(t));
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
let i, a = () => {}, o = () => {
|
|
182
|
+
a(), r(g(t));
|
|
183
|
+
};
|
|
184
|
+
t?.addEventListener("abort", o, { once: !0 }), a = e.subscribe({
|
|
185
|
+
complete() {
|
|
186
|
+
t?.removeEventListener("abort", o), n(i);
|
|
187
|
+
},
|
|
188
|
+
error(e) {
|
|
189
|
+
t?.removeEventListener("abort", o), r(e);
|
|
190
|
+
},
|
|
191
|
+
next(e) {
|
|
192
|
+
i = e;
|
|
193
|
+
}
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
function v(e, t) {
|
|
198
|
+
return new Promise((n, r) => {
|
|
199
|
+
let i = [];
|
|
200
|
+
if (t?.aborted) {
|
|
201
|
+
n(i);
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
let a = () => {}, o = () => {
|
|
205
|
+
a(), n(i);
|
|
206
|
+
};
|
|
207
|
+
t?.addEventListener("abort", o, { once: !0 }), a = e.subscribe({
|
|
208
|
+
complete() {
|
|
209
|
+
t?.removeEventListener("abort", o), n(i);
|
|
210
|
+
},
|
|
211
|
+
error(e) {
|
|
212
|
+
t?.removeEventListener("abort", o), r(e);
|
|
213
|
+
},
|
|
214
|
+
next(e) {
|
|
215
|
+
i.push(e);
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function y(...e) {
|
|
221
|
+
return (t) => e.reduce((e, t) => t(e), t);
|
|
222
|
+
}
|
|
223
|
+
//#endregion
|
|
224
|
+
export { p as catchError, d as delay, h as finalize, y as flow, m as retry, c as share, l as shareReplay, u as tap, f as timeout, v as toArray, _ as toPromise };
|
|
225
|
+
|
|
226
|
+
//# sourceMappingURL=utility.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utility.js","names":[],"sources":["../../src/operators/utility.ts"],"sourcesContent":["import type { Flux, Operator, Scheduler, Unsubscribe } from '../types';\n\nimport { error, warn } from '../_dev';\nimport { clampPositiveInt } from '../_numeric';\nimport { guard } from '../_safe';\nimport { DEFAULT_SCHEDULER } from '../_scheduler';\nimport { flux } from '../core';\nimport { FluxTimeoutError } from '../errors';\n\ntype SharedEntry<T> = { complete?: () => void; error?: (e: unknown) => void; next: (v: T) => void };\n\nfunction makeMulticast<T>(source: Flux<T>, maxBuffer: number): Flux<T> {\n const subscribers = new Set<SharedEntry<T>>();\n const buffer: T[] = [];\n let sourceUnsub: Unsubscribe | undefined;\n let sourceDone = false;\n let sourceError: unknown;\n let hasError = false;\n\n return flux<T>((observer) => {\n if (hasError) {\n observer.error?.(sourceError);\n\n return;\n }\n\n for (const v of buffer) observer.next(v);\n\n if (sourceDone) {\n observer.complete?.();\n\n return;\n }\n\n const entry: SharedEntry<T> = {\n complete: observer.complete,\n error: observer.error,\n next: observer.next,\n };\n\n subscribers.add(entry);\n\n if (subscribers.size === 1) {\n sourceUnsub = source.subscribe({\n complete() {\n sourceDone = true;\n for (const s of [...subscribers]) s.complete?.();\n subscribers.clear();\n },\n error(err) {\n hasError = true;\n sourceError = err;\n for (const s of [...subscribers]) s.error?.(err);\n subscribers.clear();\n },\n next(v) {\n if (maxBuffer > 0) {\n if (buffer.length >= maxBuffer) buffer.shift();\n\n buffer.push(v);\n }\n\n for (const s of [...subscribers]) s.next(v);\n },\n });\n }\n\n return () => {\n subscribers.delete(entry);\n\n if (subscribers.size === 0) {\n sourceUnsub?.();\n sourceUnsub = undefined;\n }\n };\n });\n}\n\n/**\n * Multicast a cold `Flux` to multiple subscribers. The first subscriber starts\n * the source; the last to unsubscribe stops it.\n *\n * @example\n * const hot$ = cold$.pipe(share()); // one source, many subscribers\n */\nexport function share<T>(): Operator<T, T> {\n return (source) => makeMulticast(source, 0);\n}\n\n/**\n * Multicast a cold `Flux` and replay the last `bufferSize` values (default: 1)\n * to any new subscriber.\n *\n * @example\n * const hot$ = cold$.pipe(shareReplay(1)); // last value replayed to late subs\n */\nexport function shareReplay<T>(bufferSize = 1): Operator<T, T> {\n const { clamped, value: safeSize } = clampPositiveInt(bufferSize);\n\n if (clamped) {\n warn(`shareReplay: bufferSize must be a finite integer >= 1, got ${bufferSize} — clamped to ${safeSize}`);\n }\n\n return (source) => makeMulticast(source, safeSize);\n}\n\n/** Run a side effect on each emission without modifying the value. */\nexport function tap<T>(fn: (value: T) => void): Operator<T, T> {\n return (source) =>\n flux<T>((observer) =>\n source.subscribe({\n complete: observer.complete,\n error: observer.error,\n next(v) {\n guard(() => {\n fn(v);\n observer.next(v);\n }, observer.error);\n },\n }),\n );\n}\n\n/** Delay each emission by `ms` milliseconds. Pass a custom `scheduler` to control time in tests. */\nexport function delay<T>(ms: number, scheduler: Scheduler = DEFAULT_SCHEDULER): Operator<T, T> {\n return (source) =>\n flux<T>((observer) => {\n const cancels: Array<() => void> = [];\n\n const unsub = source.subscribe({\n complete() {\n cancels.push(scheduler.delay(() => observer.complete?.(), ms));\n },\n error: observer.error,\n next(v) {\n cancels.push(scheduler.delay(() => observer.next(v), ms));\n },\n });\n\n return () => {\n unsub();\n for (const cancel of cancels) cancel();\n };\n });\n}\n\n/**\n * Error if no value is emitted within `ms` milliseconds since the last emission\n * (or since subscription, for the first value). The timer resets on each emission —\n * this is an inactivity timeout, not a time-to-first-value or total-duration timeout.\n * Pass a custom `scheduler` to control time in tests.\n *\n * @example\n * source$.pipe(timeout(5000)); // throws FluxTimeoutError after 5s of silence\n */\nexport function timeout<T>(ms: number, scheduler: Scheduler = DEFAULT_SCHEDULER): Operator<T, T> {\n return (source) =>\n flux<T>((observer) => {\n let cancelTimer!: () => void;\n\n const startTimer = (): void => {\n cancelTimer = scheduler.delay(() => {\n observer.error?.(new FluxTimeoutError(ms));\n }, ms);\n };\n\n startTimer();\n\n const unsub = source.subscribe({\n complete() {\n cancelTimer();\n observer.complete?.();\n },\n error(err) {\n cancelTimer();\n observer.error?.(err);\n },\n next(v) {\n cancelTimer();\n startTimer();\n observer.next(v);\n },\n });\n\n return () => {\n cancelTimer();\n unsub();\n };\n });\n}\n\n/**\n * Recover from an error by returning a new `Flux` to continue with.\n *\n * @example\n * source$.pipe(catchError((err) => of('fallback')));\n */\nexport function catchError<T>(handler: (err: unknown) => Flux<T>): Operator<T, T> {\n return (source) =>\n flux<T>((observer) => {\n let fallbackUnsub: Unsubscribe | undefined;\n\n const sourceUnsub = source.subscribe({\n complete: observer.complete,\n error(err) {\n guard(() => {\n fallbackUnsub = handler(err).subscribe({\n complete: observer.complete,\n error: observer.error,\n next: observer.next,\n });\n }, observer.error);\n },\n next: observer.next,\n });\n\n return () => {\n sourceUnsub();\n fallbackUnsub?.();\n };\n });\n}\n\n/**\n * Re-subscribe to the source up to `count` times on error.\n * Pass `delayMs` as a fixed number or `(attempt) => number` function for backoff.\n * Pass a custom `scheduler` to control time in tests.\n *\n * @example\n * fetchStream$.pipe(retry(3));\n * fetchStream$.pipe(retry(3, (n) => Math.min(1000 * 2 ** n, 30_000))); // exponential backoff\n */\nexport function retry<T>(\n count: number,\n delayMs?: number | ((attempt: number) => number),\n scheduler: Scheduler = DEFAULT_SCHEDULER,\n): Operator<T, T> {\n return (source) =>\n flux<T>((observer) => {\n let attempts = 0;\n let currentUnsub: Unsubscribe | undefined;\n let cancelDelay: (() => void) | undefined;\n\n function attempt(): void {\n currentUnsub = source.subscribe({\n complete: observer.complete,\n error(err) {\n if (attempts < count) {\n const n = attempts++;\n\n if (delayMs !== undefined) {\n guard(() => {\n const ms = typeof delayMs === 'function' ? delayMs(n) : delayMs;\n\n cancelDelay = scheduler.delay(attempt, Math.max(0, ms));\n }, observer.error);\n } else {\n attempt();\n }\n } else {\n observer.error?.(err);\n }\n },\n next: observer.next,\n });\n }\n\n attempt();\n\n return () => {\n cancelDelay?.();\n currentUnsub?.();\n };\n });\n}\n\n/**\n * Run `fn` when the stream ends — whether by completion, error, or unsubscription.\n *\n * @example\n * source$.pipe(finalize(() => console.log('stream ended')));\n */\nexport function finalize<T>(fn: () => void): Operator<T, T> {\n return (source) =>\n flux<T>((observer) => {\n let called = false;\n\n const call = (): void => {\n if (called) return;\n\n called = true;\n\n try {\n fn();\n } catch (err) {\n error('finalize: cleanup callback threw', err);\n }\n };\n\n const unsub = source.subscribe({\n complete() {\n call();\n observer.complete?.();\n },\n error(err) {\n call();\n observer.error?.(err);\n },\n next: observer.next,\n });\n\n return () => {\n call();\n unsub();\n };\n });\n}\n\n/** Reject value used when `signal` aborts a pending `toPromise()`/`toArray()`. */\nfunction abortError(signal: AbortSignal): unknown {\n return signal.reason ?? new DOMException('Aborted', 'AbortError');\n}\n\n/**\n * Convert a `Flux` to a `Promise` that resolves with the last emitted value\n * when the source completes, or rejects on error.\n * Pass `signal` to unsubscribe and reject early if the caller loses interest\n * before the source completes (e.g. a component unmounting).\n *\n * @example\n * const result = await toPromise(source$);\n * const cancellable = await toPromise(source$, controller.signal);\n */\nexport function toPromise<T>(source: Flux<T>, signal?: AbortSignal): Promise<T | undefined> {\n return new Promise<T | undefined>((resolve, reject) => {\n if (signal?.aborted) {\n reject(abortError(signal));\n\n return;\n }\n\n let last: T | undefined;\n let unsub: Unsubscribe = () => {};\n\n const onAbort = (): void => {\n unsub();\n reject(abortError(signal!));\n };\n\n // Add the listener before subscribing — the source may complete/error synchronously\n // during subscribe(), and the complete/error handlers below need it already registered\n // to remove it (otherwise it leaks on `signal` until the signal itself is GC'd).\n signal?.addEventListener('abort', onAbort, { once: true });\n\n unsub = source.subscribe({\n complete() {\n signal?.removeEventListener('abort', onAbort);\n resolve(last);\n },\n error(err) {\n signal?.removeEventListener('abort', onAbort);\n reject(err);\n },\n next(v) {\n last = v;\n },\n });\n });\n}\n\n/**\n * Collect all emitted values into an array resolved when the source completes.\n * Pass `signal` to stop early and resolve with the values collected so far\n * (rather than reject) if the caller loses interest before completion.\n *\n * @example\n * const all = await toArray(of(1, 2, 3));\n * const partial = await toArray(source$, controller.signal);\n */\nexport function toArray<T>(source: Flux<T>, signal?: AbortSignal): Promise<T[]> {\n return new Promise<T[]>((resolve, reject) => {\n const results: T[] = [];\n\n if (signal?.aborted) {\n resolve(results);\n\n return;\n }\n\n let unsub: Unsubscribe = () => {};\n\n const onAbort = (): void => {\n unsub();\n resolve(results);\n };\n\n // See toPromise() above for why the listener is added before subscribing.\n signal?.addEventListener('abort', onAbort, { once: true });\n\n unsub = source.subscribe({\n complete() {\n signal?.removeEventListener('abort', onAbort);\n resolve(results);\n },\n error(err) {\n signal?.removeEventListener('abort', onAbort);\n reject(err);\n },\n next(v) {\n results.push(v);\n },\n });\n });\n}\n\n/**\n * Compose multiple operators into a single reusable operator.\n * Provides full type safety at any pipeline depth — use instead of\n * `pipe()` overloads when chaining more than 4 operators.\n *\n * @example\n * const pipeline = flow(\n * filter((n) => n % 2 === 0),\n * map((n) => n * 10),\n * take(5),\n * );\n * source$.pipe(pipeline).subscribe(console.log);\n */\nexport function flow<A, B>(op1: Operator<A, B>): Operator<A, B>;\nexport function flow<A, B, C>(op1: Operator<A, B>, op2: Operator<B, C>): Operator<A, C>;\nexport function flow<A, B, C, D>(op1: Operator<A, B>, op2: Operator<B, C>, op3: Operator<C, D>): Operator<A, D>;\nexport function flow<A, B, C, D, E>(\n op1: Operator<A, B>,\n op2: Operator<B, C>,\n op3: Operator<C, D>,\n op4: Operator<D, E>,\n): Operator<A, E>;\nexport function flow<A, B, C, D, E, F>(\n op1: Operator<A, B>,\n op2: Operator<B, C>,\n op3: Operator<C, D>,\n op4: Operator<D, E>,\n op5: Operator<E, F>,\n): Operator<A, F>;\nexport function flow<A, B, C, D, E, F, G>(\n op1: Operator<A, B>,\n op2: Operator<B, C>,\n op3: Operator<C, D>,\n op4: Operator<D, E>,\n op5: Operator<E, F>,\n op6: Operator<F, G>,\n): Operator<A, G>;\nexport function flow<A, B, C, D, E, F, G, H>(\n op1: Operator<A, B>,\n op2: Operator<B, C>,\n op3: Operator<C, D>,\n op4: Operator<D, E>,\n op5: Operator<E, F>,\n op6: Operator<F, G>,\n op7: Operator<G, H>,\n): Operator<A, H>;\nexport function flow<A, B, C, D, E, F, G, H, I>(\n op1: Operator<A, B>,\n op2: Operator<B, C>,\n op3: Operator<C, D>,\n op4: Operator<D, E>,\n op5: Operator<E, F>,\n op6: Operator<F, G>,\n op7: Operator<G, H>,\n op8: Operator<H, I>,\n): Operator<A, I>;\nexport function flow(...ops: Operator[]): Operator {\n return (source: Flux<unknown>) => ops.reduce((f: Flux<unknown>, op) => op(f), source);\n}\n"],"mappings":"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"}
|
package/dist/subject.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
const e=require("./_dev.cjs"),t=require("./_iterator.cjs"),n=require("./_pipe.cjs"),r=require("./_numeric.cjs");var i=()=>{};function a(){let t=new AbortController,n=new Set;function r(t){for(let r of[...n])try{t(r)}catch(t){e.error(`Subscriber threw during broadcast`,t)}}function a(e,r){let a=typeof e==`function`?{next:e}:e;if(t.signal.aborted||r?.aborted){try{a.complete?.()}catch{}return i}n.add(a);let o=()=>{n.delete(a),r&&r.removeEventListener(`abort`,o)};return r&&r.addEventListener(`abort`,o,{once:!0}),o}return{ac:t,broadcast:r,doSubscribe:a,subscribers:n}}function o(e,t,n,r){let a=typeof n==`function`?{next:n}:n;if(e.ac.signal.aborted||r?.aborted){try{a.complete?.()}catch{}return i}if(t(),e.ac.signal.aborted){try{a.complete?.()}catch{}return i}return e.doSubscribe(a,r)}function s(e){return()=>{e.ac.signal.aborted||(e.ac.abort(),e.broadcast(e=>e.complete?.()),e.subscribers.clear())}}function c(e){return t=>{e.ac.signal.aborted||(e.ac.abort(),e.broadcast(e=>e.error?.(t)),e.subscribers.clear())}}function l(){let e=a(),r=s(e),i={complete:r,get disposalSignal(){return e.ac.signal},dispose:r,get disposed(){return e.ac.signal.aborted},emit(t){e.ac.signal.aborted||e.broadcast(e=>e.next(t))},fail:c(e),pipe:n.makePipe(()=>i),subscribe(t,n){return e.doSubscribe(t,n)},[Symbol.asyncIterator](){return t.makeAsyncIterator(t=>e.doSubscribe(t))},[Symbol.dispose](){r()}};return i}function u(r){let i=a(),l=s(i),u=c(i),d=r,f={complete:l,get disposalSignal(){return i.ac.signal},dispose:l,get disposed(){return i.ac.signal.aborted},emit(e){i.ac.signal.aborted||(d=e,i.broadcast(t=>t.next(e)))},fail:u,pipe:n.makePipe(()=>f),subscribe(t,n){return o(i,()=>{let n=typeof t==`function`?{next:t}:t;try{n.next(d)}catch(t){e.error(`BehaviorSubject: subscriber threw during initial replay`,t)}},t,n)},[Symbol.asyncIterator](){return t.makeAsyncIterator(t=>o(i,()=>{try{t.next(d)}catch(t){e.error(`BehaviorSubject: subscriber threw during initial replay`,t)}},t))},[Symbol.dispose](){l()},get value(){return d}};return f}function d(i){let l=a(),u=s(l),d=c(l),{clamped:f,value:p}=r.clampPositiveInt(i),m=[];f&&e.warn(`createReplaySubject: bufferSize must be a finite integer >= 1, got ${i} — clamped to ${p}`);let h={get buffer(){return m},complete:u,get disposalSignal(){return l.ac.signal},dispose:u,get disposed(){return l.ac.signal.aborted},emit(e){l.ac.signal.aborted||(m.length>=p&&m.shift(),m.push(e),l.broadcast(t=>t.next(e)))},fail:d,pipe:n.makePipe(()=>h),subscribe(t,n){return o(l,()=>{let n=typeof t==`function`?{next:t}:t;for(let t of m)try{n.next(t)}catch(t){e.error(`ReplaySubject: subscriber threw during replay`,t)}},t,n)},[Symbol.asyncIterator](){return t.makeAsyncIterator(t=>o(l,()=>{for(let n of m)try{t.next(n)}catch(t){e.error(`ReplaySubject: subscriber threw during replay`,t)}},t))},[Symbol.dispose](){u()}};return h}exports.createBehaviorSubject=u,exports.createReplaySubject=d,exports.createSubject=l;
|
|
2
|
+
//# sourceMappingURL=subject.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject.cjs","names":[],"sources":["../src/subject.ts"],"sourcesContent":["import type { Flux, Observer, Unsubscribe } from './types';\n\nimport { error, warn } from './_dev';\nimport { makeAsyncIterator } from './_iterator';\nimport { clampPositiveInt } from './_numeric';\nimport { makePipe } from './_pipe';\n\nconst NOOP: Unsubscribe = () => {};\n\n/**\n * A `Subject` is both a `Flux` and a manual emission handle.\n * Calling `emit()` pushes a value to all active subscribers.\n *\n * A Subject is hot — all subscribers share the same emission sequence.\n * Subscribers that subscribe after an emission will NOT receive past values.\n * Use `BehaviorSubject` to replay the latest value to late subscribers.\n */\nexport interface Subject<T> extends Flux<T> {\n /** `true` after `dispose()` or `complete()` is called. */\n readonly disposed: boolean;\n /** Emit a complete signal to all subscribers and dispose the subject. */\n complete(): void;\n /** Push a value to all active subscribers. */\n emit(value: T): void;\n /** Push an error to all active subscribers and dispose the subject. */\n fail(err: unknown): void;\n}\n\n/**\n * A `BehaviorSubject` is a `Subject` that replays the latest value to\n * any new subscriber immediately on subscription.\n */\nexport interface BehaviorSubject<T> extends Subject<T> {\n /** The current (latest emitted) value. */\n readonly value: T;\n}\n\n/**\n * A `ReplaySubject` is a `Subject` that replays the last N emitted values\n * to any new subscriber immediately on subscription.\n */\nexport interface ReplaySubject<T> extends Subject<T> {\n /** Snapshot of the current replay buffer (up to `bufferSize` entries). */\n readonly buffer: readonly T[];\n}\n\n// ── Shared internals ──────────────────────────────────────────────────────────\n\ninterface SubjectCore<T> {\n ac: AbortController;\n broadcast(fn: (obs: Observer<T>) => void): void;\n doSubscribe(observerOrNext: Observer<T> | ((value: T) => void), signal?: AbortSignal): Unsubscribe;\n subscribers: Set<Observer<T>>;\n}\n\nfunction makeCore<T>(): SubjectCore<T> {\n const ac = new AbortController();\n const subscribers = new Set<Observer<T>>();\n\n function broadcast(fn: (obs: Observer<T>) => void): void {\n for (const obs of [...subscribers]) {\n try {\n fn(obs);\n } catch (err) {\n error('Subscriber threw during broadcast', err);\n }\n }\n }\n\n function doSubscribe(observerOrNext: Observer<T> | ((value: T) => void), signal?: AbortSignal): Unsubscribe {\n const observer: Observer<T> = typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n\n if (ac.signal.aborted || signal?.aborted) {\n try {\n observer.complete?.();\n } catch {\n /* empty */\n }\n\n return NOOP;\n }\n\n subscribers.add(observer);\n\n const unsub = (): void => {\n subscribers.delete(observer);\n\n if (signal) signal.removeEventListener('abort', unsub);\n };\n\n if (signal) signal.addEventListener('abort', unsub, { once: true });\n\n return unsub;\n }\n\n return { ac, broadcast, doSubscribe, subscribers };\n}\n\n// Safely emit initial replay values; re-check disposed after sync replay.\nfunction replaySubscribe<T>(\n core: SubjectCore<T>,\n replay: () => void,\n observerOrNext: Observer<T> | ((value: T) => void),\n signal?: AbortSignal,\n): Unsubscribe {\n const observer: Observer<T> = typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n\n if (core.ac.signal.aborted || signal?.aborted) {\n try {\n observer.complete?.();\n } catch {\n /* empty */\n }\n\n return NOOP;\n }\n\n replay();\n\n // Re-check: the synchronous replay may have triggered a dispose.\n if (core.ac.signal.aborted) {\n try {\n observer.complete?.();\n } catch {\n /* empty */\n }\n\n return NOOP;\n }\n\n return core.doSubscribe(observer, signal);\n}\n\n/**\n * Shared `dispose()` implementation for every `Subject` variant: aborts the core,\n * notifies all active subscribers with `complete()`, and clears the subscriber set.\n * Reused instead of being copy-pasted per factory.\n * @internal\n */\nfunction makeDispose<T>(core: SubjectCore<T>): () => void {\n return () => {\n if (core.ac.signal.aborted) return;\n\n core.ac.abort();\n core.broadcast((obs) => obs.complete?.());\n core.subscribers.clear();\n };\n}\n\n/**\n * Shared `fail()` implementation for every `Subject` variant: aborts the core,\n * notifies all active subscribers with `error()`, and clears the subscriber set.\n * Reused instead of being copy-pasted per factory.\n * @internal\n */\nfunction makeFail<T>(core: SubjectCore<T>): (err: unknown) => void {\n return (err) => {\n if (core.ac.signal.aborted) return;\n\n core.ac.abort();\n core.broadcast((obs) => obs.error?.(err));\n core.subscribers.clear();\n };\n}\n\n// ── createSubject ─────────────────────────────────────────────────────────────\n\n/**\n * Creates a new `Subject<T>`.\n *\n * @example\n * const events = createSubject<string>();\n * events.subscribe((s) => console.log(s));\n * events.emit('hello');\n * events.dispose();\n */\nexport function createSubject<T>(): Subject<T> {\n const core = makeCore<T>();\n const dispose = makeDispose(core);\n const fail = makeFail(core);\n\n const subject: Subject<T> = {\n complete: dispose,\n\n get disposalSignal(): AbortSignal {\n return core.ac.signal;\n },\n\n dispose,\n\n get disposed(): boolean {\n return core.ac.signal.aborted;\n },\n\n emit(value: T): void {\n if (core.ac.signal.aborted) return;\n\n core.broadcast((obs) => obs.next(value));\n },\n\n fail,\n\n pipe: makePipe(() => subject),\n\n subscribe(observerOrNext, signal) {\n return core.doSubscribe(observerOrNext, signal);\n },\n\n [Symbol.asyncIterator](): AsyncIterableIterator<T> {\n return makeAsyncIterator<T>((obs) => core.doSubscribe(obs));\n },\n\n [Symbol.dispose](): void {\n dispose();\n },\n };\n\n return subject;\n}\n\n// ── createBehaviorSubject ─────────────────────────────────────────────────────\n\n/**\n * Creates a new `BehaviorSubject<T>` with an initial value.\n * Late subscribers immediately receive the current value on subscribe.\n *\n * @example\n * const count = createBehaviorSubject(0);\n * count.subscribe((n) => console.log(n)); // logs 0 immediately\n * count.emit(1); // logs 1\n */\nexport function createBehaviorSubject<T>(initial: T): BehaviorSubject<T> {\n const core = makeCore<T>();\n const dispose = makeDispose(core);\n const fail = makeFail(core);\n let current = initial;\n\n const subject: BehaviorSubject<T> = {\n complete: dispose,\n\n get disposalSignal(): AbortSignal {\n return core.ac.signal;\n },\n\n dispose,\n\n get disposed(): boolean {\n return core.ac.signal.aborted;\n },\n\n emit(value: T): void {\n if (core.ac.signal.aborted) return;\n\n current = value;\n core.broadcast((obs) => obs.next(value));\n },\n\n fail,\n\n pipe: makePipe(() => subject),\n\n subscribe(observerOrNext, signal) {\n return replaySubscribe(\n core,\n () => {\n const observer: Observer<T> =\n typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n\n try {\n observer.next(current);\n } catch (err) {\n error('BehaviorSubject: subscriber threw during initial replay', err);\n }\n },\n observerOrNext,\n signal,\n );\n },\n\n [Symbol.asyncIterator](): AsyncIterableIterator<T> {\n return makeAsyncIterator<T>((obs) =>\n replaySubscribe(\n core,\n () => {\n try {\n obs.next(current);\n } catch (err) {\n error('BehaviorSubject: subscriber threw during initial replay', err);\n }\n },\n obs,\n ),\n );\n },\n\n [Symbol.dispose](): void {\n dispose();\n },\n\n get value(): T {\n return current;\n },\n };\n\n return subject;\n}\n\n// ── createReplaySubject ───────────────────────────────────────────────────────\n\n/**\n * Creates a `ReplaySubject<T>` that buffers up to `bufferSize` values and\n * replays them in order to any new subscriber immediately on subscription.\n *\n * @example\n * const history = createReplaySubject<string>(3);\n * history.emit('a');\n * history.emit('b');\n * history.subscribe(console.log); // logs 'a', 'b' immediately\n */\nexport function createReplaySubject<T>(bufferSize: number): ReplaySubject<T> {\n const core = makeCore<T>();\n const dispose = makeDispose(core);\n const fail = makeFail(core);\n const { clamped, value: max } = clampPositiveInt(bufferSize);\n const buf: T[] = [];\n\n if (clamped) {\n warn(`createReplaySubject: bufferSize must be a finite integer >= 1, got ${bufferSize} — clamped to ${max}`);\n }\n\n const subject: ReplaySubject<T> = {\n get buffer(): readonly T[] {\n return buf;\n },\n\n complete: dispose,\n\n get disposalSignal(): AbortSignal {\n return core.ac.signal;\n },\n\n dispose,\n\n get disposed(): boolean {\n return core.ac.signal.aborted;\n },\n\n emit(value: T): void {\n if (core.ac.signal.aborted) return;\n\n if (buf.length >= max) buf.shift();\n\n buf.push(value);\n core.broadcast((obs) => obs.next(value));\n },\n\n fail,\n\n pipe: makePipe(() => subject),\n\n subscribe(observerOrNext, signal) {\n return replaySubscribe(\n core,\n () => {\n const observer: Observer<T> =\n typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n\n for (const v of buf) {\n try {\n observer.next(v);\n } catch (err) {\n error('ReplaySubject: subscriber threw during replay', err);\n }\n }\n },\n observerOrNext,\n signal,\n );\n },\n\n [Symbol.asyncIterator](): AsyncIterableIterator<T> {\n return makeAsyncIterator<T>((obs) =>\n replaySubscribe(\n core,\n () => {\n for (const v of buf) {\n try {\n obs.next(v);\n } catch (err) {\n error('ReplaySubject: subscriber threw during replay', err);\n }\n }\n },\n obs,\n ),\n );\n },\n\n [Symbol.dispose](): void {\n dispose();\n },\n };\n\n return subject;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type { Flux } from './types';
|
|
2
|
+
/**
|
|
3
|
+
* A `Subject` is both a `Flux` and a manual emission handle.
|
|
4
|
+
* Calling `emit()` pushes a value to all active subscribers.
|
|
5
|
+
*
|
|
6
|
+
* A Subject is hot — all subscribers share the same emission sequence.
|
|
7
|
+
* Subscribers that subscribe after an emission will NOT receive past values.
|
|
8
|
+
* Use `BehaviorSubject` to replay the latest value to late subscribers.
|
|
9
|
+
*/
|
|
10
|
+
export interface Subject<T> extends Flux<T> {
|
|
11
|
+
/** `true` after `dispose()` or `complete()` is called. */
|
|
12
|
+
readonly disposed: boolean;
|
|
13
|
+
/** Emit a complete signal to all subscribers and dispose the subject. */
|
|
14
|
+
complete(): void;
|
|
15
|
+
/** Push a value to all active subscribers. */
|
|
16
|
+
emit(value: T): void;
|
|
17
|
+
/** Push an error to all active subscribers and dispose the subject. */
|
|
18
|
+
fail(err: unknown): void;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* A `BehaviorSubject` is a `Subject` that replays the latest value to
|
|
22
|
+
* any new subscriber immediately on subscription.
|
|
23
|
+
*/
|
|
24
|
+
export interface BehaviorSubject<T> extends Subject<T> {
|
|
25
|
+
/** The current (latest emitted) value. */
|
|
26
|
+
readonly value: T;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A `ReplaySubject` is a `Subject` that replays the last N emitted values
|
|
30
|
+
* to any new subscriber immediately on subscription.
|
|
31
|
+
*/
|
|
32
|
+
export interface ReplaySubject<T> extends Subject<T> {
|
|
33
|
+
/** Snapshot of the current replay buffer (up to `bufferSize` entries). */
|
|
34
|
+
readonly buffer: readonly T[];
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Creates a new `Subject<T>`.
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* const events = createSubject<string>();
|
|
41
|
+
* events.subscribe((s) => console.log(s));
|
|
42
|
+
* events.emit('hello');
|
|
43
|
+
* events.dispose();
|
|
44
|
+
*/
|
|
45
|
+
export declare function createSubject<T>(): Subject<T>;
|
|
46
|
+
/**
|
|
47
|
+
* Creates a new `BehaviorSubject<T>` with an initial value.
|
|
48
|
+
* Late subscribers immediately receive the current value on subscribe.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* const count = createBehaviorSubject(0);
|
|
52
|
+
* count.subscribe((n) => console.log(n)); // logs 0 immediately
|
|
53
|
+
* count.emit(1); // logs 1
|
|
54
|
+
*/
|
|
55
|
+
export declare function createBehaviorSubject<T>(initial: T): BehaviorSubject<T>;
|
|
56
|
+
/**
|
|
57
|
+
* Creates a `ReplaySubject<T>` that buffers up to `bufferSize` values and
|
|
58
|
+
* replays them in order to any new subscriber immediately on subscription.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const history = createReplaySubject<string>(3);
|
|
62
|
+
* history.emit('a');
|
|
63
|
+
* history.emit('b');
|
|
64
|
+
* history.subscribe(console.log); // logs 'a', 'b' immediately
|
|
65
|
+
*/
|
|
66
|
+
export declare function createReplaySubject<T>(bufferSize: number): ReplaySubject<T>;
|
|
67
|
+
//# sourceMappingURL=subject.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject.d.ts","sourceRoot":"","sources":["../src/subject.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAyB,MAAM,SAAS,CAAC;AAS3D;;;;;;;GAOG;AACH,MAAM,WAAW,OAAO,CAAC,CAAC,CAAE,SAAQ,IAAI,CAAC,CAAC,CAAC;IACzC,0DAA0D;IAC1D,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,yEAAyE;IACzE,QAAQ,IAAI,IAAI,CAAC;IACjB,8CAA8C;IAC9C,IAAI,CAAC,KAAK,EAAE,CAAC,GAAG,IAAI,CAAC;IACrB,uEAAuE;IACvE,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAC;CAC1B;AAED;;;GAGG;AACH,MAAM,WAAW,eAAe,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IACpD,0CAA0C;IAC1C,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;CACnB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,CAAE,SAAQ,OAAO,CAAC,CAAC,CAAC;IAClD,0EAA0E;IAC1E,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC;CAC/B;AA2HD;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CA0C7C;AAID;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,CA0EvE;AAID;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,UAAU,EAAE,MAAM,GAAG,aAAa,CAAC,CAAC,CAAC,CAqF3E"}
|
package/dist/subject.js
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
import { error as e, warn as t } from "./_dev.js";
|
|
2
|
+
import { makeAsyncIterator as n } from "./_iterator.js";
|
|
3
|
+
import { makePipe as r } from "./_pipe.js";
|
|
4
|
+
import { clampPositiveInt as i } from "./_numeric.js";
|
|
5
|
+
//#region src/subject.ts
|
|
6
|
+
var a = () => {};
|
|
7
|
+
function o() {
|
|
8
|
+
let t = new AbortController(), n = /* @__PURE__ */ new Set();
|
|
9
|
+
function r(t) {
|
|
10
|
+
for (let r of [...n]) try {
|
|
11
|
+
t(r);
|
|
12
|
+
} catch (t) {
|
|
13
|
+
e("Subscriber threw during broadcast", t);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
function i(e, r) {
|
|
17
|
+
let i = typeof e == "function" ? { next: e } : e;
|
|
18
|
+
if (t.signal.aborted || r?.aborted) {
|
|
19
|
+
try {
|
|
20
|
+
i.complete?.();
|
|
21
|
+
} catch {}
|
|
22
|
+
return a;
|
|
23
|
+
}
|
|
24
|
+
n.add(i);
|
|
25
|
+
let o = () => {
|
|
26
|
+
n.delete(i), r && r.removeEventListener("abort", o);
|
|
27
|
+
};
|
|
28
|
+
return r && r.addEventListener("abort", o, { once: !0 }), o;
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
ac: t,
|
|
32
|
+
broadcast: r,
|
|
33
|
+
doSubscribe: i,
|
|
34
|
+
subscribers: n
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function s(e, t, n, r) {
|
|
38
|
+
let i = typeof n == "function" ? { next: n } : n;
|
|
39
|
+
if (e.ac.signal.aborted || r?.aborted) {
|
|
40
|
+
try {
|
|
41
|
+
i.complete?.();
|
|
42
|
+
} catch {}
|
|
43
|
+
return a;
|
|
44
|
+
}
|
|
45
|
+
if (t(), e.ac.signal.aborted) {
|
|
46
|
+
try {
|
|
47
|
+
i.complete?.();
|
|
48
|
+
} catch {}
|
|
49
|
+
return a;
|
|
50
|
+
}
|
|
51
|
+
return e.doSubscribe(i, r);
|
|
52
|
+
}
|
|
53
|
+
function c(e) {
|
|
54
|
+
return () => {
|
|
55
|
+
e.ac.signal.aborted || (e.ac.abort(), e.broadcast((e) => e.complete?.()), e.subscribers.clear());
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function l(e) {
|
|
59
|
+
return (t) => {
|
|
60
|
+
e.ac.signal.aborted || (e.ac.abort(), e.broadcast((e) => e.error?.(t)), e.subscribers.clear());
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function u() {
|
|
64
|
+
let e = o(), t = c(e), i = {
|
|
65
|
+
complete: t,
|
|
66
|
+
get disposalSignal() {
|
|
67
|
+
return e.ac.signal;
|
|
68
|
+
},
|
|
69
|
+
dispose: t,
|
|
70
|
+
get disposed() {
|
|
71
|
+
return e.ac.signal.aborted;
|
|
72
|
+
},
|
|
73
|
+
emit(t) {
|
|
74
|
+
e.ac.signal.aborted || e.broadcast((e) => e.next(t));
|
|
75
|
+
},
|
|
76
|
+
fail: l(e),
|
|
77
|
+
pipe: r(() => i),
|
|
78
|
+
subscribe(t, n) {
|
|
79
|
+
return e.doSubscribe(t, n);
|
|
80
|
+
},
|
|
81
|
+
[Symbol.asyncIterator]() {
|
|
82
|
+
return n((t) => e.doSubscribe(t));
|
|
83
|
+
},
|
|
84
|
+
[Symbol.dispose]() {
|
|
85
|
+
t();
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
return i;
|
|
89
|
+
}
|
|
90
|
+
function d(t) {
|
|
91
|
+
let i = o(), a = c(i), u = l(i), d = t, f = {
|
|
92
|
+
complete: a,
|
|
93
|
+
get disposalSignal() {
|
|
94
|
+
return i.ac.signal;
|
|
95
|
+
},
|
|
96
|
+
dispose: a,
|
|
97
|
+
get disposed() {
|
|
98
|
+
return i.ac.signal.aborted;
|
|
99
|
+
},
|
|
100
|
+
emit(e) {
|
|
101
|
+
i.ac.signal.aborted || (d = e, i.broadcast((t) => t.next(e)));
|
|
102
|
+
},
|
|
103
|
+
fail: u,
|
|
104
|
+
pipe: r(() => f),
|
|
105
|
+
subscribe(t, n) {
|
|
106
|
+
return s(i, () => {
|
|
107
|
+
let n = typeof t == "function" ? { next: t } : t;
|
|
108
|
+
try {
|
|
109
|
+
n.next(d);
|
|
110
|
+
} catch (t) {
|
|
111
|
+
e("BehaviorSubject: subscriber threw during initial replay", t);
|
|
112
|
+
}
|
|
113
|
+
}, t, n);
|
|
114
|
+
},
|
|
115
|
+
[Symbol.asyncIterator]() {
|
|
116
|
+
return n((t) => s(i, () => {
|
|
117
|
+
try {
|
|
118
|
+
t.next(d);
|
|
119
|
+
} catch (t) {
|
|
120
|
+
e("BehaviorSubject: subscriber threw during initial replay", t);
|
|
121
|
+
}
|
|
122
|
+
}, t));
|
|
123
|
+
},
|
|
124
|
+
[Symbol.dispose]() {
|
|
125
|
+
a();
|
|
126
|
+
},
|
|
127
|
+
get value() {
|
|
128
|
+
return d;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
return f;
|
|
132
|
+
}
|
|
133
|
+
function f(a) {
|
|
134
|
+
let u = o(), d = c(u), f = l(u), { clamped: p, value: m } = i(a), h = [];
|
|
135
|
+
p && t(`createReplaySubject: bufferSize must be a finite integer >= 1, got ${a} — clamped to ${m}`);
|
|
136
|
+
let g = {
|
|
137
|
+
get buffer() {
|
|
138
|
+
return h;
|
|
139
|
+
},
|
|
140
|
+
complete: d,
|
|
141
|
+
get disposalSignal() {
|
|
142
|
+
return u.ac.signal;
|
|
143
|
+
},
|
|
144
|
+
dispose: d,
|
|
145
|
+
get disposed() {
|
|
146
|
+
return u.ac.signal.aborted;
|
|
147
|
+
},
|
|
148
|
+
emit(e) {
|
|
149
|
+
u.ac.signal.aborted || (h.length >= m && h.shift(), h.push(e), u.broadcast((t) => t.next(e)));
|
|
150
|
+
},
|
|
151
|
+
fail: f,
|
|
152
|
+
pipe: r(() => g),
|
|
153
|
+
subscribe(t, n) {
|
|
154
|
+
return s(u, () => {
|
|
155
|
+
let n = typeof t == "function" ? { next: t } : t;
|
|
156
|
+
for (let t of h) try {
|
|
157
|
+
n.next(t);
|
|
158
|
+
} catch (t) {
|
|
159
|
+
e("ReplaySubject: subscriber threw during replay", t);
|
|
160
|
+
}
|
|
161
|
+
}, t, n);
|
|
162
|
+
},
|
|
163
|
+
[Symbol.asyncIterator]() {
|
|
164
|
+
return n((t) => s(u, () => {
|
|
165
|
+
for (let n of h) try {
|
|
166
|
+
t.next(n);
|
|
167
|
+
} catch (t) {
|
|
168
|
+
e("ReplaySubject: subscriber threw during replay", t);
|
|
169
|
+
}
|
|
170
|
+
}, t));
|
|
171
|
+
},
|
|
172
|
+
[Symbol.dispose]() {
|
|
173
|
+
d();
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
return g;
|
|
177
|
+
}
|
|
178
|
+
//#endregion
|
|
179
|
+
export { d as createBehaviorSubject, f as createReplaySubject, u as createSubject };
|
|
180
|
+
|
|
181
|
+
//# sourceMappingURL=subject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subject.js","names":[],"sources":["../src/subject.ts"],"sourcesContent":["import type { Flux, Observer, Unsubscribe } from './types';\n\nimport { error, warn } from './_dev';\nimport { makeAsyncIterator } from './_iterator';\nimport { clampPositiveInt } from './_numeric';\nimport { makePipe } from './_pipe';\n\nconst NOOP: Unsubscribe = () => {};\n\n/**\n * A `Subject` is both a `Flux` and a manual emission handle.\n * Calling `emit()` pushes a value to all active subscribers.\n *\n * A Subject is hot — all subscribers share the same emission sequence.\n * Subscribers that subscribe after an emission will NOT receive past values.\n * Use `BehaviorSubject` to replay the latest value to late subscribers.\n */\nexport interface Subject<T> extends Flux<T> {\n /** `true` after `dispose()` or `complete()` is called. */\n readonly disposed: boolean;\n /** Emit a complete signal to all subscribers and dispose the subject. */\n complete(): void;\n /** Push a value to all active subscribers. */\n emit(value: T): void;\n /** Push an error to all active subscribers and dispose the subject. */\n fail(err: unknown): void;\n}\n\n/**\n * A `BehaviorSubject` is a `Subject` that replays the latest value to\n * any new subscriber immediately on subscription.\n */\nexport interface BehaviorSubject<T> extends Subject<T> {\n /** The current (latest emitted) value. */\n readonly value: T;\n}\n\n/**\n * A `ReplaySubject` is a `Subject` that replays the last N emitted values\n * to any new subscriber immediately on subscription.\n */\nexport interface ReplaySubject<T> extends Subject<T> {\n /** Snapshot of the current replay buffer (up to `bufferSize` entries). */\n readonly buffer: readonly T[];\n}\n\n// ── Shared internals ──────────────────────────────────────────────────────────\n\ninterface SubjectCore<T> {\n ac: AbortController;\n broadcast(fn: (obs: Observer<T>) => void): void;\n doSubscribe(observerOrNext: Observer<T> | ((value: T) => void), signal?: AbortSignal): Unsubscribe;\n subscribers: Set<Observer<T>>;\n}\n\nfunction makeCore<T>(): SubjectCore<T> {\n const ac = new AbortController();\n const subscribers = new Set<Observer<T>>();\n\n function broadcast(fn: (obs: Observer<T>) => void): void {\n for (const obs of [...subscribers]) {\n try {\n fn(obs);\n } catch (err) {\n error('Subscriber threw during broadcast', err);\n }\n }\n }\n\n function doSubscribe(observerOrNext: Observer<T> | ((value: T) => void), signal?: AbortSignal): Unsubscribe {\n const observer: Observer<T> = typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n\n if (ac.signal.aborted || signal?.aborted) {\n try {\n observer.complete?.();\n } catch {\n /* empty */\n }\n\n return NOOP;\n }\n\n subscribers.add(observer);\n\n const unsub = (): void => {\n subscribers.delete(observer);\n\n if (signal) signal.removeEventListener('abort', unsub);\n };\n\n if (signal) signal.addEventListener('abort', unsub, { once: true });\n\n return unsub;\n }\n\n return { ac, broadcast, doSubscribe, subscribers };\n}\n\n// Safely emit initial replay values; re-check disposed after sync replay.\nfunction replaySubscribe<T>(\n core: SubjectCore<T>,\n replay: () => void,\n observerOrNext: Observer<T> | ((value: T) => void),\n signal?: AbortSignal,\n): Unsubscribe {\n const observer: Observer<T> = typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n\n if (core.ac.signal.aborted || signal?.aborted) {\n try {\n observer.complete?.();\n } catch {\n /* empty */\n }\n\n return NOOP;\n }\n\n replay();\n\n // Re-check: the synchronous replay may have triggered a dispose.\n if (core.ac.signal.aborted) {\n try {\n observer.complete?.();\n } catch {\n /* empty */\n }\n\n return NOOP;\n }\n\n return core.doSubscribe(observer, signal);\n}\n\n/**\n * Shared `dispose()` implementation for every `Subject` variant: aborts the core,\n * notifies all active subscribers with `complete()`, and clears the subscriber set.\n * Reused instead of being copy-pasted per factory.\n * @internal\n */\nfunction makeDispose<T>(core: SubjectCore<T>): () => void {\n return () => {\n if (core.ac.signal.aborted) return;\n\n core.ac.abort();\n core.broadcast((obs) => obs.complete?.());\n core.subscribers.clear();\n };\n}\n\n/**\n * Shared `fail()` implementation for every `Subject` variant: aborts the core,\n * notifies all active subscribers with `error()`, and clears the subscriber set.\n * Reused instead of being copy-pasted per factory.\n * @internal\n */\nfunction makeFail<T>(core: SubjectCore<T>): (err: unknown) => void {\n return (err) => {\n if (core.ac.signal.aborted) return;\n\n core.ac.abort();\n core.broadcast((obs) => obs.error?.(err));\n core.subscribers.clear();\n };\n}\n\n// ── createSubject ─────────────────────────────────────────────────────────────\n\n/**\n * Creates a new `Subject<T>`.\n *\n * @example\n * const events = createSubject<string>();\n * events.subscribe((s) => console.log(s));\n * events.emit('hello');\n * events.dispose();\n */\nexport function createSubject<T>(): Subject<T> {\n const core = makeCore<T>();\n const dispose = makeDispose(core);\n const fail = makeFail(core);\n\n const subject: Subject<T> = {\n complete: dispose,\n\n get disposalSignal(): AbortSignal {\n return core.ac.signal;\n },\n\n dispose,\n\n get disposed(): boolean {\n return core.ac.signal.aborted;\n },\n\n emit(value: T): void {\n if (core.ac.signal.aborted) return;\n\n core.broadcast((obs) => obs.next(value));\n },\n\n fail,\n\n pipe: makePipe(() => subject),\n\n subscribe(observerOrNext, signal) {\n return core.doSubscribe(observerOrNext, signal);\n },\n\n [Symbol.asyncIterator](): AsyncIterableIterator<T> {\n return makeAsyncIterator<T>((obs) => core.doSubscribe(obs));\n },\n\n [Symbol.dispose](): void {\n dispose();\n },\n };\n\n return subject;\n}\n\n// ── createBehaviorSubject ─────────────────────────────────────────────────────\n\n/**\n * Creates a new `BehaviorSubject<T>` with an initial value.\n * Late subscribers immediately receive the current value on subscribe.\n *\n * @example\n * const count = createBehaviorSubject(0);\n * count.subscribe((n) => console.log(n)); // logs 0 immediately\n * count.emit(1); // logs 1\n */\nexport function createBehaviorSubject<T>(initial: T): BehaviorSubject<T> {\n const core = makeCore<T>();\n const dispose = makeDispose(core);\n const fail = makeFail(core);\n let current = initial;\n\n const subject: BehaviorSubject<T> = {\n complete: dispose,\n\n get disposalSignal(): AbortSignal {\n return core.ac.signal;\n },\n\n dispose,\n\n get disposed(): boolean {\n return core.ac.signal.aborted;\n },\n\n emit(value: T): void {\n if (core.ac.signal.aborted) return;\n\n current = value;\n core.broadcast((obs) => obs.next(value));\n },\n\n fail,\n\n pipe: makePipe(() => subject),\n\n subscribe(observerOrNext, signal) {\n return replaySubscribe(\n core,\n () => {\n const observer: Observer<T> =\n typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n\n try {\n observer.next(current);\n } catch (err) {\n error('BehaviorSubject: subscriber threw during initial replay', err);\n }\n },\n observerOrNext,\n signal,\n );\n },\n\n [Symbol.asyncIterator](): AsyncIterableIterator<T> {\n return makeAsyncIterator<T>((obs) =>\n replaySubscribe(\n core,\n () => {\n try {\n obs.next(current);\n } catch (err) {\n error('BehaviorSubject: subscriber threw during initial replay', err);\n }\n },\n obs,\n ),\n );\n },\n\n [Symbol.dispose](): void {\n dispose();\n },\n\n get value(): T {\n return current;\n },\n };\n\n return subject;\n}\n\n// ── createReplaySubject ───────────────────────────────────────────────────────\n\n/**\n * Creates a `ReplaySubject<T>` that buffers up to `bufferSize` values and\n * replays them in order to any new subscriber immediately on subscription.\n *\n * @example\n * const history = createReplaySubject<string>(3);\n * history.emit('a');\n * history.emit('b');\n * history.subscribe(console.log); // logs 'a', 'b' immediately\n */\nexport function createReplaySubject<T>(bufferSize: number): ReplaySubject<T> {\n const core = makeCore<T>();\n const dispose = makeDispose(core);\n const fail = makeFail(core);\n const { clamped, value: max } = clampPositiveInt(bufferSize);\n const buf: T[] = [];\n\n if (clamped) {\n warn(`createReplaySubject: bufferSize must be a finite integer >= 1, got ${bufferSize} — clamped to ${max}`);\n }\n\n const subject: ReplaySubject<T> = {\n get buffer(): readonly T[] {\n return buf;\n },\n\n complete: dispose,\n\n get disposalSignal(): AbortSignal {\n return core.ac.signal;\n },\n\n dispose,\n\n get disposed(): boolean {\n return core.ac.signal.aborted;\n },\n\n emit(value: T): void {\n if (core.ac.signal.aborted) return;\n\n if (buf.length >= max) buf.shift();\n\n buf.push(value);\n core.broadcast((obs) => obs.next(value));\n },\n\n fail,\n\n pipe: makePipe(() => subject),\n\n subscribe(observerOrNext, signal) {\n return replaySubscribe(\n core,\n () => {\n const observer: Observer<T> =\n typeof observerOrNext === 'function' ? { next: observerOrNext } : observerOrNext;\n\n for (const v of buf) {\n try {\n observer.next(v);\n } catch (err) {\n error('ReplaySubject: subscriber threw during replay', err);\n }\n }\n },\n observerOrNext,\n signal,\n );\n },\n\n [Symbol.asyncIterator](): AsyncIterableIterator<T> {\n return makeAsyncIterator<T>((obs) =>\n replaySubscribe(\n core,\n () => {\n for (const v of buf) {\n try {\n obs.next(v);\n } catch (err) {\n error('ReplaySubject: subscriber threw during replay', err);\n }\n }\n },\n obs,\n ),\n );\n },\n\n [Symbol.dispose](): void {\n dispose();\n },\n };\n\n return subject;\n}\n"],"mappings":"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"}
|