nanoeffects 0.4.0 → 0.6.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 (60) hide show
  1. package/README.md +4 -1
  2. package/dist/{action-creator-D48fp13T.d.ts → action-creator-c292nK7v.d.ts} +130 -34
  3. package/dist/actions.d.ts +54 -5
  4. package/dist/actions.js +1 -1
  5. package/dist/{bus-Cho463Sq.js → bus-BAs9x7IQ.js} +1 -1
  6. package/dist/{context-DlA80GOA.js → context-CK0ZomWt.js} +1 -1
  7. package/dist/context-plugin-1pYmSQEG.d.ts +34 -0
  8. package/dist/dev.d.ts +2 -2
  9. package/dist/effects.d.ts +27 -129
  10. package/dist/effects.js +1 -1
  11. package/dist/index.d.ts +3 -2
  12. package/dist/index.js +1 -1
  13. package/dist/{module-DVX8aYlq.d.ts → module-BlF2KSgy.d.ts} +34 -5
  14. package/dist/notrace/{action-creator-D48fp13T.d.ts → action-creator-DKG_sIia.d.ts} +130 -34
  15. package/dist/notrace/actions.d.ts +96 -7
  16. package/dist/notrace/actions.js +1 -1
  17. package/dist/notrace/{bus-B12SvxLv.js → bus-Bdk0YyFQ.js} +1 -1
  18. package/dist/notrace/{context-yAWj0BFZ.js → context-CctVmHLC.js} +1 -1
  19. package/dist/notrace/context-plugin-Dt1IgVo8.d.ts +34 -0
  20. package/dist/notrace/{delay-Cgvn16oY.js → delay-B_W1tnkS.js} +1 -1
  21. package/dist/notrace/effects.d.ts +27 -129
  22. package/dist/notrace/effects.js +1 -1
  23. package/dist/notrace/index.d.ts +3 -2
  24. package/dist/notrace/index.js +1 -1
  25. package/dist/notrace/plugin-B0AXKusc.d.ts +207 -0
  26. package/dist/notrace/policies.d.ts +1 -1
  27. package/dist/notrace/policies.js +1 -1
  28. package/dist/notrace/redux.d.ts +18 -20
  29. package/dist/notrace/redux.js +1 -1
  30. package/dist/observable.d.ts +1 -1
  31. package/dist/plugin-CCYlC0XS.d.ts +207 -0
  32. package/dist/policies.d.ts +1 -1
  33. package/dist/policies.js +1 -1
  34. package/dist/react.d.ts +50 -0
  35. package/dist/react.js +1 -0
  36. package/dist/redux.d.ts +18 -20
  37. package/dist/redux.js +1 -1
  38. package/dist/scope-key-B7l7mUS5.js +1 -0
  39. package/dist/scope.d.ts +58 -0
  40. package/dist/scope.js +1 -0
  41. package/dist/trace.d.ts +1 -1
  42. package/dist/types-mLaAx-EZ.d.ts +15 -0
  43. package/docs/README.md +7 -1
  44. package/docs/actions.md +25 -1
  45. package/docs/context.md +26 -2
  46. package/docs/effects.md +83 -5
  47. package/docs/guide.md +24 -0
  48. package/docs/migrating-from-effector.md +293 -0
  49. package/docs/migrating-from-rxjs.md +127 -0
  50. package/docs/migrating-from-saga.md +93 -0
  51. package/docs/observable.md +1 -0
  52. package/docs/package.md +13 -2
  53. package/docs/policies.md +1 -0
  54. package/docs/react.md +157 -0
  55. package/docs/scope.md +226 -0
  56. package/docs/stores.md +429 -40
  57. package/docs/typescript.md +153 -0
  58. package/llms-full.txt +2925 -0
  59. package/llms.txt +49 -0
  60. package/package.json +44 -6
@@ -0,0 +1,34 @@
1
+ import { R as EventMap, j as WithContext, p as Bus, y as ContextOf } from "./action-creator-DKG_sIia.js";
2
+ //#region src/core/context-plugin.d.ts
3
+ /** What a function that makes the fields of a task gets to see. */
4
+ type ContextTask = {
5
+ type: string;
6
+ payload?: unknown;
7
+ };
8
+ /**
9
+ * `unknown` when none of the `fields` is already a context field of the bus,
10
+ * else `never`: the call does not compile. Used as `bus: Bus<E> & NoClash<…>`.
11
+ */
12
+ type NoClash<Fields extends object, E extends EventMap> = [keyof Fields & keyof ContextOf<E>] extends [never] ? unknown : never;
13
+ /**
14
+ * Puts `fields` on the context of every task of the bus: a store, a client, a
15
+ * logger. The types come from the value, so the event map needs no
16
+ * `WithContext`. Returns the same bus, typed with the fields. A function gets
17
+ * `{ type, payload }` of the task and returns its fields.
18
+ *
19
+ * Several uses merge with each other, with the `context` option of `createBus`
20
+ * and with `effectsPlugin`. A name that the bus already has is a type error. The
21
+ * fields of the library (`signal`, `emit`, `run`, …) win, and a field that the
22
+ * context already has is not replaced.
23
+ *
24
+ * @example
25
+ * ```ts
26
+ * type Events = { "user/loaded": User };
27
+ *
28
+ * const bus = createBus<Events>().use(contextPlugin({ store }));
29
+ * bus.on("user/loaded", (user, { store }) => store.put(user)); // ctx.store: Store
30
+ * ```
31
+ */
32
+ declare const contextPlugin: <Fields extends object>(fields: Fields | ((task: ContextTask) => Fields)) => <E extends EventMap>(bus: Bus<E> & NoClash<Fields, E>) => Bus<E & WithContext<Fields>>;
33
+ //#endregion
34
+ export { NoClash as n, contextPlugin as r, ContextTask as t };
@@ -1 +1 @@
1
- import{s as e}from"./context-yAWj0BFZ.js";const t=2**31-1,n=(e,n)=>{let r={id:null};if(n===1/0)return r;let i=n=>{r.id=setTimeout(()=>{n>t?i(n-t):(r.id=null,e())},Math.min(n,t))};return i(n>0?n:0),r},r=e=>{e.id!==null&&(clearTimeout(e.id),e.id=null)},i=(t,i)=>new Promise((a,o)=>{let s=n(()=>{c(),a()},typeof i==`function`?i():i),c=e(t,e=>{r(s),o(e)})});export{r as n,n as r,i as t};
1
+ import{s as e}from"./context-CctVmHLC.js";const t=2**31-1,n=(e,n)=>{let r={id:null};if(n===1/0)return r;let i=n=>{r.id=setTimeout(()=>{n>t?i(n-t):(r.id=null,e())},Math.min(n,t))};return i(n>0?n:0),r},r=e=>{e.id!==null&&(clearTimeout(e.id),e.id=null)},i=(t,i)=>new Promise((a,o)=>{let s=n(()=>{c(),a()},typeof i==`function`?i():i),c=e(t,e=>{r(s),o(e)})});export{r as n,n as r,i as t};
@@ -1,89 +1,41 @@
1
- import { S as Context, o as EventMap, s as Keys, u as Task } from "./action-creator-D48fp13T.js";
2
- //#region src/utils/delay.d.ts
3
- /**
4
- * Resolves after `ms`, or rejects early if `ctx.signal` aborts. `ms` can be a
5
- * function that returns the number of ms, called once when the delay starts:
6
- * handy for a random pause (jitter).
7
- *
8
- * @example
9
- * ```ts
10
- * await delay({}, 500);
11
- *
12
- * // 200 to 400 ms
13
- * await delay({}, () => 200 + Math.random() * 200);
14
- *
15
- * // inside a task: stops waiting when the task is aborted
16
- * bus.on("retry", async (_, ctx) => {
17
- * await delay(ctx, 1000);
18
- * await load();
19
- * });
20
- * ```
21
- */
22
- export declare const delay: (ctx: {
23
- signal?: AbortSignal | undefined;
24
- }, ms: number | (() => number)) => Promise<void>;
25
- //#endregion
1
+ import { H as Task, R as EventMap, l as Effect } from "./action-creator-DKG_sIia.js";
2
+ import { a as RaceStarter, c as all, d as delay, i as take, l as EffectContext, n as effectsPlugin, o as race, r as TakeOptions, s as allSettled, u as Starter } from "./plugin-B0AXKusc.js";
26
3
  //#region src/utils/onAbort.d.ts
27
4
  export declare const onAbort: (ctx: {
28
5
  signal?: AbortSignal | undefined;
29
6
  }, fn: (reason: unknown) => void) => (() => void);
30
7
  //#endregion
31
- //#region src/effects/run.d.ts
32
- /** Context passed into `race` / `all` effect starters. */
33
- type EffectContext = {
34
- signal: AbortSignal;
35
- abort: (reason?: unknown) => void;
8
+ //#region src/effects/backoff.d.ts
9
+ type BackoffOptions = {
10
+ /** Pause before the second attempt, in ms. Default 100. */
11
+ base?: number;
12
+ /** How many times each pause is longer than the one before. Default 2. */
13
+ factor?: number;
14
+ /** Longest pause, in ms. Default `Infinity`. */
15
+ max?: number;
16
+ /**
17
+ * Use a random pause from 0 up to the computed one ("full jitter"), so
18
+ * clients that failed together do not retry together. Default `false`.
19
+ */
20
+ jitter?: boolean;
36
21
  };
37
- type Starter<T> = (ctx: EffectContext) => T | PromiseLike<T>;
38
- //#endregion
39
- //#region src/effects/all.d.ts
40
22
  /**
41
- * Runs all starters; waits for every result. On failure or parent abort, cancels the rest.
23
+ * Builds the `delay` of `retry`: the pause grows as `base * factor ** (attempt - 1)`
24
+ * and never passes `max`. `retry` counts attempts from 1; `poll` counts calls from
25
+ * 0, so there the first pause is `base / factor`.
42
26
  *
43
27
  * @example
44
28
  * ```ts
45
- * bus.on("load", async (id, ctx) => {
46
- * const { user, posts } = await all(ctx, {
47
- * user: ({ signal }) => fetchUser(id, { signal }),
48
- * posts: ({ signal }) => fetchPosts(id, { signal }),
49
- * });
50
- *
51
- * // arrays work too: const [user, posts] = await all(ctx, [getUser, getPosts]);
52
- * });
53
- * ```
54
- */
55
- export declare function all<T extends Record<string, Starter<unknown>>>(ctx: {
56
- signal?: AbortSignal;
57
- }, effects: T): Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
58
- export declare function all<const T extends readonly Starter<unknown>[]>(ctx: {
59
- signal?: AbortSignal;
60
- }, effects: T): Promise<{ -readonly [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
61
- //#endregion
62
- //#region src/effects/allSettled.d.ts
63
- /**
64
- * Runs all starters and waits for every one to settle, whether it succeeds or
65
- * fails: nothing is cancelled when a starter fails. The result has, for each
66
- * starter, `{ status: "fulfilled", value }` or `{ status: "rejected", reason }`.
67
- * Only an abort of `ctx` rejects it, with the abort reason.
68
- *
69
- * @example
70
- * ```ts
71
- * bus.on("load", async (id, ctx) => {
72
- * const { user, posts } = await allSettled(ctx, {
73
- * user: ({ signal }) => fetchUser(id, { signal }),
74
- * posts: ({ signal }) => fetchPosts(id, { signal }),
75
- * });
76
- *
77
- * if (user.status === "fulfilled") render(user.value);
78
- * });
29
+ * bus.on(
30
+ * "load",
31
+ * retry(loadUser, {
32
+ * times: 5,
33
+ * delay: backoff({ base: 200, max: 5000, jitter: true }), // 200, 400, 800, ... up to 5 s, randomised
34
+ * }),
35
+ * );
79
36
  * ```
80
37
  */
81
- export declare function allSettled<T extends Record<string, Starter<unknown>>>(ctx: {
82
- signal?: AbortSignal;
83
- }, effects: T): Promise<{ [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
84
- export declare function allSettled<const T extends readonly Starter<unknown>[]>(ctx: {
85
- signal?: AbortSignal;
86
- }, effects: T): Promise<{ -readonly [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
38
+ export declare const backoff: (options?: BackoffOptions) => (attempt: number) => number;
87
39
  //#endregion
88
40
  //#region src/effects/cancellable.d.ts
89
41
  type CancellableHandle<T> = {
@@ -160,32 +112,6 @@ export declare function poll(ctx: {
160
112
  signal: AbortSignal;
161
113
  }, fn: (tick: number) => unknown, ms: PollMs, options?: PollOptions): Promise<void>;
162
114
  //#endregion
163
- //#region src/effects/race.d.ts
164
- type RaceStarter<T> = Starter<T>;
165
- /**
166
- * Runs all starters; first to settle wins, losers are cancelled via `ctx.abort`.
167
- * The result holds only the winner's value, under its key or index.
168
- *
169
- * @example
170
- * ```ts
171
- * bus.on("load", async (id, ctx) => {
172
- * const result = await race(ctx, {
173
- * data: ({ signal }) => fetchData(id, { signal }),
174
- * timeout: ({ signal }) => delay({ signal }, 5000),
175
- * });
176
- *
177
- * if ("timeout" in result) throw new Error("timed out");
178
- * render(result.data);
179
- * });
180
- * ```
181
- */
182
- export declare function race<T extends Record<string, RaceStarter<unknown>>>(ctx: {
183
- signal?: AbortSignal;
184
- }, effects: T): Promise<{ [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
185
- export declare function race<const T extends readonly RaceStarter<unknown>[]>(ctx: {
186
- signal?: AbortSignal;
187
- }, effects: T): Promise<{ -readonly [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
188
- //#endregion
189
115
  //#region src/effects/retry.d.ts
190
116
  type RetryOptions = {
191
117
  /** Total number of attempts, the first one included. Default 3. */
@@ -226,34 +152,6 @@ export declare function retry<T>(ctx: {
226
152
  signal?: AbortSignal;
227
153
  }, fn: RetryFn<T>, options?: RetryOptions): Promise<T>;
228
154
  //#endregion
229
- //#region src/effects/take.d.ts
230
- type TakeOptions<P> = {
231
- /** Wait for the first payload this accepts; others are skipped. */
232
- predicate?: (payload: P) => boolean;
233
- /** Stop waiting when this aborts, e.g. the signal of a `race` starter. */
234
- signal?: AbortSignal | undefined;
235
- };
236
- /**
237
- * Waits for the next `event` on the bus and resolves with its payload. It sees
238
- * only events emitted after the call, takes only one, and unsubscribes when it
239
- * is done. If `ctx` (or `options.signal`) aborts first, it unsubscribes and
240
- * rejects with the abort reason.
241
- *
242
- * @example
243
- * ```ts
244
- * bus.on("login", async (user, ctx) => {
245
- * const reason = await take(ctx, "logout");
246
- * cleanup(user, reason);
247
- * });
248
- *
249
- * // wait for a matching event, but not longer than 5 s
250
- * const done = await timeout(ctx, 5000, ({ signal }) =>
251
- * take(ctx, "saved", { signal, predicate: (id) => id === draftId }),
252
- * );
253
- * ```
254
- */
255
- export declare const take: <E extends EventMap, K extends Keys<E>>(ctx: Context<E>, event: K, options?: TakeOptions<E[K]>) => Promise<E[K]>;
256
- //#endregion
257
155
  //#region src/effects/timeout.d.ts
258
156
  /**
259
157
  * Runs a function; if it takes longer than `ms`, aborts its signal and rejects
@@ -281,4 +179,4 @@ export declare function timeout<T>(ctx: {
281
179
  signal?: AbortSignal;
282
180
  }, ms: number, starter: Starter<T>): Promise<T>;
283
181
  //#endregion
284
- export type { CancellableExecutor, CancellableHandle, EffectContext, PollOptions, RaceStarter, RetryOptions, TakeOptions };
182
+ export { type BackoffOptions, type CancellableExecutor, type CancellableHandle, type Effect, type EffectContext, type PollOptions, type RaceStarter, type RetryOptions, type TakeOptions, all, allSettled, delay, effectsPlugin, race, take };
@@ -1 +1 @@
1
- import{a as e,c as t,i as n,o as r,s as i,t as a}from"./context-yAWj0BFZ.js";import{n as o,r as s,t as c}from"./delay-Cgvn16oY.js";const l=(e,t)=>t?.signal?new Promise((n,r)=>{let a=i(t,r);e.then(n,r).finally(a)}):e,u=async(e,t,o,s)=>{t?.signal?.throwIfAborted();let{ctx:c,unlink:u}=n(t??{}),d=a(c,e);r(c,e,`start`),i(c,()=>d(`cancel`));try{let e=await l(o(c),t);return d(`done`),s?.(!1),e}catch(e){throw d(`error`,e),s?.(!0),e}finally{u()}},d=async(t,r)=>{let{ctx:i,unlink:a}=n(t);try{return await e(i,`run`,()=>r(i))}finally{a()}},f=e=>e,p=(e,t)=>n=>e(t,f(n)),m=e=>Array.isArray(e)?Array(e.length):{},h=(t,r)=>{let i=Object.entries(r).map(([r,i])=>{let a=n(t),o={signal:a.ctx.signal,abort:a.ctx.abort},s=()=>i(o);return{key:r,task:new Promise(t=>t(e(a.ctx,`run`,s))).finally(a.unlink),cancel:a.ctx.abort}});return{tasks:i.map(({key:e,task:t})=>[e,t]),cancelAll:()=>{for(let e of i)e.cancel()}}},g=(e,t,n,r,i)=>{let a=()=>{};return u(e,t,async e=>{let t=h(e,n);return a=t.cancelAll,r(t.tasks)},e=>{(e||i===`end`)&&a()})};function _(e,t){return g(`all`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>e)),r=m(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`)}const v=e=>e.then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}));function y(e,t){return g(`allSettled`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>v(e))),r=m(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`)}const b=(e,n)=>e.signal.aborted?Promise.reject(e.signal.reason):new Promise((r,a)=>{let o=[],s=`pending`,c=e=>{try{e()}catch(e){t(`cancel cleanup failed`,e)}},l=i(e,e=>{s=`cancelled`;for(let e of o.reverse())c(e);a(e)}),u=e=>(...t)=>{s===`pending`&&(s=`settled`,l(),o.length=0,e(...t))},d=e=>{s===`pending`?o.push(e):s===`cancelled`&&c(e)};try{n({resolve:u(r),reject:u(a),onCancel:d})}catch(e){u(a)(e)}}),x=(e,t,n,r)=>{if(e.signal.aborted)return Promise.resolve();let a=r.leading??!1,c=r.waitForFn??!1;return u(`poll`,e,e=>new Promise((r,l)=>{let u=0,f=null,p=()=>{f!==null&&(o(f),f=null)},m=e=>{try{f=s(h,typeof n==`function`?n(e):n)}catch(e){p(),l(e)}},h=()=>{f=null,c||m(u+1),g()},g=()=>{let n=u++;d(e,e=>t(e,n)).then(()=>{c&&!e.signal.aborted&&m(u)},e=>{p(),l(e)})};i(e,p),a?(g(),c||m(u)):m(0)})).catch(t=>{if(!e.signal.aborted)throw t})};function S(e,t,n,r={}){if(typeof e!=`object`){let r=t,i=n??{};return(t,n)=>x(n,p(r,t),e,i)}let i=t;return x(e,(e,t)=>i(t),n,r)}function C(e,t){let n=m(t);return Object.keys(t).length===0?Promise.resolve(n):g(`race`,e,t,async e=>{let[t,r]=await Promise.race(e.map(([e,t])=>t.then(t=>[e,t])));return n[t]=r,n},`end`)}const w=(e,t,n)=>typeof e==`function`?e(t,n):e,T=e=>({times:e.times??3,delay:e.delay??0,shouldRetry:e.shouldRetry??(()=>!0)}),E=(e,t,n)=>u(`retry`,e,async e=>{let{times:r,delay:i,shouldRetry:a}=T(n);for(let n=1;;n++)try{return await d(e,e=>t(e,n))}catch(t){if(e.signal.throwIfAborted(),n>=r||!a(t,n))throw t;let o=w(i,n,t);o>0&&await c(e,o)}});function D(e,t,n={}){if(typeof e==`function`){let n=e;return(e,r)=>E(r,p(n,e),t??{})}let r=t;return E(e,(e,t)=>r(t),n)}const O=(e,t,n={})=>u(`take`,e,r=>new Promise((a,o)=>{let{predicate:s}=n,c=[],l=()=>{for(let e of c)e()},u=e=>{l(),o(e)};c.push(e.on(t,e=>{(!s||s(e))&&(l(),a(e))})),c.push(i(r,u)),c.push(i({signal:n.signal},u))})),k=(t,r,i)=>u(`timeout`,t,async t=>{let a=n(t),c=s(()=>a.ctx.abort(new DOMException(`Timed out after ${r}ms`,`TimeoutError`)),r);try{return await l(Promise.resolve(e(a.ctx,`run`,()=>i(a.ctx))),a.ctx)}finally{o(c),a.unlink()}});function A(e,t,n){if(typeof e==`number`){let n=t;return(t,r)=>k(r,e,p(n,t))}let r=t,i=n;return k(e,r,e=>i({signal:e.signal,abort:e.abort}))}export{_ as all,y as allSettled,b as cancellable,c as delay,i as onAbort,S as poll,C as race,D as retry,O as take,A as timeout};
1
+ import{a as e,c as t,i as n,o as r,s as i,t as a}from"./context-CctVmHLC.js";import{n as o,r as s,t as c}from"./delay-B_W1tnkS.js";const l=(e,t)=>t?.signal?new Promise((n,r)=>{let a=i(t,r);e.then(n,r).finally(a)}):e,u=async(e,t,o,s)=>{t?.signal?.throwIfAborted();let{ctx:c,unlink:u}=n(t??{}),d=a(c,e);r(c,e,`start`),i(c,()=>d(`cancel`));try{let e=await l(o(c),t);return d(`done`),s?.(!1),e}catch(e){throw d(`error`,e),s?.(!0),e}finally{u()}},d=async(t,r)=>{let{ctx:i,unlink:a}=n(t);try{return await e(i,`run`,()=>r(i))}finally{a()}},f=e=>e,p=(e,t)=>n=>e(t,f(n)),m=e=>Array.isArray(e)?Array(e.length):{},h=(t,r)=>{let i=Object.entries(r).map(([r,i])=>{let a=n(t),o={signal:a.ctx.signal,abort:a.ctx.abort},s=()=>i(o);return{key:r,task:new Promise(t=>t(e(a.ctx,`run`,s))).finally(a.unlink),cancel:a.ctx.abort}});return{tasks:i.map(({key:e,task:t})=>[e,t]),cancelAll:()=>{for(let e of i)e.cancel()}}},g=(e,t,n,r,i)=>{let a=()=>{};return u(e,t,async e=>{let t=h(e,n);return a=t.cancelAll,r(t.tasks)},e=>{(e||i===`end`)&&a()})};function _(e,t){return g(`all`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>e)),r=m(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`)}const v=e=>e.then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}));function y(e,t){return g(`allSettled`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>v(e))),r=m(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`)}const b=e=>e>0?e:0,x=(e={})=>{let t=b(e.base??100),n=e.factor??2,r=b(e.max??1/0),i=e.jitter??!1;return e=>{let a=b(Math.min(r,t*n**(e-1)));return i?Math.random()*a||0:a}},S=(e,n)=>e.signal.aborted?Promise.reject(e.signal.reason):new Promise((r,a)=>{let o=[],s=`pending`,c=e=>{try{e()}catch(e){t(`cancel cleanup failed`,e)}},l=i(e,e=>{s=`cancelled`;for(let e of o.reverse())c(e);a(e)}),u=e=>(...t)=>{s===`pending`&&(s=`settled`,l(),o.length=0,e(...t))},d=e=>{s===`pending`?o.push(e):s===`cancelled`&&c(e)};try{n({resolve:u(r),reject:u(a),onCancel:d})}catch(e){u(a)(e)}}),C=e=>t=>{let n=t.addContext,r=Object.entries(e);return t.addContext=e=>{n?.(e);for(let[t,n]of r)Object.assign(e,{[t]:(...t)=>n(e,...t)})},t},w=(e,t,n,r)=>{if(e.signal.aborted)return Promise.resolve();let a=r.leading??!1,c=r.waitForFn??!1;return u(`poll`,e,e=>new Promise((r,l)=>{let u=0,f=null,p=()=>{f!==null&&(o(f),f=null)},m=e=>{try{f=s(h,typeof n==`function`?n(e):n)}catch(e){p(),l(e)}},h=()=>{f=null,c||m(u+1),g()},g=()=>{let n=u++;d(e,e=>t(e,n)).then(()=>{c&&!e.signal.aborted&&m(u)},e=>{p(),l(e)})};i(e,p),a?(g(),c||m(u)):m(0)})).catch(t=>{if(!e.signal.aborted)throw t})};function T(e,t,n,r={}){if(typeof e!=`object`){let r=t,i=n??{};return(t,n)=>w(n,p(r,t),e,i)}let i=t;return w(e,(e,t)=>i(t),n,r)}function E(e,t){let n=m(t);return Object.keys(t).length===0?Promise.resolve(n):g(`race`,e,t,async e=>{let[t,r]=await Promise.race(e.map(([e,t])=>t.then(t=>[e,t])));return n[t]=r,n},`end`)}const D=(e,t,n)=>typeof e==`function`?e(t,n):e,O=e=>({times:e.times??3,delay:e.delay??0,shouldRetry:e.shouldRetry??(()=>!0)}),k=(e,t,n)=>u(`retry`,e,async e=>{let{times:r,delay:i,shouldRetry:a}=O(n);for(let n=1;;n++)try{return await d(e,e=>t(e,n))}catch(t){if(e.signal.throwIfAborted(),!(n<r)||!a(t,n))throw t;let o=D(i,n,t);o>0&&await c(e,o)}});function A(e,t,n={}){if(typeof e==`function`){let n=e;return(e,r)=>k(r,p(n,e),t??{})}let r=t;return k(e,(e,t)=>r(t),n)}function j(e,t,n={}){return u(`take`,e,r=>new Promise((a,o)=>{let{predicate:s}=n,c=[],l=()=>{for(let e of c)e()},u=e=>{l(),o(e)};c.push(e.on(t,e=>{(!s||s(e))&&(l(),a(e))})),c.push(i(r,u)),c.push(i({signal:n.signal},u))}))}const M=(t,r,i)=>u(`timeout`,t,async t=>{let a=n(t),c=s(()=>a.ctx.abort(new DOMException(`Timed out after ${r}ms`,`TimeoutError`)),r);try{return await l(Promise.resolve(e(a.ctx,`run`,()=>i(a.ctx))),a.ctx)}finally{o(c),a.unlink()}});function N(e,t,n){if(typeof e==`number`){let n=t;return(t,r)=>M(r,e,p(n,t))}let r=t,i=n;return M(e,r,e=>i({signal:e.signal,abort:e.abort}))}export{_ as all,y as allSettled,x as backoff,S as cancellable,c as delay,C as effectsPlugin,i as onAbort,T as poll,E as race,A as retry,j as take,N as timeout};
@@ -1,2 +1,3 @@
1
- import { A as Handler, C as ContextOf, D as EventKey, E as Emittable, F as WithType, I as commandCall, L as createBus, M as Off, N as On, O as EventLike, P as WithContext, R as Tracer, S as Context, T as Emit, _ as Bus, a as EffectName, b as CommandCall, c as PayloadOf, d as Trace, f as TraceEvent, g as AnyEvent, h as Action, i as WithPayload, j as HandlerRef, k as EventPayload, l as Phase, m as UnsubscribeCallback, o as EventMap, p as TraceLogger, s as Keys, u as Task, v as BusOptions, w as ContextOption, x as Commands, y as Command, z as anyEventType } from "./action-creator-D48fp13T.js";
2
- export { type Action, type AnyEvent, type Bus, type BusOptions, type Command, type CommandCall, type Commands, type Context, type ContextOf, type ContextOption, type EffectName, type Emit, type Emittable, type EventKey, type EventLike, type EventMap, type EventPayload, type Handler, type HandlerRef, type Keys, type Off, type On, type PayloadOf, type Phase, type Task, type Trace, type TraceEvent, type TraceLogger, type Tracer, type UnsubscribeCallback, type WithContext, type WithPayload, type WithType, anyEventType, commandCall, createBus };
1
+ import { A as On, B as PayloadOf, C as EventKey, D as Handler, E as EventsOf, F as Tracer, G as TraceLogger, H as Task, I as anyEventType, K as UnsubscribeCallback, L as EffectName, M as WithType, N as commandCall, O as HandlerRef, P as createBus, R as EventMap, S as Emittable, T as EventPayload, U as Trace, V as Phase, W as TraceEvent, _ as Commands, b as ContextOption, d as Action, f as AnyEvent, g as CommandCall, h as Command, i as WithPayload, j as WithContext, k as Off, m as BusOptions, p as Bus, v as Context, w as EventLike, x as Emit, y as ContextOf, z as Keys } from "./action-creator-DKG_sIia.js";
2
+ import { n as NoClash, r as contextPlugin, t as ContextTask } from "./context-plugin-Dt1IgVo8.js";
3
+ export { type Action, type AnyEvent, type Bus, type BusOptions, type Command, type CommandCall, type Commands, type Context, type ContextOf, type ContextOption, type ContextTask, type EffectName, type Emit, type Emittable, type EventKey, type EventLike, type EventMap, type EventPayload, type EventsOf, type Handler, type HandlerRef, type Keys, type NoClash, type Off, type On, type PayloadOf, type Phase, type Task, type Trace, type TraceEvent, type TraceLogger, type Tracer, type UnsubscribeCallback, type WithContext, type WithPayload, type WithType, anyEventType, commandCall, contextPlugin, createBus };
@@ -1 +1 @@
1
- export{i as anyEventType,t as commandCall,n as createBus}from"./bus-B12SvxLv.js";
1
+ import{i as e,n as t,t as n}from"./bus-Bdk0YyFQ.js";const r=e=>typeof e==`function`,i=e=>({type:Reflect.get(e,`type`),payload:Reflect.get(e,`payload`)}),a=e=>t=>{let n=t.addContext;return t.addContext=t=>{n?.(t);let a=r(e)?e(i(t)):e;for(let[e,n]of Object.entries(a))e in t||Reflect.set(t,e,n)},t};export{e as anyEventType,n as commandCall,a as contextPlugin,t as createBus};
@@ -0,0 +1,207 @@
1
+ import { R as EventMap, c as BoundForm, j as WithContext, p as Bus, u as Effects, v as Context, z as Keys } from "./action-creator-DKG_sIia.js";
2
+ import { n as NoClash } from "./context-plugin-Dt1IgVo8.js";
3
+ //#region src/utils/delay.d.ts
4
+ /**
5
+ * Resolves after `ms`, or rejects early if `ctx.signal` aborts. `ms` can be a
6
+ * function that returns the number of ms, called once when the delay starts:
7
+ * handy for a random pause (jitter).
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * await delay({}, 500);
12
+ *
13
+ * // 200 to 400 ms
14
+ * await delay({}, () => 200 + Math.random() * 200);
15
+ *
16
+ * // inside a task: stops waiting when the task is aborted
17
+ * bus.on("retry", async (_, ctx) => {
18
+ * await delay(ctx, 1000);
19
+ * await load();
20
+ * });
21
+ * ```
22
+ */
23
+ declare const delay: (ctx: {
24
+ signal?: AbortSignal | undefined;
25
+ }, ms: number | (() => number)) => Promise<void>;
26
+ //#endregion
27
+ //#region src/effects/run.d.ts
28
+ /** Context passed into `race` / `all` effect starters. */
29
+ type EffectContext = {
30
+ signal: AbortSignal;
31
+ abort: (reason?: unknown) => void;
32
+ };
33
+ type Starter<T> = (ctx: EffectContext) => T | PromiseLike<T>;
34
+ //#endregion
35
+ //#region src/effects/all.d.ts
36
+ /**
37
+ * Runs all starters; waits for every result. On failure or parent abort, cancels the rest.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * bus.on("load", async (id, ctx) => {
42
+ * const { user, posts } = await all(ctx, {
43
+ * user: ({ signal }) => fetchUser(id, { signal }),
44
+ * posts: ({ signal }) => fetchPosts(id, { signal }),
45
+ * });
46
+ *
47
+ * // arrays work too: const [user, posts] = await all(ctx, [getUser, getPosts]);
48
+ * });
49
+ * ```
50
+ */
51
+ declare function all<T extends Record<string, Starter<unknown>>>(ctx: {
52
+ signal?: AbortSignal;
53
+ }, effects: T): Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
54
+ declare function all<const T extends readonly Starter<unknown>[]>(ctx: {
55
+ signal?: AbortSignal;
56
+ }, effects: T): Promise<{ -readonly [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
57
+ //#endregion
58
+ //#region src/effects/allSettled.d.ts
59
+ /**
60
+ * Runs all starters and waits for every one to settle, whether it succeeds or
61
+ * fails: nothing is cancelled when a starter fails. The result has, for each
62
+ * starter, `{ status: "fulfilled", value }` or `{ status: "rejected", reason }`.
63
+ * Only an abort of `ctx` rejects it, with the abort reason.
64
+ *
65
+ * @example
66
+ * ```ts
67
+ * bus.on("load", async (id, ctx) => {
68
+ * const { user, posts } = await allSettled(ctx, {
69
+ * user: ({ signal }) => fetchUser(id, { signal }),
70
+ * posts: ({ signal }) => fetchPosts(id, { signal }),
71
+ * });
72
+ *
73
+ * if (user.status === "fulfilled") render(user.value);
74
+ * });
75
+ * ```
76
+ */
77
+ declare function allSettled<T extends Record<string, Starter<unknown>>>(ctx: {
78
+ signal?: AbortSignal;
79
+ }, effects: T): Promise<{ [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
80
+ declare function allSettled<const T extends readonly Starter<unknown>[]>(ctx: {
81
+ signal?: AbortSignal;
82
+ }, effects: T): Promise<{ -readonly [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
83
+ //#endregion
84
+ //#region src/effects/race.d.ts
85
+ type RaceStarter<T> = Starter<T>;
86
+ /**
87
+ * Runs all starters; first to settle wins, losers are cancelled via `ctx.abort`.
88
+ * The result holds only the winner's value, under its key or index.
89
+ *
90
+ * @example
91
+ * ```ts
92
+ * bus.on("load", async (id, ctx) => {
93
+ * const result = await race(ctx, {
94
+ * data: ({ signal }) => fetchData(id, { signal }),
95
+ * timeout: ({ signal }) => delay({ signal }, 5000),
96
+ * });
97
+ *
98
+ * if ("timeout" in result) throw new Error("timed out");
99
+ * render(result.data);
100
+ * });
101
+ * ```
102
+ */
103
+ declare function race<T extends Record<string, RaceStarter<unknown>>>(ctx: {
104
+ signal?: AbortSignal;
105
+ }, effects: T): Promise<{ [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
106
+ declare function race<const T extends readonly RaceStarter<unknown>[]>(ctx: {
107
+ signal?: AbortSignal;
108
+ }, effects: T): Promise<{ -readonly [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
109
+ //#endregion
110
+ //#region src/effects/take.d.ts
111
+ type TakeOptions<P> = {
112
+ /**
113
+ * Wait for the first payload this accepts; others are skipped. A type guard
114
+ * (`(payload): payload is T`) narrows the type of the result to `T`.
115
+ */
116
+ predicate?: (payload: P) => boolean;
117
+ /** Stop waiting when this aborts, e.g. the signal of a `race` starter. */
118
+ signal?: AbortSignal | undefined;
119
+ };
120
+ /**
121
+ * Waits for the next `event` on the bus and resolves with its payload. It sees
122
+ * only events emitted after the call, takes only one, and unsubscribes when it
123
+ * is done. If `ctx` (or `options.signal`) aborts first, it unsubscribes and
124
+ * rejects with the abort reason.
125
+ *
126
+ * @example
127
+ * ```ts
128
+ * bus.on("login", async (user, ctx) => {
129
+ * const reason = await take(ctx, "logout");
130
+ * cleanup(user, reason);
131
+ * });
132
+ *
133
+ * // wait for a matching event, but not longer than 5 s
134
+ * const done = await timeout(ctx, 5000, ({ signal }) =>
135
+ * take(ctx, "saved", { signal, predicate: (id) => id === draftId }),
136
+ * );
137
+ *
138
+ * // a type guard narrows the result: `failed` is `{ ok: false }`
139
+ * const failed = await take(ctx, "result", {
140
+ * predicate: (result): result is { ok: false } => !result.ok,
141
+ * });
142
+ * ```
143
+ */
144
+ declare function take<E extends EventMap, K extends Keys<E>, T extends E[K]>(ctx: Context<E>, event: K, options: TakeOptions<E[K]> & {
145
+ predicate: (payload: E[K]) => payload is T;
146
+ }): Promise<T>;
147
+ declare function take<E extends EventMap, K extends Keys<E>>(ctx: Context<E>, event: K, options?: TakeOptions<E[K]>): Promise<E[K]>;
148
+ //#endregion
149
+ //#region src/effects/plugin.d.ts
150
+ /** The effects that `effectsPlugin` can put on `ctx`. */
151
+ type Supported = {
152
+ race: typeof race;
153
+ all: typeof all;
154
+ allSettled: typeof allSettled;
155
+ take: typeof take;
156
+ delay: typeof delay;
157
+ };
158
+ type Results = Record<string, Starter<unknown>>;
159
+ type List = readonly Starter<unknown>[];
160
+ /** Each supported effect without its leading `ctx` argument. `take` knows the events of the bus. */
161
+ type Bound<E extends EventMap> = {
162
+ race: {
163
+ <T extends Results>(effects: T): Promise<{ [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
164
+ <const T extends List>(effects: T): Promise<{ -readonly [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
165
+ };
166
+ all: {
167
+ <T extends Results>(effects: T): Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
168
+ <const T extends List>(effects: T): Promise<{ -readonly [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
169
+ };
170
+ allSettled: {
171
+ <T extends Results>(effects: T): Promise<{ [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
172
+ <const T extends List>(effects: T): Promise<{ -readonly [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
173
+ };
174
+ take: <K extends Keys<E>>(event: K, options?: TakeOptions<E[K]>) => Promise<E[K]>;
175
+ delay: (ms: number | (() => number)) => Promise<void>;
176
+ };
177
+ /** Any function whose first parameter takes `{ signal }` can go on the context, not only the built-in ones. */
178
+ type Helpers = Effects;
179
+ /**
180
+ * The effects as a handler sees them: the built-in ones keep their hand-written
181
+ * types, any other loses its first parameter, or has the type `Effect<F>` says.
182
+ */
183
+ type BoundOf<H extends Helpers, E extends EventMap> = { [K in keyof H]: K extends keyof Bound<E> ? H[K] extends Supported[K] ? Bound<E>[K] : BoundForm<H[K]> : BoundForm<H[K]>; };
184
+ /**
185
+ * Puts the effects you pass on the context of every task of the bus, bound to
186
+ * that task, so a handler can write `({ race })` instead of `race(ctx, …)`.
187
+ * The key is the name of the effect: `race`, `all`, `allSettled`, `take`,
188
+ * `delay`. Returns the same bus, typed with the new fields.
189
+ *
190
+ * @example
191
+ * ```ts
192
+ * import { createBus } from "nanoeffects";
193
+ * import { all, delay, effectsPlugin, race } from "nanoeffects/effects";
194
+ *
195
+ * const bus = createBus().use(effectsPlugin({ race, delay }));
196
+ *
197
+ * bus.on("load", async (id, { race, delay }) => {
198
+ * const result = await race({
199
+ * data: ({ signal }) => fetchData(id, { signal }),
200
+ * timeout: () => delay(5000),
201
+ * });
202
+ * });
203
+ * ```
204
+ */
205
+ declare const effectsPlugin: <H extends Helpers>(helpers: H) => <E extends EventMap>(bus: Bus<E> & NoClash<BoundOf<H, E>, E>) => Bus<E & WithContext<BoundOf<H, E>>>;
206
+ //#endregion
207
+ export { RaceStarter as a, all as c, delay as d, take as i, EffectContext as l, effectsPlugin as n, race as o, TakeOptions as r, allSettled as s, BoundOf as t, Starter as u };
@@ -1,4 +1,4 @@
1
- import { o as EventMap, u as Task } from "./action-creator-D48fp13T.js";
1
+ import { H as Task, R as EventMap } from "./action-creator-DKG_sIia.js";
2
2
  //#region src/policies/keyed.d.ts
3
3
  /** Options shared by every policy that can keep its state per key. */
4
4
  type KeyOption<P> = {
@@ -1 +1 @@
1
- import{a as e,i as t,o as n,s as r,t as i}from"./context-yAWj0BFZ.js";import{n as a,r as o,t as s}from"./delay-Cgvn16oY.js";import{n as c,t as l}from"./promise-CSLpzwSR.js";const u=()=>{},d=(e,t)=>{let n=/* @__PURE__ */ new Map;return(r,i)=>{let a=e(r),o=n.get(a);if(!o){let e=t(()=>{n.get(a)===e&&n.delete(a)});o=e,n.set(a,e)}return o(r,i)}},f=(e,t)=>e?d(e,t):t(u),p=(e,t={})=>f(t.key,t=>m(`latest`,(t,n,r)=>(r(),e(t,n)),t)),m=(e,a,o=u)=>{let s=null;return(l,u)=>{if(s?.abort(),u.signal.aborted)return;let{ctx:d,unlink:f}=t(u);s=d;let p=i(d,e),m=!1,h=()=>{d.signal.aborted||(m=!0,n(d,e,`start`))};r(d,()=>p(m?`cancel`:`drop`));let g=()=>{f(),s===d&&(s=null,o())},_=e=>{if(!d.signal.aborted)return p(m?`done`:`drop`),e};try{let e=a(l,d,h);return c(e)?Promise.resolve(e).then(_,e=>{if(!d.signal.aborted)throw p(`error`,e),e}).finally(g):(g(),_(e))}catch(e){if(g(),d.signal.aborted)return;throw p(`error`,e),e}}},h=(e,t,n={})=>f(n.key,r=>_(e,t,n,r)),g=(t,r,i,s)=>{let c=s!==u,l=null,d=null;return(u,f)=>{if(f.signal.aborted)return;let p=Date.now(),m=l===null||p-l>=t||p-l<0;return l=p,d!==null&&a(d),d=c?o(s,t):null,i&&m?Promise.resolve(e(f,`debounce`,()=>r(u,f))):(n(f,`debounce`,`drop`),Promise.resolve(void 0))}},_=(t,n,i,a)=>{let o=i.leading??!1,c=i.trailing??!0;if(!c)return g(t,n,o,a);let l=!1,u=0,d=m(`debounce`,([e,i],a,o)=>{let d=u;return r(a,()=>{u===d&&(l=!1)}),s(a,t).then(()=>{if(l=!1,c&&!i)return o(),n(e,a)})},a);return(t,r)=>{if(r.signal.aborted)return;let i=o&&!l;l=!0,u++;let a=d([t,i],r);return i?Promise.resolve(e(r,`debounce`,()=>n(t,r))):a}},v=(t,i={})=>f(i.key,i=>{let a=null;return(o,s)=>{if(s.signal.aborted)return;if(a){n(s,`leading`,`drop`);return}let c={};a=c;let u=()=>{d(),a===c&&(a=null,i())},d=r(s,u);try{return l(e(s,`leading`,()=>t(o,s)),u)}catch(e){throw u(),e}}}),y=(e,t={})=>f(t.key,n=>b(e,t,n)),b=(t,i,a)=>{let o=i.concurrency??1,s=i.limit??1/0,c=[],l=0,d=()=>{for(;l<o;){let e=c.shift();if(!e)return;e.start()}};return(f,p)=>new Promise((m,h)=>{if(p.signal.aborted){m(void 0);return}let g=u,_=()=>{g(),n(p,`queue`,`drop`),m(void 0)},v=()=>{if(g(),p.signal.aborted){_();return}l++;let n=!0,i=()=>{n&&(n=!1,l--,d(),l===0&&c.length===0&&a())},o=r(p,()=>{i(),m(void 0)}),s;try{s=Promise.resolve(e(p,`queue`,()=>t(f,p)))}catch(e){s=Promise.reject(e)}let u=()=>{o(),i()};s.then(e=>{u(),m(p.signal.aborted?void 0:e)},e=>{u(),p.signal.aborted?m(void 0):h(e)})};if(l<o){v();return}if(c.length>=s){if(i.overflow!==`drop-old`||s<=0){_();return}c.shift()?.drop()}let y={start:v,drop:_};c.push(y),g=r(p,()=>{let e=c.indexOf(y);e>=0&&c.splice(e,1),_()})})},x=(e,t,n={})=>f(n.key,r=>S(e,t,n,r)),S=(t,r,i,s)=>{let c=i.leading??!0,l=i.trailing??!0,d=s!==u,f=null,p=0,m=null,h=null,g=null,_=!1,v=e=>f===null||e-f>=t||e-f<0||e-p>=t,y=e=>n(e,`throttle`,`drop`),b=()=>{let e=g;g=null,e&&(y(e.ctx),e.resolve())},x=(e,t)=>(b(),new Promise((n,r)=>{g={payload:e,ctx:t,resolve:n,reject:r}})),S=(t,n,i)=>{b(),p=i,_=!0;try{return e(n,`throttle`,()=>r(t,n))}finally{_=!1}},C=()=>{d&&(h=o(w,t))},w=()=>{if(h=null,!d||m!==null||g)return;let e=Date.now(),n=Math.max(t-(e-(f??-1/0)),t-(e-p));n<=0?s():h=o(w,n)},T=e=>{m=null;let t=g;if(l&&t&&!t.ctx.signal.aborted){g=null;try{t.resolve(S(t.payload,t.ctx,e))}catch(e){t.reject(e)}}else b();w()},E=()=>{let e=Date.now();v(e)?T(e):m=o(E,Math.min(t-(e-(f??e)),t-(e-p)))},D=()=>{h!==null&&(a(h),h=null)},O=(e,t)=>{if(!l)y(t);else return x(e,t)},k=(e,t,n,r)=>{if(!r)y(t);else if(p=n,C(),!c)y(t);else return S(e,t,n)},A=(e,n,r,i)=>i&&m!==null?(a(m),m=o(E,t),S(e,n,r)):m===null&&(m=o(E,t),i&&(p=r,c))?S(e,n,r):O(e,n);return(e,t)=>{if(t.signal.aborted)return;let n=Date.now(),r=!_&&v(n);return f=n,D(),l?A(e,t,n,r):k(e,t,n,r)}};export{h as debounce,p as latest,v as leading,y as queue,x as throttle};
1
+ import{a as e,i as t,o as n,s as r,t as i}from"./context-CctVmHLC.js";import{n as a,r as o,t as s}from"./delay-B_W1tnkS.js";import{n as c,t as l}from"./promise-CSLpzwSR.js";const u=()=>{},d=(e,t)=>{let n=/* @__PURE__ */ new Map;return(r,i)=>{let a=e(r),o=n.get(a);if(!o){let e=t(()=>{n.get(a)===e&&n.delete(a)});o=e,n.set(a,e)}return o(r,i)}},f=(e,t)=>e?d(e,t):t(u),p=(e,t={})=>f(t.key,t=>m(`latest`,(t,n,r)=>(r(),e(t,n)),t)),m=(e,a,o=u)=>{let s=null;return(l,u)=>{if(s?.abort(),u.signal.aborted)return;let{ctx:d,unlink:f}=t(u);s=d;let p=i(d,e),m=!1,h=()=>{d.signal.aborted||(m=!0,n(d,e,`start`))};r(d,()=>p(m?`cancel`:`drop`));let g=()=>{f(),s===d&&(s=null,o())},_=e=>{if(!d.signal.aborted)return p(m?`done`:`drop`),e};try{let e=a(l,d,h);return c(e)?Promise.resolve(e).then(_,e=>{if(!d.signal.aborted)throw p(`error`,e),e}).finally(g):(g(),_(e))}catch(e){if(g(),d.signal.aborted)return;throw p(`error`,e),e}}},h=(e,t,n={})=>f(n.key,r=>_(e,t,n,r)),g=(t,r,i,s)=>{let c=s!==u,l=null,d=null;return(u,f)=>{if(f.signal.aborted)return;let p=Date.now(),m=l===null||p-l>=t||p-l<0;return l=p,d!==null&&a(d),d=c?o(s,t):null,i&&m?Promise.resolve(e(f,`debounce`,()=>r(u,f))):(n(f,`debounce`,`drop`),Promise.resolve(void 0))}},_=(t,n,i,a)=>{let o=i.leading??!1,c=i.trailing??!0;if(!c)return g(t,n,o,a);let l=!1,u=0,d=m(`debounce`,([e,i],a,o)=>{let d=u;return r(a,()=>{u===d&&(l=!1)}),s(a,t).then(()=>{if(l=!1,c&&!i)return o(),n(e,a)})},a);return(t,r)=>{if(r.signal.aborted)return;let i=o&&!l;l=!0,u++;let a=d([t,i],r);return i?Promise.resolve(e(r,`debounce`,()=>n(t,r))):a}},v=(t,i={})=>f(i.key,i=>{let a=null;return(o,s)=>{if(s.signal.aborted)return;if(a){n(s,`leading`,`drop`);return}let c={};a=c;let u=()=>{d(),a===c&&(a=null,i())},d=r(s,u);try{return l(e(s,`leading`,()=>t(o,s)),u)}catch(e){throw u(),e}}}),y=(e,t={})=>f(t.key,n=>b(e,t,n)),b=(t,i,a)=>{let o=i.concurrency??1,s=i.limit??1/0,c=[],l=0,d=()=>{for(;l<o;){let e=c.shift();if(!e)return;e.start()}};return(f,p)=>new Promise((m,h)=>{if(p.signal.aborted){m(void 0);return}let g=u,_=()=>{g(),n(p,`queue`,`drop`),m(void 0)},v=()=>{if(g(),p.signal.aborted){_();return}l++;let n=!0,i=()=>{n&&(n=!1,l--,d(),l===0&&c.length===0&&a())},o=r(p,()=>{i(),m(void 0)}),s;try{s=Promise.resolve(e(p,`queue`,()=>t(f,p)))}catch(e){s=Promise.reject(e)}let u=()=>{o(),i()};s.then(e=>{u(),m(p.signal.aborted?void 0:e)},e=>{u(),p.signal.aborted?m(void 0):h(e)})};if(l<o){v();return}if(c.length>=s){if(i.overflow!==`drop-old`||s<=0){_();return}c.shift()?.drop()}let y={start:v,drop:_};c.push(y),g=r(p,()=>{let e=c.indexOf(y);e>=0&&c.splice(e,1),_()})})},x=(e,t,n={})=>f(n.key,r=>S(e,t,n,r)),S=(t,r,i,s)=>{let c=i.leading??!0,l=i.trailing??!0,d=s!==u,f=null,p=0,m=null,h=null,g=null,_=!1,v=e=>f===null||e-f>=t||e-f<0||e-p>=t,y=e=>n(e,`throttle`,`drop`),b=()=>{let e=g;g=null,e&&(y(e.ctx),e.resolve())},x=(e,t)=>(b(),new Promise((n,r)=>{g={payload:e,ctx:t,resolve:n,reject:r}})),S=(t,n,i)=>{b(),p=i,_=!0;try{return e(n,`throttle`,()=>r(t,n))}finally{_=!1}},C=()=>{d&&(h=o(w,t))},w=()=>{if(h=null,!d||m!==null||g)return;let e=Date.now(),n=Math.max(t-(e-(f??-1/0)),t-(e-p));n<=0?s():h=o(w,n)},T=e=>{m=null;let t=g;if(l&&t&&!t.ctx.signal.aborted){g=null;try{t.resolve(S(t.payload,t.ctx,e))}catch(e){t.reject(e)}}else b();w()},E=()=>{let e=Date.now();v(e)?T(e):m=o(E,Math.min(t-(e-(f??e)),t-(e-p)))},D=()=>{h!==null&&(a(h),h=null)},O=(e,t)=>{if(!l)y(t);else return x(e,t)},k=(e,t,n,r)=>{if(!r)y(t);else if(p=n,C(),!c)y(t);else return S(e,t,n)},A=(e,n,r,i)=>i&&m!==null?(a(m),m=o(E,t),S(e,n,r)):m===null&&(m=o(E,t),i&&(p=r,c))?S(e,n,r):O(e,n);return(e,t)=>{if(t.signal.aborted)return;let n=Date.now(),r=!_&&v(n);return f=n,D(),l?A(e,t,n,r):k(e,t,n,r)}};export{h as debounce,p as latest,v as leading,y as queue,x as throttle};
@@ -1,4 +1,4 @@
1
- import { _ as Bus, o as EventMap, v as BusOptions } from "./action-creator-D48fp13T.js";
1
+ import { R as EventMap, p as Bus } from "./action-creator-DKG_sIia.js";
2
2
  //#region src/store/redux/middleware.d.ts
3
3
  /** What Redux passes through a middleware: an action is a plain object with a `type`. */
4
4
  type ReduxAction = {
@@ -8,6 +8,8 @@ type ReduxAction = {
8
8
  type NanoeffectsMiddlewareOptions = {
9
9
  /** Return `false` for the actions that the bus should not get. Default: all of them. */
10
10
  filter?: (action: ReduxAction) => boolean;
11
+ /** Receives an error that `emit` throws, so `dispatch` does not. Default: the error is thrown. */
12
+ onError?: (error: unknown, action: ReduxAction) => void;
11
13
  };
12
14
  //#endregion
13
15
  //#region src/store/redux/effects.d.ts
@@ -19,48 +21,44 @@ type ReduxStoreApi<State = unknown> = {
19
21
  }) => unknown;
20
22
  getState: () => State;
21
23
  };
22
- type EffectsMiddlewareOptions<E extends EventMap> = Omit<BusOptions<E>, "context"> & NanoeffectsMiddlewareOptions & {
23
- /** More fields for the context of every task, next to `store`. */
24
- context?: object;
25
- };
24
+ type EffectsMiddlewareOptions = Pick<NanoeffectsMiddlewareOptions, "filter">;
26
25
  /**
27
- * Creates a bus and the Redux middleware that feeds it: the effects of an app
28
- * in one place, without sagas. Every task gets `ctx.store`, the `dispatch` and
29
- * `getState` of the store, as soon as the middleware is added to it. Type it
30
- * in the event map:
26
+ * Makes the Redux middleware that feeds a bus you already have: the actions of
27
+ * the store reach its handlers, and every task gets `ctx.store`, the `dispatch`
28
+ * and `getState` of the store, as soon as Redux has installed the middleware.
29
+ * Type it in the event map of the bus:
31
30
  *
32
31
  * ```ts
33
32
  * type Events = { userRequested: string } & WithContext<{ store: ReduxStoreApi<RootState> }>;
34
33
  * ```
35
34
  *
36
- * Two things are looked after for you:
35
+ * Use one bus for one store: a second store would replace the first in the
36
+ * contexts. Two things are looked after for you:
37
37
  *
38
38
  * - **A handler does not loop on its own action.** An action that a handler
39
39
  * dispatches through `ctx.store` and that has the type the handler works on
40
40
  * does not go back to the bus (a handler of `a` that dispatches `a`). Other
41
41
  * handlers of that type do not get it either. Longer cycles, `a` to `b` to
42
42
  * `a`, are yours to avoid.
43
- * - **A failing handler does not break `dispatch`.** Errors go to `onError`,
44
- * by default to `console.error`, as in Redux Toolkit listeners; reducers
45
- * still throw to the caller.
43
+ * - **A failing handler does not break `dispatch`.** With `onError` on the bus
44
+ * the bus isolates the handlers. Without it the error is written to
45
+ * `console.error`, as in Redux Toolkit listeners. Reducers still throw to
46
+ * the caller.
46
47
  *
47
48
  * @example
48
49
  * ```ts
49
- * const effects = createEffectsMiddleware<Events>();
50
+ * const bus = createBus<Events>();
50
51
  *
51
52
  * const store = configureStore({
52
53
  * reducer,
53
- * middleware: (getDefault) => getDefault().concat(effects.middleware),
54
+ * middleware: (getDefault) => getDefault().concat(createEffectsMiddleware(bus)),
54
55
  * });
55
56
  *
56
- * effects.bus.on(userRequested, latest(async (id, { store, signal }) => {
57
+ * bus.on(userRequested, latest(async (id, { store, signal }) => {
57
58
  * store.dispatch(userLoaded(await fetchUser(id, { signal })));
58
59
  * }));
59
60
  * ```
60
61
  */
61
- export declare const createEffectsMiddleware: <E extends EventMap = EventMap>(options?: EffectsMiddlewareOptions<E>) => {
62
- bus: Bus<E>;
63
- middleware: (storeApi: ReduxStoreApi) => (next: (action: unknown) => unknown) => (action: unknown) => unknown;
64
- };
62
+ export declare const createEffectsMiddleware: <E extends EventMap>(bus: Bus<E>, options?: EffectsMiddlewareOptions) => (storeApi: ReduxStoreApi) => (next: (action: unknown) => unknown) => (action: unknown) => unknown;
65
63
  //#endregion
66
64
  export type { EffectsMiddlewareOptions, ReduxStoreApi };
@@ -1 +1 @@
1
- import{c as e}from"./context-yAWj0BFZ.js";import{n as t}from"./bus-B12SvxLv.js";const n=e=>typeof e==`object`&&!!e&&`type`in e,r=(e,t={})=>{let r=e.emit;return()=>e=>i=>{let a=e(i);return n(i)&&(t.filter?.(i)??!0)&&r(i),a}},i=(n={})=>{let{filter:i,context:a,onError:o,...s}=n,c,l=/* @__PURE__ */ new WeakMap,u=e=>({...a,store:c&&{getState:c.getState,dispatch:t=>{typeof t==`object`&&t&&l.set(t,e.type);let n=t;return c?.dispatch(n)}}}),d=t({...s,onError:o??((t,{type:n})=>{e(`handler of "${n}" failed`,t)}),context:u}),f=r(d,{filter:e=>l.get(e)!==e.type&&(i?.(e)??!0)});return{bus:d,middleware:e=>(c=e,f())}};export{i as createEffectsMiddleware};
1
+ const e=e=>typeof e==`object`&&!!e&&`type`in e,t=(t,n={})=>{let r=t.emit,i=e=>{try{r(e)}catch(t){if(!n.onError)throw t;n.onError(t,e)}};return()=>t=>r=>{let a=t(r);return e(r)&&(n.filter?.(r)??!0)&&i(r),a}},n=(e,n={})=>{let r,i=/* @__PURE__ */ new WeakMap,a=e.addContext;e.addContext=e=>{a?.(e);let t=r;if(!t)return;let{type:n}=e;Object.assign(e,{store:{getState:t.getState,dispatch:e=>{typeof e==`object`&&e&&i.set(e,n);let r=e;return t.dispatch(r)}}})};let o=t(e,{filter:e=>i.get(e)!==e.type&&(n.filter?.(e)??!0),onError:(e,{type:t})=>{globalThis.console?.error(`[nanoeffects] handler of "${t}" failed`,e)}});return e=>(r=e,o())};export{n as createEffectsMiddleware};
@@ -1,4 +1,4 @@
1
- import { _ as Bus, o as EventMap, s as Keys } from "./action-creator-D48fp13T.js";
1
+ import { B as EventMap, V as Keys, h as Bus } from "./action-creator-c292nK7v.js";
2
2
  //#region src/observable.d.ts
3
3
  declare global {
4
4
  interface SymbolConstructor {