nanoeffects 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +95 -2
  3. package/dist/action-BM-UdmJr.d.ts +302 -0
  4. package/dist/actions.d.ts +196 -0
  5. package/dist/actions.js +1 -0
  6. package/dist/bus-RUiw8f9p.js +1 -0
  7. package/dist/context-BXQ6Einm.js +1 -0
  8. package/dist/delay-CIHnOh_L.js +1 -0
  9. package/dist/effects.d.ts +244 -0
  10. package/dist/effects.js +1 -0
  11. package/dist/event-0RIBGYqS.js +1 -0
  12. package/dist/index-CaxrMD1A.d.ts +1 -0
  13. package/dist/index.d.ts +3 -0
  14. package/dist/index.js +1 -0
  15. package/dist/notrace/action-BM-UdmJr.d.ts +302 -0
  16. package/dist/notrace/actions.d.ts +196 -0
  17. package/dist/notrace/actions.js +1 -0
  18. package/dist/notrace/bus-CFxgpsRL.js +1 -0
  19. package/dist/notrace/context-DGPIFXxI.js +1 -0
  20. package/dist/notrace/delay-Cko_Q9hl.js +1 -0
  21. package/dist/notrace/effects.d.ts +244 -0
  22. package/dist/notrace/effects.js +1 -0
  23. package/dist/notrace/event-0RIBGYqS.js +1 -0
  24. package/dist/notrace/index-CaxrMD1A.d.ts +1 -0
  25. package/dist/notrace/index.d.ts +3 -0
  26. package/dist/notrace/index.js +1 -0
  27. package/dist/notrace/policies.d.ts +171 -0
  28. package/dist/notrace/policies.js +1 -0
  29. package/dist/notrace/promise-CSLpzwSR.js +1 -0
  30. package/dist/notrace/redux.d.ts +92 -0
  31. package/dist/notrace/redux.js +1 -0
  32. package/dist/observable.d.ts +20 -0
  33. package/dist/observable.js +1 -0
  34. package/dist/onAbort-BgMfspK4.js +1 -0
  35. package/dist/policies.d.ts +171 -0
  36. package/dist/policies.js +1 -0
  37. package/dist/promise-CSLpzwSR.js +1 -0
  38. package/dist/redux.d.ts +92 -0
  39. package/dist/redux.js +1 -0
  40. package/dist/trace.d.ts +144 -0
  41. package/dist/trace.js +1 -0
  42. package/docs/README.md +12 -0
  43. package/docs/actions.md +68 -0
  44. package/docs/context.md +16 -0
  45. package/docs/effects.md +119 -0
  46. package/docs/errors.md +23 -0
  47. package/docs/hmr.md +74 -0
  48. package/docs/observable.md +22 -0
  49. package/docs/policies.md +53 -0
  50. package/docs/semantics.md +7 -0
  51. package/docs/stores.md +50 -0
  52. package/docs/tracing.md +104 -0
  53. package/package.json +164 -5
@@ -0,0 +1,196 @@
1
+ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as EventMap, m as Emittable, n as FreeActionCreator, o as Bus, r as createAction, t as ActionCreator, u as Context } from "./action-BM-UdmJr.js";
2
+ //#region src/actions/command.d.ts
3
+ /**
4
+ * Creates a command: a typed request for a result. `bus.emit(command, payload)`
5
+ * runs its handler as a task, with a context, and returns what the handler
6
+ * returns. Listeners of the command's type are told first, as for any event.
7
+ *
8
+ * The handler is optional. A command without one is only a contract, and the
9
+ * bus gets its implementation from the `commands` registry (see
10
+ * `createCommands` and `bindHandler`). A handler bound there wins over the one
11
+ * the command was created with, so a test can give a bus its own implementation.
12
+ *
13
+ * A handler can be wrapped in a policy, e.g. `latest(fn)`. Calling the command
14
+ * directly, `command(payload)`, runs its own handler outside of any bus.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const getUser = createCommand("user/get", (id: string, { signal }) =>
19
+ * fetchUser(id, { signal }),
20
+ * );
21
+ * const sendMail = createCommand<Mail, void>("mail/send"); // implemented elsewhere
22
+ *
23
+ * const commands = createCommands([bindHandler(sendMail, smtpSend)]);
24
+ * const bus = createBus({ commands });
25
+ * const user = await bus.emit(getUser, "1");
26
+ *
27
+ * commands.handle(getUser, async () => fakeUser); // in a test
28
+ * ```
29
+ */
30
+ export declare const createCommand: <P = void, R = void, T extends string = string, E extends EventMap = EventMap>(type: T, handler?: Task<P, E, R>) => Command<P, R> & {
31
+ readonly type: T;
32
+ };
33
+ /** A command (or its type) with the handler to bind to it; `bindHandler` makes one. */
34
+ type Binding<E extends EventMap = EventMap> = readonly [Command<never, unknown> | string, Task<never, E, unknown>];
35
+ /**
36
+ * Pairs a command with the handler to bind to it, for `createCommands`. It
37
+ * checks that the handler fits the command.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * createCommands([bindHandler(sendMail, smtpSend)]);
42
+ * ```
43
+ */
44
+ export declare const bindHandler: <P, R, E extends EventMap>(command: Command<P, R>, fn: Task<P, E, R>) => Binding<E>;
45
+ /**
46
+ * The handlers bound to commands, for `createBus({ commands })`. Each bus gets
47
+ * its own, so each test can have its own implementation. `handle` binds more
48
+ * later and returns the function that unbinds.
49
+ *
50
+ * What the bus runs for a command: the handler bound last, else the one the
51
+ * command was created with, else it throws `No handler for command "..."`.
52
+ *
53
+ * @example
54
+ * ```ts
55
+ * const commands = createCommands([bindHandler(sendMail, smtpSend)]);
56
+ * const bus = createBus<Events>({ commands });
57
+ *
58
+ * const unbind = commands.handle(getUser, async () => fakeUser);
59
+ * unbind(); // the command's own handler is back
60
+ * ```
61
+ */
62
+ export declare const createCommands: <E extends EventMap = EventMap>(bindings?: readonly Binding<E>[]) => {
63
+ run: (command: Command, payload: unknown, ctx: unknown) => unknown;
64
+ handle: {
65
+ <P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
66
+ (type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
67
+ (bindings: readonly Binding<E>[]): UnsubscribeCallback;
68
+ };
69
+ };
70
+ //#endregion
71
+ //#region src/actions/job.d.ts
72
+ /**
73
+ * Creates a command whose outcome is sent on: when the handler succeeds, its
74
+ * result goes to `done`, and when it fails, the error goes to `fail`. Each is
75
+ * anything `emit` takes as its first argument, and receives the result (or the
76
+ * error) as the payload: an event type, an action creator, a command, or a
77
+ * plain action. It is made for the case where nobody waits for the result and
78
+ * the bus carries it on, like `createAsyncThunk` or an effector effect.
79
+ *
80
+ * `bus.emit(job, payload)` returns a promise of the result. When `fail` is set
81
+ * the error counts as handled: it goes to `fail` and the promise resolves with
82
+ * `undefined`; without `fail` the promise rejects. The outcome is routed by the
83
+ * bus, also for a handler bound with `commands.handle`, and is skipped once the
84
+ * task is aborted. Calling the job directly runs only its handler.
85
+ *
86
+ * @example
87
+ * ```ts
88
+ * const loaded = createAction<User>("user/loaded");
89
+ * const failed = createAction<Error>("user/failed");
90
+ *
91
+ * const loadUser = createJob("user/load", fetchUser, { done: loaded, fail: failed });
92
+ *
93
+ * bus.on(loaded, (user) => render(user));
94
+ * bus.emit(loadUser, "1"); // loaded(user) or failed(error) comes later
95
+ * ```
96
+ */
97
+ export declare const createJob: <P = void, R = void, T extends string = string, E extends EventMap = EventMap>(type: T, handler?: Task<P, E, R>, outcomes?: {
98
+ /** Gets the result when the handler succeeds. */
99
+ done?: Emittable<E>;
100
+ /** Gets the error when the handler fails. */
101
+ fail?: Emittable<E>;
102
+ }) => Command<P, Promise<Awaited<R> | undefined>> & {
103
+ readonly type: T;
104
+ };
105
+ //#endregion
106
+ //#region src/actions/module.d.ts
107
+ /**
108
+ * What a module's `setup` gets: the context of the module's task, so `on`,
109
+ * `emit` and `run` work as in a handler, plus `handle` to bind commands, `use`
110
+ * to mount sub-modules and `spawn` to start a background task. Everything the
111
+ * module does is undone when it is unmounted.
112
+ */
113
+ type ModuleContext<E extends EventMap = EventMap> = Context<E> & {
114
+ /** Binds the handler of a command, or a list of them; undone on unmount. */
115
+ handle<P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
116
+ handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
117
+ handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
118
+ /**
119
+ * Mounts sub-modules; they are unmounted with this one. The returned function
120
+ * unmounts just these, e.g. when they were added later from a listener.
121
+ */
122
+ use(...modules: Module<E>[]): UnsubscribeCallback;
123
+ /**
124
+ * Starts a background task that lives as long as the module: it is aborted
125
+ * on unmount, and an error of it is left unhandled, as in any handler.
126
+ */
127
+ spawn<P>(fn: Task<P, E, unknown>, ...payload: PayloadOf<P>): void;
128
+ };
129
+ type Module<E extends EventMap = EventMap> = {
130
+ readonly name: string;
131
+ readonly setup: (m: ModuleContext<E>) => void;
132
+ };
133
+ /**
134
+ * Describes one domain of an app: the commands it handles, the events it
135
+ * listens to, its sub-modules and its background tasks. The `name` shows up as
136
+ * the type of the module's tasks in the trace.
137
+ *
138
+ * @example
139
+ * ```ts
140
+ * export const userModule = createModule<Events>("user", (m) => {
141
+ * m.handle(getUser, fetchUser);
142
+ * m.handle([bindHandler(sendMail, smtpSend)]);
143
+ * m.use(authModule);
144
+ *
145
+ * m.on(loginRequested, (user, ctx) => ctx.emit(userLoaded(user)));
146
+ * m.spawn(async (_, ctx) => {
147
+ * for (;;) await handleNext(await take(ctx, "job"));
148
+ * });
149
+ * });
150
+ * ```
151
+ */
152
+ export declare const createModule: <E extends EventMap = EventMap>(name: string, setup: (m: ModuleContext<E>) => void) => Module<E>;
153
+ type Registry<E extends EventMap> = ReturnType<typeof createCommands<E>>;
154
+ /** What `registerModules` returns. */
155
+ type ModuleApi<E extends EventMap = EventMap> = {
156
+ /** The registry of command handlers of the bus: the one it was made with, or the app's own. */
157
+ commands: Registry<E>;
158
+ /** Mounts a module and returns the function that unmounts it; a module that is mounted already is not run again. */
159
+ mount(module: Module<E>): UnsubscribeCallback;
160
+ unmount(module: Module<E>): void;
161
+ isMounted(module: Module<E>): boolean;
162
+ /** Unmounts every module; a disposed app cannot mount modules. */
163
+ dispose(): void;
164
+ };
165
+ /**
166
+ * Assembles an app from modules on `bus`: mounts `modules` at once, in the
167
+ * order given, and returns `mount`, `unmount`, `isMounted` and `dispose` for
168
+ * the modules that come and go later. The bus runs the commands that the
169
+ * modules bind: if it was made with `commands: createCommands()` that registry
170
+ * is used, otherwise the app brings its own, as `app.commands`.
171
+ *
172
+ * A module is known by its `name`: mounting a module whose name is taken
173
+ * replaces the mounted one, which is unmounted first. That is what hot reload
174
+ * needs (see `docs/hmr.md`): the new version of a module file mounts again and
175
+ * the old version goes away with its subscriptions, commands and tasks.
176
+ *
177
+ * Unmounting undoes everything the module did: its subscriptions, its bound
178
+ * commands, its sub-modules and its background tasks. `dispose` unmounts them
179
+ * all, and a disposed app cannot mount modules.
180
+ *
181
+ * @example
182
+ * ```ts
183
+ * const bus = createBus<Events>();
184
+ * const app = registerModules(bus, [userModule]);
185
+ *
186
+ * const unmount = app.mount(orderModule); // later, e.g. after a lazy import
187
+ * unmount(); // or app.unmount(orderModule)
188
+ *
189
+ * bus.emit(getUser, "1");
190
+ * app.commands.handle(getUser, fakeUser); // in a test
191
+ * app.dispose();
192
+ * ```
193
+ */
194
+ export declare const registerModules: <E extends EventMap>(bus: Bus<E>, modules?: readonly Module<E>[]) => ModuleApi<E>;
195
+ //#endregion
196
+ export { type ActionCreator, type Binding, type FreeActionCreator, type Module, type ModuleApi, type ModuleContext, createAction };
@@ -0,0 +1 @@
1
+ import{i as e,n as t,s as n}from"./context-DGPIFXxI.js";import{t as r}from"./event-0RIBGYqS.js";function i(e,t){return Object.assign((...n)=>({type:e,payload:t?t(...n).payload:n[0]}),{type:e,match:t=>t.type===e,toString:()=>e})}var a=class extends Error{};const o=(e,n)=>Object.assign((r,i)=>{if(!n)throw new a(`No handler for command "${e}"`);return n(r,i??t({type:e,payload:r}).ctx)},{type:e}),s=(e,t)=>[e,t],c=(e=[])=>{let t=/* @__PURE__ */ new Map,n=(e,n)=>{let r={fn:n};return t.set(e,[...t.get(e)??[],r]),()=>{let n=(t.get(e)??[]).filter(e=>e!==r);n.length>0?t.set(e,n):t.delete(e)}};function i(e,t){if(t)return n(r(e),t);let i=e.map(([e,t])=>n(r(e),t));return()=>{for(let e of i)e()}}return i(e),{run:(e,n,r)=>{let i=(t.get(e.type)??[]).at(-1)?.fn,a=i&&e.wrap?e.wrap(i):i??e;return Reflect.apply(a,null,[n,r])},handle:i}},l=(e,t,n)=>{let r=e.emit;typeof t==`string`?r(t,n):typeof t==`function`?r(`match`in t?t.type:t,n):r({type:t.type,payload:n})},u=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof a)throw e;return Promise.reject(e)}},d=(e,t,n={})=>{let r=o(e,t),i=(e,t,r)=>{let i=r;return u(()=>Reflect.apply(e,null,[t,r])).then(e=>(n.done&&l(i,n.done,e),e),e=>{if(!n.fail)throw e;l(i,n.fail,e)})};return Object.assign((e,t)=>t?i(r,e,t):u(()=>r(e)),{type:e,wrap:e=>(t,n)=>i(e,t,n)})},f=(e,t)=>({name:e,setup:t}),p=(r,i=[])=>{let a=r.commands??c();r.commands??=a;let o={handle:(...e)=>{if(!a.handle)throw Error("registerModules: the `commands` of the bus is not a registry from `createCommands()`");return Reflect.apply(a.handle,null,e)}},s=t({type:`app`,payload:void 0},r,r.trace),l=t=>{let r=/* @__PURE__ */ new Map,i=/* @__PURE__ */ new Map;return{mount:a=>{let s=r.get(a);if(s)return s;let c=i.get(a.name);c&&r.get(c)?.();let u=e(t,a.name),d=u.ctx,f=l(d),p=()=>{r.delete(a),i.get(a.name)===a&&i.delete(a.name),d.abort(),u.unlink()};r.set(a,p),i.set(a.name,a);let m=(e,t)=>{let r=Reflect.apply(o.handle,null,[e,t]);return n(d,r),r},h=(...e)=>{let t=e.map(f.mount);return()=>{for(let e of t)e()}},g=(e,...t)=>{d.run(e,...t).catch(e=>{if(!d.signal.aborted)throw e})};try{a.setup(Object.assign(d,{handle:m,use:h,spawn:g}))}catch(e){throw p(),e}return p},unmount:e=>r.get(e)?.(),isMounted:e=>r.has(e)}},u=l(s.ctx);for(let e of i)u.mount(e);return{commands:a,mount:e=>(s.ctx.signal.throwIfAborted(),u.mount(e)),unmount:u.unmount,isMounted:u.isMounted,dispose:()=>s.ctx.abort()}};export{s as bindHandler,i as createAction,o as createCommand,c as createCommands,d as createJob,f as createModule,p as registerModules};
@@ -0,0 +1 @@
1
+ import{a as e,c as t,n,r}from"./context-DGPIFXxI.js";import{n as i}from"./promise-CSLpzwSR.js";import{n as a,t as o}from"./event-0RIBGYqS.js";const s=`*`,c=()=>{let e={},t=/* @__PURE__ */ new WeakSet,n=n=>{let r=e[n]??[];if(!t.has(r))return e[n]=r,r;let i=[...r];return e[n]=i,i},r=(t,r)=>{if(!r){e[t]=[];return}let i=(e[t]??[]).indexOf(r);i>=0&&n(t).splice(i,1)};return{get:n=>{let r=e[n]??[];return t.add(r),r},add:(e,t)=>(n(e).push(t),()=>{r(e,t)}),remove:r}},l=(e,t,n)=>Reflect.apply(e,null,[t,n]),u=(s={})=>{let u=c(),d=(e,t)=>u.add(o(e),t),f=(e,t)=>u.remove(o(e),t),p=(e,a)=>{let{onError:o}=s,{ctx:c}=n(a,m,s.trace,{ref:r()});if(!o){e(a.payload,c);return}let l=e=>{try{o(e,a)}catch(e){t(`onError failed`,e)}};try{let t=e(a.payload,c);i(t)&&Promise.resolve(t).catch(l)}catch(e){l(e)}},m={on:d,off:f,emit:(t,i)=>{let c=o(t),d=a(t,i),f={type:c,payload:d},h=[...u.get(c),...u.get(`*`)];h.length===0&&typeof t!=`function`&&s.onUnhandled?.(f);for(let e of h)p(e,f);if(typeof t==`function`){let{ctx:i}=n(f,m,s.trace,{ref:r()}),a=m.commands?.run??l;return e(i,`command`,()=>a(t,d,i))}},commands:s.commands,context:s.context,trace:s.trace};return m};export{s as n,u as t};
@@ -0,0 +1 @@
1
+ const e=(e,t)=>{globalThis.console?.error(`[nanoeffects] ${e}`,t)},t=()=>{},n=/* @__PURE__ */ new WeakMap,r=t=>{let r=n.get(t);if(r)return r;let i=/* @__PURE__ */ new Set;return n.set(t,i),t.addEventListener(`abort`,()=>{let n=[...i];i.clear();for(let{fn:r}of n)try{r(t.reason)}catch(t){e(`abort callback failed`,t)}},{once:!0}),i},i=(e,n)=>{let{signal:i}=e;if(!i)return t;if(i.aborted)return n(i.reason),t;let a=r(i),o={fn:n};return a.add(o),()=>{a.delete(o)}},a=e=>{let t=new AbortController;return{controller:t,unlink:i({signal:e},e=>t.abort(e))}};let o;const s=()=>o,c=()=>{},l=(e,t,n,r)=>{},u=(e,t)=>c,d=(e,t,n)=>n(),f=(e,t)=>typeof e==`function`?e(t):e,p=e=>e,m=(e,t,n,r)=>{let{controller:s,unlink:l}=a(r?.signal),{signal:u}=s,h=(...e)=>{if(u.aborted)return;let n=t?.emit,r=o;o=void 0;try{return n?.(...e)}finally{o=r}},g=(...e)=>{if(u.aborted)return c;let n=t?.on,r=n?.(...e);if(!r)return c;let a=i({signal:u},r);return()=>{a(),r()}},_=async(r,...i)=>{u.throwIfAborted();let a=i[0],o=m({type:e.type,payload:a},t,n,{signal:u,ref:void 0});try{return await d(o.ctx,`run`,()=>r(a,o.ctx))}finally{o.unlink()}};return{ctx:p({...f(t?.context,e),type:e.type,payload:e.payload,signal:u,abort:e=>s.abort(e),emit:h,on:g,off:t?.off??c,run:_}),unlink:l}},h=(e,t)=>m({type:t??e.type??``,payload:e.payload},{emit:e.emit,on:e.on,off:e.off,context:e},void 0,{signal:e.signal,ref:void 0});export{d as a,e as c,h as i,m as n,l as o,s as r,i as s,u as t};
@@ -0,0 +1 @@
1
+ import{s as e}from"./context-DGPIFXxI.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};
@@ -0,0 +1,244 @@
1
+ import { A as Keys, k as EventMap, u as Context } from "./action-BM-UdmJr.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
26
+ //#region src/utils/onAbort.d.ts
27
+ export declare const onAbort: (ctx: {
28
+ signal?: AbortSignal | undefined;
29
+ }, fn: (reason: unknown) => void) => (() => void);
30
+ //#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;
36
+ };
37
+ type Starter<T> = (ctx: EffectContext) => T | PromiseLike<T>;
38
+ //#endregion
39
+ //#region src/effects/all.d.ts
40
+ /**
41
+ * Runs all starters; waits for every result. On failure or parent abort, cancels the rest.
42
+ *
43
+ * @example
44
+ * ```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
+ * });
79
+ * ```
80
+ */
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]>>>; }>;
87
+ //#endregion
88
+ //#region src/effects/cancellable.d.ts
89
+ type CancellableHandle<T> = {
90
+ resolve: (value: T | PromiseLike<T>) => void;
91
+ reject: (reason?: unknown) => void;
92
+ /** Registers a cleanup that runs if the promise is cancelled before it settles. */
93
+ onCancel: (cleanup: () => void) => void;
94
+ };
95
+ type CancellableExecutor<T> = (handle: CancellableHandle<T>) => void;
96
+ /**
97
+ * A promise tied to `ctx.signal`. It works like `new Promise`, but the
98
+ * executor gets one object, `{ resolve, reject, onCancel }`. If the signal
99
+ * aborts before the promise settles, the cleanups run (last registered first)
100
+ * and the promise rejects with the abort reason. If the signal is already
101
+ * aborted, the executor does not run. After the promise settles, the abort
102
+ * listener is removed and the cleanups are dropped.
103
+ *
104
+ * @example
105
+ * ```ts
106
+ * bus.on(
107
+ * "wait",
108
+ * latest((_, ctx) =>
109
+ * cancellable(ctx, ({ resolve, onCancel }) => {
110
+ * const timer = setTimeout(resolve, 5000);
111
+ * onCancel(() => clearTimeout(timer));
112
+ * }),
113
+ * ),
114
+ * );
115
+ * ```
116
+ */
117
+ export declare const cancellable: <T = void>(ctx: {
118
+ signal: AbortSignal;
119
+ }, executor: CancellableExecutor<T>) => Promise<T>;
120
+ //#endregion
121
+ //#region src/effects/poll.d.ts
122
+ type PollOptions = {
123
+ /** Also call `fn` at once, not only after the first `ms`. Default `false`. */
124
+ leading?: boolean;
125
+ /**
126
+ * Start the pause after a call finishes, so calls never overlap. By default
127
+ * the calls come every `ms` whatever the duration of `fn`.
128
+ */
129
+ waitForFn?: boolean;
130
+ };
131
+ /**
132
+ * Calls `fn` every `ms`, like patronum `interval`: the first call comes after
133
+ * `ms` (with `leading` also at once), and the next ticks keep a steady rate
134
+ * whatever the duration of `fn`, so a slow `fn` may overlap with the next call
135
+ * (`waitForFn` starts each pause when the call ends instead). `fn` gets the
136
+ * number of the call, starting at 0.
137
+ *
138
+ * `ms` can be a function of the number of the call that the pause leads to, for
139
+ * a growing or random pause: `(call) => Math.min(1000 * 2 ** call, 60_000)`.
140
+ *
141
+ * It stops when `ctx` aborts: the result then resolves, it does not reject, and
142
+ * the pending timer is cleared. If a call throws, polling stops and the result
143
+ * rejects.
144
+ *
145
+ * @example
146
+ * ```ts
147
+ * bus.on("watch", async (_, ctx) => {
148
+ * await poll(ctx, () => refresh(), 5000);
149
+ * cleanup(); // the task was aborted
150
+ * });
151
+ * ```
152
+ */
153
+ export declare const poll: (ctx: {
154
+ signal: AbortSignal;
155
+ }, fn: (tick: number) => unknown, ms: number | ((call: number) => number), options?: PollOptions) => Promise<void>;
156
+ //#endregion
157
+ //#region src/effects/race.d.ts
158
+ type RaceStarter<T> = Starter<T>;
159
+ /**
160
+ * Runs all starters; first to settle wins, losers are cancelled via `ctx.abort`.
161
+ * The result holds only the winner's value, under its key or index.
162
+ *
163
+ * @example
164
+ * ```ts
165
+ * bus.on("load", async (id, ctx) => {
166
+ * const result = await race(ctx, {
167
+ * data: ({ signal }) => fetchData(id, { signal }),
168
+ * timeout: ({ signal }) => delay({ signal }, 5000),
169
+ * });
170
+ *
171
+ * if ("timeout" in result) throw new Error("timed out");
172
+ * render(result.data);
173
+ * });
174
+ * ```
175
+ */
176
+ export declare function race<T extends Record<string, RaceStarter<unknown>>>(ctx: {
177
+ signal?: AbortSignal;
178
+ }, effects: T): Promise<{ [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
179
+ export declare function race<const T extends readonly RaceStarter<unknown>[]>(ctx: {
180
+ signal?: AbortSignal;
181
+ }, effects: T): Promise<{ -readonly [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
182
+ //#endregion
183
+ //#region src/effects/retry.d.ts
184
+ type RetryOptions = {
185
+ /** Total number of attempts, the first one included. Default 3. */
186
+ times?: number;
187
+ /**
188
+ * Pause before the next attempt, in ms: a number, or a function of the
189
+ * number of the attempt that just failed and its error. Default 0.
190
+ */
191
+ delay?: number | ((attempt: number, error: unknown) => number);
192
+ /** Return `false` to stop retrying and throw `error`. Default: always retry. */
193
+ shouldRetry?: (error: unknown, attempt: number) => boolean;
194
+ };
195
+ export declare const retry: <T>(ctx: {
196
+ signal?: AbortSignal;
197
+ }, fn: (attempt: number) => T | PromiseLike<T>, options?: RetryOptions) => Promise<T>;
198
+ //#endregion
199
+ //#region src/effects/take.d.ts
200
+ type TakeOptions<P> = {
201
+ /** Wait for the first payload this accepts; others are skipped. */
202
+ predicate?: (payload: P) => boolean;
203
+ /** Stop waiting when this aborts, e.g. the signal of a `race` starter. */
204
+ signal?: AbortSignal | undefined;
205
+ };
206
+ /**
207
+ * Waits for the next `event` on the bus and resolves with its payload. It sees
208
+ * only events emitted after the call, takes only one, and unsubscribes when it
209
+ * is done. If `ctx` (or `options.signal`) aborts first, it unsubscribes and
210
+ * rejects with the abort reason.
211
+ *
212
+ * @example
213
+ * ```ts
214
+ * bus.on("login", async (user, ctx) => {
215
+ * const reason = await take(ctx, "logout");
216
+ * cleanup(user, reason);
217
+ * });
218
+ *
219
+ * // wait for a matching event, but not longer than 5 s
220
+ * const done = await timeout(ctx, 5000, ({ signal }) =>
221
+ * take(ctx, "saved", { signal, predicate: (id) => id === draftId }),
222
+ * );
223
+ * ```
224
+ */
225
+ export declare const take: <E extends EventMap, K extends Keys<E>>(ctx: Context<E>, event: K, options?: TakeOptions<E[K]>) => Promise<E[K]>;
226
+ //#endregion
227
+ //#region src/effects/timeout.d.ts
228
+ /**
229
+ * Runs `starter`; if it takes longer than `ms`, aborts its signal and rejects
230
+ * with a `TimeoutError` (a `DOMException`, like `AbortSignal.timeout`), even
231
+ * if the starter ignores the signal. If `ctx` aborts, rejects with its reason.
232
+ *
233
+ * @example
234
+ * ```ts
235
+ * bus.on("load", async (id, ctx) => {
236
+ * const data = await timeout(ctx, 5000, ({ signal }) => fetchData(id, { signal }));
237
+ * });
238
+ * ```
239
+ */
240
+ export declare const timeout: <T>(ctx: {
241
+ signal?: AbortSignal;
242
+ }, ms: number, starter: Starter<T>) => Promise<T>;
243
+ //#endregion
244
+ export type { CancellableExecutor, CancellableHandle, EffectContext, PollOptions, RaceStarter, RetryOptions, TakeOptions };
@@ -0,0 +1 @@
1
+ import{a as e,c as t,i as n,o as r,s as i,t as a}from"./context-DGPIFXxI.js";import{n as o,r as s,t as c}from"./delay-Cko_Q9hl.js";const l=(e,t)=>t?.signal?new Promise((n,r)=>{let a=i(t,r);e.then(n,r).finally(a)}):e,u=e=>Array.isArray(e)?Array(e.length):{},d=(t,o,s)=>{s?.signal?.throwIfAborted();let c=n(s??{}),u=a(c.ctx,o);return r(c.ctx,o,`start`),i(c.ctx,()=>u(`cancel`)),{tasks:Object.entries(t).map(([t,r])=>{let i=n(c.ctx),a={signal:i.ctx.signal,abort:i.ctx.abort};return[t,new Promise(t=>t(e(i.ctx,`run`,()=>r(a)))).finally(i.unlink)]}),cancelAll:()=>c.ctx.abort(),unfollowParent:c.unlink,settle:u,until:e=>l(e,s)}};async function f(e,t){let n=d(t,`all`,e);try{let e=await n.until(Promise.all(n.tasks.map(([,e])=>e))),r=u(t);for(let[t,[i]]of n.tasks.entries())r[i]=e[t];return n.settle(`done`),r}catch(e){throw n.settle(`error`,e),n.cancelAll(),e}finally{n.unfollowParent()}}const p=e=>e.then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}));async function m(e,t){let n=d(t,`allSettled`,e);try{let e=await n.until(Promise.all(n.tasks.map(([,e])=>p(e)))),r=u(t);for(let[t,[i]]of n.tasks.entries())r[i]=e[t];return n.settle(`done`),r}catch(e){throw n.settle(`error`,e),n.cancelAll(),e}finally{n.unfollowParent()}}const h=(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)}}),g=async(e,t,o)=>{t?.signal?.throwIfAborted();let{ctx:s,unlink:c}=n(t??{}),u=a(s,e);r(s,e,`start`),i(s,()=>u(`cancel`));try{let e=await l(o(s),t);return u(`done`),e}catch(e){throw u(`error`,e),e}finally{c()}},_=async(t,r)=>{let{ctx:i,unlink:a}=n(t);try{return await e(i,`run`,r)}finally{a()}},v=(e,t,n,r={})=>{if(e.signal.aborted)return Promise.resolve();let a=r.leading??!1,c=r.waitForFn??!1;return g(`poll`,e,e=>new Promise((r,l)=>{let u=0,d=null,f=()=>{d!==null&&(o(d),d=null)},p=e=>{try{d=s(m,typeof n==`function`?n(e):n)}catch(e){f(),l(e)}},m=()=>{d=null,c||p(u+1),h()},h=()=>{let n=u++;_(e,()=>t(n)).then(()=>{c&&!e.signal.aborted&&p(u)},e=>{f(),l(e)})};i(e,f),a?(h(),c||p(u)):p(0)})).catch(t=>{if(!e.signal.aborted)throw t})};async function y(e,t){let n=u(t);if(Object.keys(t).length===0)return n;let r=d(t,`race`,e);try{let[e,t]=await r.until(Promise.race(r.tasks.map(([e,t])=>t.then(t=>[e,t]))));return n[e]=t,r.settle(`done`),n}catch(e){throw r.settle(`error`,e),e}finally{r.unfollowParent(),r.cancelAll()}}const b=(e,t,n)=>typeof e==`function`?e(t,n):e,x=e=>({times:e.times??3,delay:e.delay??0,shouldRetry:e.shouldRetry??(()=>!0)}),S=(e,t,n={})=>g(`retry`,e,async e=>{let{times:r,delay:i,shouldRetry:a}=x(n);for(let n=1;;n++)try{return await _(e,()=>t(n))}catch(t){if(e.signal.throwIfAborted(),n>=r||!a(t,n))throw t;let o=b(i,n,t);o>0&&await c(e,o)}}),C=(e,t,n={})=>g(`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))})),w=(t,r,i)=>g(`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({signal:a.ctx.signal,abort:a.ctx.abort}))),a.ctx)}finally{o(c),a.unlink()}});export{f as all,m as allSettled,h as cancellable,c as delay,i as onAbort,v as poll,y as race,S as retry,C as take,w as timeout};
@@ -0,0 +1 @@
1
+ const e=e=>typeof e==`string`?e:e.type,t=(e,t)=>typeof e==`object`?e.payload:t;export{t as n,e as t};
@@ -0,0 +1 @@
1
+ export {}
@@ -0,0 +1,3 @@
1
+ import { A as Keys, C as WithPayload, D as anyEventType, E as Tracer, F as TraceEvent, I as TraceLogger, L as UnsubscribeCallback, M as Phase, N as Task, O as EffectName, P as Trace, S as WithContext, T as createBus, _ as EventPayload, a as AnyEvent, b as Off, c as Command, d as ContextOf, f as ContextOption, g as EventLike, h as EventKey, i as Action, j as PayloadOf, k as EventMap, l as Commands, m as Emittable, o as Bus, p as Emit, s as BusOptions, u as Context, v as Handler, w as WithType, x as On, y as HandlerRef } from "./action-BM-UdmJr.js";
2
+ import "./index-CaxrMD1A.js";
3
+ export { type Action, type AnyEvent, type Bus, type BusOptions, type Command, 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, createBus };
@@ -0,0 +1 @@
1
+ export{n as anyEventType,t as createBus}from"./bus-CFxgpsRL.js";
@@ -0,0 +1,171 @@
1
+ import { N as Task, k as EventMap } from "./action-BM-UdmJr.js";
2
+ //#region src/policies/keyed.d.ts
3
+ /** Options shared by every policy that can keep its state per key. */
4
+ type KeyOption<P> = {
5
+ /**
6
+ * Gives each key its own state: calls with different keys do not affect
7
+ * each other. The state of a key is dropped when that key goes idle, so
8
+ * keys can be unbounded (ids, urls).
9
+ */
10
+ key?: (payload: P) => unknown;
11
+ };
12
+ //#endregion
13
+ //#region src/policies/debounce.d.ts
14
+ type DebounceResult<R> = Promise<R | undefined> | Promise<Awaited<R> | undefined> | undefined;
15
+ type DebounceOptions<P = never> = KeyOption<P> & {
16
+ /** Run the first call of a burst at once. Default `false`. */
17
+ leading?: boolean;
18
+ /** Run the last call of a burst after `ms` of quiet. Default `true`. */
19
+ trailing?: boolean;
20
+ };
21
+ /**
22
+ * Waits for `ms` of quiet, then runs; a new call restarts the wait and drops
23
+ * the previous. With `leading` the first call of a burst runs at once, and the
24
+ * trailing run happens only if more calls follow it. With `trailing: false`
25
+ * only the leading call runs. With `options.key` each key has its own wait.
26
+ *
27
+ * @example
28
+ * ```ts
29
+ * bus.on(
30
+ * "input",
31
+ * debounce(300, async (text, { signal }) => {
32
+ * const res = await fetch(`/api?q=${text}`, { signal });
33
+ * showResults(await res.json());
34
+ * }),
35
+ * );
36
+ *
37
+ * bus.emit("input", "r");
38
+ * bus.emit("input", "re"); // only the last call runs, 300 ms after it
39
+ * ```
40
+ */
41
+ export declare const debounce: <P, E extends EventMap, R>(ms: number, fn: Task<P, E, R>, options?: DebounceOptions<P>) => Task<P, E, DebounceResult<R>>;
42
+ //#endregion
43
+ //#region src/policies/latest.d.ts
44
+ type LatestOptions<P = never> = KeyOption<P>;
45
+ /**
46
+ * Aborts the previous run when a new call arrives; stale results are dropped.
47
+ * With `options.key` each key has its own latest run.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * bus.on(
52
+ * "search",
53
+ * latest(async (query, { signal }) => {
54
+ * const res = await fetch(`/api?q=${query}`, { signal });
55
+ * showResults(await res.json());
56
+ * }),
57
+ * );
58
+ *
59
+ * bus.emit("search", "re"); // aborted by the next call
60
+ * bus.emit("search", "redux"); // only this one finishes
61
+ *
62
+ * // one latest run per user instead of one for all
63
+ * bus.on("load", latest(loadUser, { key: (user) => user.id }));
64
+ * ```
65
+ */
66
+ export declare const latest: <P, E extends EventMap, R>(fn: Task<P, E, R>, options?: LatestOptions<P>) => Task<P, E, R | Promise<Awaited<R> | undefined> | undefined>;
67
+ //#endregion
68
+ //#region src/policies/leading.d.ts
69
+ type LeadingOptions<P = never> = KeyOption<P>;
70
+ /**
71
+ * Drops new calls while the task is still running. The lock is released when
72
+ * the run settles or when its task is aborted, whichever comes first, so a
73
+ * `fn` that ignores the abort signal may overlap with the next run. With
74
+ * `options.key` each key has its own lock.
75
+ *
76
+ * @example
77
+ * ```ts
78
+ * bus.on(
79
+ * "save",
80
+ * leading(async (draft) => {
81
+ * await api.save(draft);
82
+ * }),
83
+ * );
84
+ *
85
+ * bus.emit("save", draft); // runs
86
+ * bus.emit("save", draft); // dropped while the first save is in flight
87
+ * ```
88
+ */
89
+ export declare const leading: <P, E extends EventMap, R>(fn: Task<P, E, R>, options?: LeadingOptions<P>) => Task<P, E, R | Promise<Awaited<R>> | undefined>;
90
+ //#endregion
91
+ //#region src/policies/queue.d.ts
92
+ type QueueOptions<P = never> = KeyOption<P> & {
93
+ /** How many calls may run at the same time. Default 1. */
94
+ concurrency?: number;
95
+ /** How many calls may wait for a free slot. Default: no limit. */
96
+ limit?: number;
97
+ /**
98
+ * What to drop when a call arrives and `limit` calls already wait: the new
99
+ * call (`"drop-new"`, the default) or the oldest waiting one (`"drop-old"`,
100
+ * which keeps the most recent calls). A dropped call resolves with `undefined`.
101
+ */
102
+ overflow?: "drop-new" | "drop-old";
103
+ };
104
+ /**
105
+ * Runs calls one after another, in the order they arrived: a call starts when
106
+ * fewer than `concurrency` calls are running. Every call returns a promise with
107
+ * the result of its own run; an error rejects only that call, and the queue
108
+ * goes on. The first call on an idle queue starts synchronously.
109
+ *
110
+ * With `limit` the number of waiting calls is capped. `limit: 1` with
111
+ * `overflow: "drop-old"` keeps only the latest call while one is running, and
112
+ * runs it when the current one is done.
113
+ *
114
+ * With `options.key` each key has its own line.
115
+ *
116
+ * A call whose task aborts while it waits is skipped and resolves with
117
+ * `undefined`. When the task of a running call aborts, its slot is freed at
118
+ * once and its result is dropped; a `fn` that ignores the abort signal can
119
+ * then overlap with the next run.
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * bus.on(
124
+ * "save",
125
+ * queue(async (draft, { signal }) => {
126
+ * await api.save(draft, { signal });
127
+ * }),
128
+ * );
129
+ *
130
+ * bus.emit("save", a); // runs
131
+ * bus.emit("save", b); // waits for a, then runs
132
+ * ```
133
+ */
134
+ export declare const queue: <P, E extends EventMap, R>(fn: Task<P, E, R>, options?: QueueOptions<P>) => Task<P, E, Promise<Awaited<R> | undefined>>;
135
+ //#endregion
136
+ //#region src/policies/throttle.d.ts
137
+ type ThrottleOptions<P = never> = KeyOption<P> & {
138
+ /** Run the first call at once, when the throttle is idle. Default `true`. */
139
+ leading?: boolean;
140
+ /** Run the latest call made while waiting, at the end of the window. Default `true`. */
141
+ trailing?: boolean;
142
+ };
143
+ /**
144
+ * At most one run per `ms`, with the semantics of lodash `throttle` (and
145
+ * patronum): a call made when the throttle is idle, that is, at least `ms`
146
+ * after the previous call and the previous run, runs at once (`leading`); calls
147
+ * made while it waits are held, and the latest of them runs when the window
148
+ * closes (`trailing`). Under a steady stream of calls it runs every `ms`.
149
+ *
150
+ * A held call returns a promise that settles with its result; calls superseded
151
+ * by a newer one, or not allowed to wait (`trailing: false`), resolve with
152
+ * `undefined`. With `leading: false` even the first call waits for the end of
153
+ * its window. With `options.key` each key has its own throttle.
154
+ *
155
+ * @example
156
+ * ```ts
157
+ * bus.on(
158
+ * "scroll",
159
+ * throttle(200, (position) => {
160
+ * saveScrollPosition(position);
161
+ * }),
162
+ * );
163
+ *
164
+ * bus.emit("scroll", 10); // runs now
165
+ * bus.emit("scroll", 20); // superseded
166
+ * bus.emit("scroll", 30); // runs once the 200 ms window closes
167
+ * ```
168
+ */
169
+ export declare const throttle: <P, E extends EventMap, R>(ms: number, fn: Task<P, E, R>, options?: ThrottleOptions<P>) => Task<P, E, R | Promise<R | undefined> | undefined>;
170
+ //#endregion
171
+ export type { DebounceOptions, LatestOptions, LeadingOptions, QueueOptions, ThrottleOptions };
@@ -0,0 +1 @@
1
+ import{a as e,i as t,o as n,s as r,t as i}from"./context-DGPIFXxI.js";import{n as a,r as o,t as s}from"./delay-Cko_Q9hl.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={})=>{let n=t=>p(`latest`,(t,n,r)=>(r(),e(t,n)),t);return t.key?d(t.key,n):n(u)},p=(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}}},m=(e,t,n={})=>{let r=r=>g(e,t,n,r);return n.key?d(n.key,r):r(u)},h=(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))}},g=(t,n,i,a)=>{let o=i.leading??!1,c=i.trailing??!0;if(!c)return h(t,n,o,a);let l=!1,u=0,d=p(`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}},_=(t,i={})=>{let a=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}}};return i.key?d(i.key,a):a(u)},v=(e,t={})=>{let n=n=>y(e,t,n);return t.key?d(t.key,n):n(u)},y=(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),_()})})},b=(e,t,n={})=>{let r=r=>x(e,t,n,r);return n.key?d(n.key,r):r(u)},x=(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{m as debounce,f as latest,_ as leading,v as queue,b as throttle};