nanoeffects 0.7.0 → 0.9.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 (76) hide show
  1. package/README.md +2 -2
  2. package/dist/{action-creator-Bd4TBZgl.d.ts → action-creator-BrZF6hXc.d.ts} +0 -4
  3. package/dist/actions.d.ts +41 -25
  4. package/dist/actions.js +1 -1
  5. package/dist/bus-CkTHUAvq.js +1 -0
  6. package/dist/context-COgyNlrC.js +1 -0
  7. package/dist/{context-plugin-BVNKqkIx.d.ts → context-plugin--HkNN1ha.d.ts} +1 -1
  8. package/dist/dev.d.ts +9 -8
  9. package/dist/dev.js +1 -1
  10. package/dist/effects.d.ts +2 -2
  11. package/dist/effects.js +1 -1
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.js +1 -1
  14. package/dist/match.d.ts +50 -0
  15. package/dist/match.js +1 -0
  16. package/dist/{module-DZ5ngUrM.d.ts → module-DqKegXHt.d.ts} +43 -18
  17. package/dist/notrace/{action-creator-D-y_-xRS.d.ts → action-creator-DHAEgwuh.d.ts} +0 -4
  18. package/dist/notrace/actions.d.ts +90 -39
  19. package/dist/notrace/actions.js +1 -1
  20. package/dist/notrace/bus-BmCTo8BG.js +1 -0
  21. package/dist/notrace/{context-plugin-DDfsaErA.d.ts → context-plugin-BapQkGwQ.d.ts} +1 -1
  22. package/dist/notrace/context-yYU3_9lq.js +1 -0
  23. package/dist/notrace/{delay-B_W1tnkS.js → delay-BosJKFjg.js} +1 -1
  24. package/dist/notrace/effects.d.ts +2 -2
  25. package/dist/notrace/effects.js +1 -1
  26. package/dist/notrace/index.d.ts +2 -2
  27. package/dist/notrace/index.js +1 -1
  28. package/dist/notrace/{plugin-CDAngHwg.d.ts → plugin-Cxadz6uU.d.ts} +2 -2
  29. package/dist/notrace/policies.d.ts +30 -2
  30. package/dist/notrace/policies.js +1 -1
  31. package/dist/notrace/redux.d.ts +1 -1
  32. package/dist/observable.d.ts +1 -1
  33. package/dist/oop.d.ts +131 -0
  34. package/dist/oop.js +1 -0
  35. package/dist/{plugin-DQNPBcxx.d.ts → plugin-DkXCvsmB.d.ts} +2 -2
  36. package/dist/policies.d.ts +3 -2
  37. package/dist/policies.js +1 -1
  38. package/dist/react.d.ts +33 -1
  39. package/dist/react.js +1 -1
  40. package/dist/redux.d.ts +1 -1
  41. package/dist/scope.d.ts +5 -6
  42. package/dist/scope.js +1 -1
  43. package/dist/signal.d.ts +51 -0
  44. package/dist/signal.js +1 -0
  45. package/dist/trace.d.ts +1 -1
  46. package/dist/{types-BJ0fzV1p.d.ts → types-KavbvHix.d.ts} +13 -3
  47. package/dist/with-policy-CqUS-VWW.d.ts +30 -0
  48. package/dist/with-policy-DBV9dh2F.js +1 -0
  49. package/docs/README.md +7 -0
  50. package/docs/actions.md +152 -39
  51. package/docs/cancel-stale-requests.md +111 -0
  52. package/docs/debounce-and-abort.md +106 -0
  53. package/docs/guide.md +143 -19
  54. package/docs/hmr.md +6 -5
  55. package/docs/migrating-from-effector.md +51 -18
  56. package/docs/migrating-from-mitt.md +97 -0
  57. package/docs/migrating-from-rxjs.md +17 -6
  58. package/docs/motivation.md +41 -0
  59. package/docs/observable.md +124 -10
  60. package/docs/oop.md +286 -0
  61. package/docs/package.md +6 -2
  62. package/docs/plugins.md +247 -51
  63. package/docs/policies.md +33 -0
  64. package/docs/prevent-double-submit.md +128 -0
  65. package/docs/query-libraries.md +124 -0
  66. package/docs/react.md +61 -5
  67. package/docs/scope.md +60 -22
  68. package/docs/stores.md +263 -109
  69. package/llms-full.txt +2153 -355
  70. package/llms.txt +10 -3
  71. package/package.json +43 -4
  72. package/skills/nanoeffects/SKILL.md +52 -0
  73. package/dist/bus-BAs9x7IQ.js +0 -1
  74. package/dist/context-CK0ZomWt.js +0 -1
  75. package/dist/notrace/bus-Bdk0YyFQ.js +0 -1
  76. package/dist/notrace/context-CctVmHLC.js +0 -1
package/README.md CHANGED
@@ -88,8 +88,8 @@ Start with the [Guide](docs/guide.md) (bus → policies → effects → modules)
88
88
  | Domain logic off the UI | [Actions, commands, modules](docs/actions.md) |
89
89
  | Redux / Zustand / MobX | [Stores](docs/stores.md) |
90
90
 
91
- [Full index, package entries, tracing](docs/README.md) · [Examples](examples/README.md)
91
+ [Full index, package entries, tracing](docs/README.md) · [Examples](examples/README.md) · [Why nanoeffects exists](docs/motivation.md)
92
92
 
93
- - **Tiny.** `createBus` is about 1.3 kB gzip; other entries load only when imported.
93
+ - **Tiny.** `createBus` is about 1.4 kB gzip (1.3 kB brotli); other entries load only when imported.
94
94
  - **Cancellation first.** Aborting a task aborts its children and drops its result.
95
95
  - **One model** instead of hand-rolled `AbortController`, lodash debounce, and retry glue.
@@ -224,10 +224,6 @@ interface Bus<E extends EventMap> {
224
224
  readonly trace?: Tracer | undefined;
225
225
  /** Called with every new task context to add fields to it, for what needs the task, like `effectsPlugin`. Chain to the previous one. */
226
226
  addContext?: ((ctx: object) => void) | undefined;
227
- /** Puts the fields of a module's scope on the context of one of its tasks; `scopePlugin` sets it. Without it a module's scope is ignored. */
228
- applyScope?: ((ctx: object, scope: Scope) => void) | undefined;
229
- /** Wraps a handler so it runs with the fields of a module's scope; `scopePlugin` sets it. */
230
- fitScope?: ((scope: Scope, fn: unknown) => unknown) | undefined;
231
227
  }
232
228
  type BusOptions<E extends EventMap> = {
233
229
  /** Tracing of every task phase; make it with `createTracer` from `nanoeffects/trace`. */
package/dist/actions.d.ts CHANGED
@@ -1,6 +1,6 @@
1
- import { B as EventMap, H as PayloadOf, T as EventKey, W as Task, c as WithScope, h as Bus, n as Free, o as Scope, r as FreeActionCreator, t as ActionCreator } from "./action-creator-Bd4TBZgl.js";
2
- import { n as Scoped, t as FieldsOfScope } from "./types-BJ0fzV1p.js";
3
- import { a as modulePlugin, c as MadeCommand, d as createCommand, i as createModule, l as bindHandler, n as ModuleApi, o as Binding, r as ModuleContext, s as CarryingCalls, t as Module, u as commandsPlugin } from "./module-DZ5ngUrM.js";
1
+ import { B as EventMap, H as PayloadOf, T as EventKey, W as Task, c as WithScope, h as Bus, n as Free, o as Scope, r as FreeActionCreator, t as ActionCreator } from "./action-creator-BrZF6hXc.js";
2
+ import { r as Scoped, t as FieldsOfScope } from "./types-KavbvHix.js";
3
+ import { a as createModule, c as CarryingCalls, d as commandsPlugin, f as createCommand, l as MadeCommand, n as ModuleApi, o as modulePlugin, r as ModuleContext, s as Binding, t as Module, u as bindHandler } from "./module-DqKegXHt.js";
4
4
  //#region src/actions/action.d.ts
5
5
  type ScopedCreator<P, T extends string, F> = [P] extends [Free] ? FreeActionCreator<T, F> & WithScope<F> : ActionCreator<P, T, PayloadOf<P>, F> & WithScope<F>;
6
6
  /**
@@ -87,55 +87,71 @@ type Creator = {
87
87
  readonly type: string;
88
88
  };
89
89
  type Outcome = string | Creator;
90
- /** What `createJob` returns: the command of the job, with its two actions as properties. */
91
- type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = MadeCommand<P, Promise<Awaited<R> | undefined>, T> & {
90
+ /** What `createJob` returns: the command of the job, with its four actions as properties. */
91
+ type Job<P, R, T extends string, S extends Outcome, F extends Outcome, PE extends Outcome = `${T}/pending`, CE extends Outcome = `${T}/cancel`> = MadeCommand<P, Promise<Awaited<R> | undefined>, T> & {
92
+ /** Made from a string with the payload of the call as its payload, or the creator that was given. */
93
+ readonly pending: PE extends string ? ActionCreator<P, PE> : PE;
92
94
  /** Made from a string with the result as its payload, or the creator that was given. */
93
95
  readonly success: S extends string ? ActionCreator<Awaited<R>, S> : S;
94
96
  /** Made from a string with the error as its payload, or the creator that was given. */
95
97
  readonly fail: F extends string ? ActionCreator<unknown, F> : F;
98
+ /** Made from a string with the abort reason as its payload, or the creator that was given. */
99
+ readonly cancel: CE extends string ? ActionCreator<unknown, CE> : CE;
96
100
  };
97
101
  /**
98
102
  * Creates a job: a command whose outcome is sent on as actions. When the
99
- * handler succeeds, `job.success(result)` is emitted on the bus, and when it
100
- * fails, `job.fail(error)`. It is made for the case where nobody waits for
101
- * the result and the bus carries it on, like `createAsyncThunk` or an effector
102
- * effect. It returns the command, with the two actions on it: `job.success` and
103
- * `job.fail`.
103
+ * handler starts, `job.pending(payload)` is emitted on the bus. When it
104
+ * succeeds, `job.success(result)` follows, and when it fails, `job.fail(error)`.
105
+ * When the task is aborted after it started, `job.cancel(reason)` follows
106
+ * instead. After `pending`, exactly one of the three closes the call. A job is
107
+ * made for the case where nobody waits for the result and the bus carries it
108
+ * on, like `createAsyncThunk` or an effector effect. It returns the command,
109
+ * with the four actions on it.
104
110
  *
105
111
  * A scope as the last argument, `{ cache, $effects: { race } }`, gives the handler
106
112
  * and the listeners of the outcome those context fields; see `scopePlugin`.
107
113
  *
108
- * `success` and `fail` are a type string, from which the job makes an action
109
- * creator with `createAction`, or an action creator that exists already, which
110
- * is used and returned as it is. A missing one is made with the type
111
- * `<type>/success` or `<type>/fail`.
114
+ * `pending`, `success`, `fail` and `cancel` are a type string, from which the
115
+ * job makes an action creator with `createAction`, or an action creator that
116
+ * exists already, which is used and returned as it is. A missing one is made
117
+ * with the type `<type>/pending`, `<type>/success`, `<type>/fail` or
118
+ * `<type>/cancel`.
112
119
  *
113
120
  * `bus.emit(job(payload))` returns a promise of the result. An error of the
114
121
  * handler always counts as handled: it goes to `job.fail` and the promise
115
122
  * resolves with `undefined`; a command is the tool for a result that must reject.
116
123
  * The actions are emitted as the task that ran the job, also for a handler bound
117
- * with `commands.handle`, and are skipped once the task is aborted. A missing
118
- * handler is not an outcome: `emit` throws `MissingHandlerError`. Calling the
119
- * job builds `{ type, payload }` like a command; it does not run the handler.
124
+ * with `commands.handle`. Once the task is aborted, `success` and `fail` are
125
+ * skipped and `cancel` is sent when the handler settles (a handler that never
126
+ * settles sends nothing). A call that does not start, because a policy drops it
127
+ * or it is aborted while it waits in a `queue`, sends none of the four. A
128
+ * missing handler is not an outcome: `emit` throws `MissingHandlerError`.
129
+ * Calling the job builds `{ type, payload }` like a command; it does not run
130
+ * the handler.
120
131
  *
121
132
  * @example
122
133
  * ```ts
123
- * const loadUser = createJob("user/load", fetchUser, {
124
- * success: "user/loaded",
125
- * fail: "user/failed",
126
- * });
134
+ * const loadUser = createJob("user/load", fetchUser);
135
+ * let loading = false;
127
136
  *
128
- * bus.on(loadUser.success, (user) => render(user));
129
- * bus.emit(loadUser("1")); // loadUser.success(user) or loadUser.fail(error) comes later
137
+ * bus.on(loadUser.pending, () => { loading = true; });
138
+ * bus.on(loadUser.success, (user) => { loading = false; render(user); });
139
+ * bus.on(loadUser.fail, () => { loading = false; });
140
+ * bus.on(loadUser.cancel, () => { loading = false; });
141
+ * bus.emit(loadUser("1")); // pending now, then success, fail or cancel
130
142
  * ```
131
143
  */
132
- export declare const createJob: <P = void, R = void, T extends string = string, E extends EventMap = EventMap, S extends Outcome = `${T}/success`, F extends Outcome = `${T}/fail`, X extends Scope = Record<never, never>>(type: T, handler?: Task<P, Scoped<E, X>, R>, outcomes?: {
144
+ export declare const createJob: <P = void, R = void, T extends string = string, E extends EventMap = EventMap, S extends Outcome = `${T}/success`, F extends Outcome = `${T}/fail`, PE extends Outcome = `${T}/pending`, CE extends Outcome = `${T}/cancel`, X extends Scope = Record<never, never>>(type: T, handler?: Task<P, Scoped<E, X>, R>, outcomes?: {
145
+ /** Gets the payload of the call when the handler starts: a type to make an action creator of, or an action creator. */
146
+ pending?: PE;
133
147
  /** Gets the result when the handler succeeds: a type to make an action creator of, or an action creator. */
134
148
  success?: S;
135
149
  /** Gets the error when the handler fails: a type to make an action creator of, or an action creator. */
136
150
  fail?: F;
151
+ /** Gets the abort reason when the task is aborted before the handler settles: a type to make an action creator of, or an action creator. */
152
+ cancel?: CE;
137
153
  },
138
154
  /** Context values and `$effects` for the handler and for the listeners of the outcome; see `scopePlugin`. */
139
- scope?: X) => CarryingCalls<Job<P, R, T, S, F>, P, Promise<Awaited<R> | undefined>, FieldsOfScope<E, X>>;
155
+ scope?: X) => CarryingCalls<Job<P, R, T, S, F, PE, CE>, P, Promise<Awaited<R> | undefined>, FieldsOfScope<E, X>>;
140
156
  //#endregion
141
157
  export { type ActionCreator, type Binding, type EmitterApi, type FreeActionCreator, type Job, type Module, type ModuleApi, type ModuleContext, bindHandler, commandsPlugin, createCommand, createModule, modulePlugin };
package/dist/actions.js CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./onAbort-BgMfspK4.js";import{i as t,n}from"./context-CK0ZomWt.js";import{t as r}from"./event-0RIBGYqS.js";import{r as i}from"./bus-BAs9x7IQ.js";import{t as a}from"./scope-key-B7l7mUS5.js";const o=(e,t)=>(t&&Object.defineProperty(e,a,{value:t}),e),s=(e,t)=>({...e,...t,$effects:{...e.$effects,...t.$effects}}),c=e=>Reflect.get(e,a);function l(e,t,n){let r=typeof t==`function`?t:void 0,i=typeof t==`function`?n:t;return Object.assign(o((...t)=>o({type:e,payload:r?r(...t).payload:t[0]},i),i),{type:e,match:t=>t.type===e,toString:()=>e})}var u=class extends Error{};function d(e,t,n){let r=t=>t.type===e;function a(r,a){if(typeof a==`object`){if(!t)throw new u(`No handler for command "${e}"`);return t(r,a)}return o(i(c,e,r),n)}let s=Object.assign(a,{type:e,match:r}),c=o(s,n);return c}const f=(e,t)=>[e,t],p=(e=[])=>t=>{let n=/* @__PURE__ */ new Map,i=(e,t)=>{let r={fn:t};return n.set(e,[...n.get(e)??[],r]),()=>{let t=(n.get(e)??[]).filter(e=>e!==r);t.length>0?n.set(e,t):n.delete(e)}};function a(e,t){if(t)return i(r(e),t);let n=e.map(([e,t])=>i(r(e),t));return()=>{for(let e of n)e()}}a(e);let o={run:(e,t,r)=>{let i=(n.get(e.type)??[]).at(-1)?.fn,a=i&&e.wrap?e.wrap(i):i??e;return Reflect.apply(a,null,[t,r])},handle:a};return t.commands=o,o},m=()=>e=>{function t(t){return(...n)=>{let r=t(...n);e.emit(r)}}return Object.assign(e,{emitter:t})},h=e=>typeof e==`string`?l(e):e,g=(e,t,n,r)=>{let i=c(t);e.emit(Reflect.apply(t,null,[n]),r&&i?s(r,i):r)},_=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof u)throw e;return Promise.reject(e)}},v=(e,t,n={},r)=>{let a=d(e,t),s=h(n.success??`${e}/success`),c=h(n.fail??`${e}/fail`),l=(e,t,n)=>{let i=n;return _(()=>Reflect.apply(e,null,[t,n])).then(e=>(g(i,s,e,r),e),e=>{g(i,c,e,r)})},u=e=>(t,n)=>l(e,t,n);function f(t,n){return typeof n==`object`?l(a,t,n):o(i(m,e,t),r)}let p=Object.assign(f,{type:e,match:a.match,wrap:u,success:s,fail:c}),m=o(p,r);return m};function y(e,t,n){return n?{name:e,setup:t,scope:n}:{name:e,setup:t}}const b=(e,t)=>n=>t?e.fitScope?.(t,n)??n:n,x=(e,t,n)=>{n&&e.applyScope?.(t,n)},S=(e,t,n)=>Array.isArray(t)?[t.map(([t,n])=>[t,e(n)]),n]:[t,e(n)],C=(e,t)=>{let n=e.on;return(...e)=>{let[r,i]=e;return Reflect.apply(n,null,[r,t(i)])}},w=e=>(t,...n)=>{e.run(t,...n).catch(t=>{if(!e.signal.aborted)throw t})},T=(r=[])=>i=>{let a=i.commands??p()(i),o={handle:(...e)=>{if(!a.handle)throw Error("modulePlugin: the `commands` of the bus is not a registry from `commandsPlugin()`");return Reflect.apply(a.handle,null,e)}},s=n({event:{type:`app`,payload:void 0},bus:i,tracer:i.trace}),c=n=>{let r=/* @__PURE__ */ new Map,a=/* @__PURE__ */ new Map;return{mount:s=>{let l=r.get(s);if(l)return l;let u=a.get(s.name);u&&r.get(u)?.();let d=t(n,s.name),f=d.ctx,p=c(f),m=()=>{r.delete(s),a.get(s.name)===s&&a.delete(s.name),f.abort(),d.unlink()};r.set(s,m),a.set(s.name,s);let h=s.scope,g=b(i,h),_=(t,n)=>{let r=Reflect.apply(o.handle,null,S(g,t,n));return e(f,r),r},v=(...e)=>{let t=e.map(e=>typeof e==`function`?_(e,e):p.mount(e));return()=>{for(let e of t)e()}},y=w(f),T=C(f,g);try{x(i,f,h),s.setup(Object.assign(f,{handle:_,use:v,spawn:y,on:T}))}catch(e){throw m(),e}return m},unmount:e=>r.get(e)?.(),isMounted:e=>r.has(e)}},l=c(s.ctx);for(let e of r)l.mount(e);return{commands:a,mount:e=>(s.ctx.signal.throwIfAborted(),l.mount(e)),unmount:l.unmount,isMounted:l.isMounted,dispose:()=>s.ctx.abort(),createModule:y}};export{f as bindHandler,p as commandsPlugin,l as createAction,d as createCommand,v as createJob,y as createModule,m as emitterPlugin,T as modulePlugin};
1
+ import{n as e,t}from"./onAbort-BgMfspK4.js";import{i as n,n as r,s as i}from"./context-COgyNlrC.js";import{t as a}from"./event-0RIBGYqS.js";import{i as o}from"./bus-CkTHUAvq.js";import{t as s}from"./scope-key-B7l7mUS5.js";const c=(e,t)=>(t&&Object.defineProperty(e,s,{value:t}),e),l=(e,t)=>({...e,...t,$effects:{...e.$effects,...t.$effects}}),u=e=>Reflect.get(e,s);function d(e,t,n){let r=typeof t==`function`?t:void 0,i=typeof t==`function`?n:t;return Object.assign(c((...t)=>c({type:e,payload:r?r(...t).payload:t[0]},i),i),{type:e,match:t=>t.type===e,toString:()=>e})}var f=class extends Error{};function p(e,t,n){let r=t=>t.type===e;function i(r,i){if(typeof i==`object`){if(!t)throw new f(`No handler for command "${e}"`);return t(r,i)}return c(o(s,e,r),n)}let a=Object.assign(i,{type:e,match:r}),s=c(a,n);return s}const m=(e,t)=>[e,t],h=e=>typeof Reflect.get(e??{},`handle`)==`function`,g=(e=[])=>t=>{let n=t.commands;if(h(n))return n.handle(e),n;let r=/* @__PURE__ */ new Map,i=(e,t)=>{let n={fn:t};return r.set(e,[...r.get(e)??[],n]),()=>{let t=(r.get(e)??[]).filter(e=>e!==n);t.length>0?r.set(e,t):r.delete(e)}};function o(e,t){if(t)return i(a(e),t);let n=e.map(([e,t])=>i(a(e),t));return()=>{for(let e of n)e()}}o(e);let s={run:(e,t,n)=>{let i=(r.get(e.type)??[]).at(-1)?.fn,a=i&&e.wrap?e.wrap(i):i??e;return Reflect.apply(a,null,[t,n])},handle:o};return t.commands=s,s},_=()=>e=>{function t(t){return(...n)=>{let r=t(...n);e.emit(r)}}return Object.assign(e,{emitter:t})},v=e=>typeof e==`string`?d(e):e,y=(e,t,n,r)=>{let i=u(t);e.emit(Reflect.apply(t,null,[n]),r&&i?l(r,i):r)},b=(t,n,r)=>{let a=t;a[i]=!0;try{y(t,n,t.signal.reason,r)}catch(t){e(`cancel listener`,t)}a[i]=!1},x=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof f)throw e;return Promise.reject(e)}},S=(e,t,n={},r)=>{let i=p(e,t),a=t=>v(n[t]??`${e}/${t}`),s=a(`pending`),l=a(`success`),u=a(`fail`),d=a(`cancel`),f=(e,t,n)=>{let i=n;return x(()=>(y(i,s,t,r),Reflect.apply(e,null,[t,n]))).then(e=>(i.signal.aborted?b(i,d,r):y(i,l,e,r),e),e=>{i.signal.aborted?b(i,d,r):y(i,u,e,r)})},m=e=>(t,n)=>f(e,t,n);function h(n,a){return typeof a==`object`?t?f(i,n,a):Reflect.apply(i,null,[n,a]):c(o(_,e,n),r)}let g=Object.assign(h,{type:e,match:i.match,wrap:m,pending:s,success:l,fail:u,cancel:d}),_=c(g,r);return _},C=e=>typeof e==`object`&&!!e,w=e=>{if(typeof e==`string`)return e;if(C(e)||typeof e==`function`){let t=Reflect.get(e,`type`);return typeof t==`string`?t:e}return e},T=(e,t)=>{let[n,r]=e;return n===void 0||Object.is(w(n),w(t[0]))&&(r===void 0||Object.is(r,t[1]))},E=e=>{let t={on:e.on,once:e.once,off:e.off},n=[],r=!0,i=(t,n)=>Reflect.apply(t,e,n),a=(e,t)=>(...a)=>{if(!r)return i(t,a);let o={kind:e,args:a,dropped:!1};return n.push(o),()=>{o.live?o.live():o.dropped=!0}},o=e=>(...t)=>{if(!r)return i(e,t);for(let e of n)e.kind!==`off`&&T(t,e.args)&&(e.dropped=!0);n.push({kind:`off`,args:t,dropped:!1})},s=a(`on`,t.on),c=a(`once`,t.once),l=o(t.off);return e.on=s,e.once=c,e.off=l,{release:()=>{r=!1,e.on===s&&(e.on=t.on),e.once===c&&(e.once=t.once),e.off===l&&(e.off=t.off)},replay:()=>{for(let e of n.splice(0))if(!e.dropped){if(e.kind===`off`)i(t.off,e.args);else{let n=e.kind===`on`?t.on:t.once;e.live=i(n,e.args)}}}}};function D(e,t,n){return n?{name:e,setup:t,scope:n}:{name:e,setup:t}}const O=(e,t)=>n=>t?e.fitScope?.(t,n)??n:n,k=(e,t,n)=>{n&&e.applyScope?.(t,n)},A=(e,t,n)=>Array.isArray(t)?[t.map(([t,n])=>[t,e(n)]),n]:[t,e(n)],j=(e,t)=>{let n=e.on;return(...e)=>{let[r,i]=e;return Reflect.apply(n,null,[r,t(i)])}},M=e=>(t,...n)=>{e.run(t,...n).catch(t=>{if(!e.signal.aborted)throw t})},N=(e=[])=>i=>{let a=i.commands??g()(i),o={handle:(...e)=>{if(!a.handle)throw Error("modulePlugin: the `commands` of the bus is not a registry from `commandsPlugin()`");return Reflect.apply(a.handle,null,e)}},s=e=>{let r=/* @__PURE__ */ new Map,a=/* @__PURE__ */ new Map;return{mount:c=>{let l=r.get(c);if(l)return l;let u=a.get(c.name);u&&r.get(u)?.();let d=n(e,c.name),f=d.ctx,p=s(f),m=()=>{r.delete(c),a.get(c.name)===c&&a.delete(c.name),f.abort(),d.unlink()};r.set(c,m),a.set(c.name,c);let h=c.scope,g=O(i,h),_=(e,n)=>{let r=Reflect.apply(o.handle,null,A(g,e,n));return t(f,r),r},v=(...e)=>{let t=e.map(e=>typeof e==`function`?_(e,e):p.mount(e));return()=>{for(let e of t)e()}},y=M(f),b=j(f,g);try{k(i,f,h),c.setup(Object.assign(f,{handle:_,use:v,spawn:y,on:b}))}catch(e){throw m(),e}return m},unmount:e=>r.get(e)?.(),isMounted:e=>r.has(e)}},c=E(i),l=i.emit,u,d=(t=!0)=>{if(u)return u;c.release(),i.emit===f&&(i.emit=l);let n=r({event:{type:`app`,payload:void 0},bus:i,tracer:i.trace});if(u={root:n,apps:s(n.ctx)},t)for(let t of e)u.apps.mount(t);return c.replay(),u},f=(...e)=>(d(),Reflect.apply(l,i,e));i.emit=f;let p={get commands(){return d(),a},mount:e=>{let{root:t,apps:n}=d();return t.ctx.signal.throwIfAborted(),n.mount(e)},unmount:e=>d().apps.unmount(e),isMounted:e=>d().apps.isMounted(e),dispose:()=>d(!1).root.ctx.abort(),createModule:D};return i.app=p,p};export{m as bindHandler,g as commandsPlugin,d as createAction,p as createCommand,S as createJob,D as createModule,_ as emitterPlugin,N as modulePlugin};
@@ -0,0 +1 @@
1
+ import{n as e}from"./onAbort-BgMfspK4.js";import{a as t,n,r}from"./context-COgyNlrC.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={},n=n=>(t[n]=void 0,e[n]??=/* @__PURE__ */ new Map,e[n]),r=(e,t)=>{let r=n(e),i=r.get(t)??0;i>1?r.set(t,i-1):t?r.delete(t):r.clear()};return{get:n=>(t[n]??=[...e[n]??[]].flatMap(([e,t])=>Array(t).fill(e)),t[n]),add:(e,t)=>{let i=n(e);return i.set(t,(i.get(t)??0)+1),()=>{r(e,t)}},remove:r,clear:()=>{for(let t of Reflect.ownKeys(e))delete e[t];for(let e of Reflect.ownKeys(t))delete t[e]}}},l=Symbol(),u=(e,t,n)=>{let r={type:t,payload:n};return Object.defineProperty(r,l,{value:e,enumerable:!1}),r},d=e=>{if(typeof e==`function`)return e;if(typeof e==`object`&&e&&l in e)return e[l]},f=(e,t,n)=>Reflect.apply(e,null,[t,n]),p=(s={})=>{let l=c(),u=(e,t)=>l.add(o(e),t),p=(e,t)=>{let n=u(e,(e,r)=>(n(),t(e,r)));return n},m=(e,t)=>{e===void 0?l.clear():l.remove(o(e),t)},h=(t,a)=>{let{onError:o}=s,{ctx:c}=n({event:a,bus:g,tracer:s.trace,parent:{ref:r()}});if(!o){t(a.payload,c);return}let l=t=>{try{o(t,a)}catch(t){e(`onError failed`,t)}};try{let e=t(a.payload,c);i(e)&&Promise.resolve(e).catch(l)}catch(e){l(e)}},g={on:u,once:p,off:m,emit:(e,i)=>{let c=o(e),u=a(e,i),p={type:c,payload:u},m=d(e),_=[...l.get(c),...l.get(`*`)];_.length===0&&!m&&s.onUnhandled?.(p);for(let e of _)h(e,p);if(m){let{ctx:e}=n({event:p,bus:g,tracer:s.trace,parent:{ref:r()}}),i=g.commands?.run??f;return t(e,`command`,()=>i(m,u,e))}},use:e=>e(g),ctx:s.context,trace:s.trace};return g};export{s as a,u as i,d as n,p as r,l as t};
@@ -0,0 +1 @@
1
+ import{t as e}from"./onAbort-BgMfspK4.js";const t=t=>{let n=new AbortController;return{controller:n,unlink:e({signal:t},e=>n.abort(e))}},n=Symbol(),r=typeof __NANOEFFECTS_TRACE__>`u`||__NANOEFFECTS_TRACE__,i=/* @__PURE__ */ new WeakMap;let a;const o=()=>a,s=()=>{},c=(e,t,n,a)=>{let o=r&&i.get(e);o&&o.tracer.report(o.ref,t,n,a)},l=(e,t)=>{let n=r&&i.get(e);return n?n.tracer.settler(n.ref,t):s},u=(e,t,n)=>{let a=r&&i.get(e);return a?a.tracer.run(a.ref,t,e.signal,n):n()},d=(e,t)=>typeof e==`function`?e(t):e,f=({event:o,bus:c,tracer:l,parent:p})=>{let{controller:m,unlink:h}=t(p?.signal),{signal:g}=m,_=r&&l?{tracer:l,ref:l.task(o,p?.ref)}:void 0,v=(...e)=>{if(g.aborted&&!x[n])return;let t=c?.emit,r=a;a=_?.ref;try{return t?.(...e)}finally{a=r}},y=(...t)=>{if(g.aborted)return s;let n=c?.on,r=n?.(...t);if(!r)return s;let i=e({signal:g},r);return()=>{i(),r()}},b=async(e,...t)=>{g.throwIfAborted();let n=t[0],r=f({event:{type:o.type,payload:n},bus:c,tracer:l,parent:{signal:g,ref:_?.ref}});try{return await u(r.ctx,`run`,()=>e(n,r.ctx))}finally{r.unlink()}},x={...d(c?.ctx,o),type:o.type,payload:o.payload,signal:g,abort:e=>m.abort(e),emit:v,on:y,off:c?.off??s,run:b};return c?.addContext?.(x),_&&i.set(x,_),{ctx:x,unlink:h}},p=(e,t)=>{let n=r?i.get(e):void 0;return f({event:{type:t??e.type??``,payload:e.payload},bus:{emit:e.emit,on:e.on,off:e.off,ctx:e},tracer:n?.tracer,parent:{signal:e.signal,ref:n?.ref}})};export{u as a,p as i,f as n,c as o,o as r,n as s,l as t};
@@ -1,4 +1,4 @@
1
- import { B as EventMap, N as WithContext, h as Bus, x as ContextOf } from "./action-creator-Bd4TBZgl.js";
1
+ import { B as EventMap, N as WithContext, h as Bus, x as ContextOf } from "./action-creator-BrZF6hXc.js";
2
2
  //#region src/core/context-plugin.d.ts
3
3
  /** What a function that makes the fields of a task gets to see. */
4
4
  type ContextTask = {
package/dist/dev.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as EventMap, J as UnsubscribeCallback, h as Bus } from "./action-creator-Bd4TBZgl.js";
2
- import { n as ModuleApi } from "./module-DZ5ngUrM.js";
1
+ import { B as EventMap, J as UnsubscribeCallback, h as Bus } from "./action-creator-BrZF6hXc.js";
2
+ import { i as WithApp, n as ModuleApi } from "./module-DqKegXHt.js";
3
3
  //#region src/dev/types.d.ts
4
4
  /** The parts of what `modulePlugin` returned that the diagnostics report. */
5
5
  type ReportedApp<E extends EventMap> = Pick<ModuleApi<E>, "mount" | "unmount" | "isMounted">;
@@ -12,11 +12,11 @@ type DevOptions<E extends EventMap = EventMap> = {
12
12
  modules?: boolean;
13
13
  /** Receives every message. Default: `console.warn` for leaks and `console.info` for modules. */
14
14
  log?: (message: string) => void;
15
- /** What `modulePlugin` returned, to report its modules. */
15
+ /** What `modulePlugin` returned, to report its modules. Without it the app that `modulePlugin` put on the bus is used, in either order of the two plugins. */
16
16
  app?: ReportedApp<E>;
17
17
  };
18
18
  /** A plugin that connects the diagnostics to a bus; the function it returns disconnects them. */
19
- type DevPlugin = <E extends EventMap>(options?: DevOptions<E>) => (bus: Bus<E>) => UnsubscribeCallback;
19
+ type DevPlugin = <E extends EventMap>(options?: DevOptions<E>) => (bus: Bus<E> & WithApp) => UnsubscribeCallback;
20
20
  //#endregion
21
21
  //#region src/dev/plugin.d.ts
22
22
  /**
@@ -28,8 +28,9 @@ type DevPlugin = <E extends EventMap>(options?: DevOptions<E>) => (bus: Bus<E>)
28
28
  * the count: a file that was reloaded and subscribes again, or an
29
29
  * unsubscribe that is never called. The count follows the function that `on`
30
30
  * returns; `bus.off(event, fn)` is not seen.
31
- * - **Modules.** With `app` (what `modulePlugin` returned) it reports a
32
- * module that is mounted, replaced by name and unmounted.
31
+ * - **Modules.** It reports a module that is mounted, replaced by name and
32
+ * unmounted, for the app that `modulePlugin` returned: the `app` option, or
33
+ * else the one `modulePlugin` put on the bus, whichever plugin was used first.
33
34
  *
34
35
  * It wraps `bus.on`, `app.mount` and `app.unmount`; the function that `bus.use` returns
35
36
  * puts the originals back. In a production build `nanoeffects/dev` is a no-op, so
@@ -37,8 +38,8 @@ type DevPlugin = <E extends EventMap>(options?: DevOptions<E>) => (bus: Bus<E>)
37
38
  *
38
39
  * @example
39
40
  * ```ts
40
- * const app = bus.use(modulePlugin([userModule]));
41
- * const disconnect = bus.use(devPlugin({ app })); // warnings and messages in the console while developing
41
+ * bus.use(modulePlugin([userModule]));
42
+ * const disconnect = bus.use(devPlugin()); // warnings and messages in the console while developing
42
43
  * ```
43
44
  */
44
45
  export declare const devPlugin: DevPlugin;
package/dist/dev.js CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./event-0RIBGYqS.js";const t=`[nanoeffects]`,n=(e={})=>t=>{let{maxListeners:n=10,leaks:a=!0,modules:o=!0,app:s}=e,c=e.log??(e=>console.warn(e)),l=e.log??(e=>console.info(e)),u=[];return a&&u.push(r(t,n,c)),o&&s&&u.push(i(s,l)),()=>{for(let e of u.splice(0))e()}},r=(n,r,i)=>{let a=n.on,o=/* @__PURE__ */ new Map,s=/* @__PURE__ */ new Set;return n.on=(...c)=>{let[l]=c,u=e(l),d=(o.get(u)??0)+1;o.set(u,d),d>r&&!s.has(u)&&(s.add(u),i(`${t} ${d} listeners of "${u}" were added and not unsubscribed (more than ${r}). A file that is reloaded and subscribes again, or an unsubscribe that is never called?`));let f=Reflect.apply(a,n,c),p=!1;return()=>{if(!p){p=!0;let e=(o.get(u)??1)-1;o.set(u,e),e<=r&&s.delete(u)}f()}},()=>{n.on=a}},i=(e,n)=>{let{mount:r,unmount:i}=e,a=/* @__PURE__ */ new Map;return e.mount=i=>{let o=a.get(i.name);if(o===i&&e.isMounted(i))return r(i);let s=o!==void 0&&e.isMounted(o),c=r(i);return a.set(i.name,i),n(`${t} module "${i.name}" ${s?`replaced`:`mounted`}`),()=>{e.isMounted(i)&&n(`${t} module "${i.name}" unmounted`),c()}},e.unmount=r=>{e.isMounted(r)&&n(`${t} module "${r.name}" unmounted`),i(r)},()=>{e.mount=r,e.unmount=i}};export{n as devPlugin};
1
+ import{t as e}from"./event-0RIBGYqS.js";const t=`[nanoeffects]`,n=(e={})=>t=>{let{maxListeners:n=10,leaks:r=!0,modules:o=!0,app:s}=e,c=e.log??(e=>console.warn(e)),l=e.log??(e=>console.info(e)),u=[];return r&&u.push(i(t,n,c)),o&&u.push(a(t,s,l)),()=>{for(let e of u.splice(0))e()}},r=t=>typeof t==`function`&&typeof Reflect.get(t,`type`)!=`string`?`*`:e(t),i=(e,n,i)=>{let a=e.on,o=/* @__PURE__ */ new Map,s=/* @__PURE__ */ new Set,c=!0,l=(...l)=>{if(!c)return Reflect.apply(a,e,l);let[u]=l,d=r(u),f=(o.get(d)??0)+1;o.set(d,f),f>n&&!s.has(d)&&(s.add(d),i(`${t} ${f} listeners of "${d}" were added and not unsubscribed (more than ${n}). A file that is reloaded and subscribes again, or an unsubscribe that is never called?`));let p=Reflect.apply(a,e,l),m=!1;return()=>{if(!m){m=!0;let e=(o.get(d)??1)-1;o.set(d,e),e<=n&&s.delete(d)}p()}};return e.on=l,()=>{c=!1,e.on===l&&(e.on=a)}},a=(e,t,n)=>{let r=t??e.app;if(r)return o(r,n);let i,a;return Object.defineProperty(e,"app",{configurable:!0,enumerable:!0,get:()=>i,set:e=>{a?.(),i=e,a=e?o(e,n):void 0}}),()=>{a?.(),Object.defineProperty(e,"app",{configurable:!0,enumerable:!0,writable:!0,value:i})}},o=(e,n)=>{let{mount:r,unmount:i}=e,a=/* @__PURE__ */ new Map;return e.mount=i=>{let o=a.get(i.name);if(o===i&&e.isMounted(i))return r(i);let s=o!==void 0&&e.isMounted(o),c=r(i);return a.set(i.name,i),n(`${t} module "${i.name}" ${s?`replaced`:`mounted`}`),()=>{e.isMounted(i)&&n(`${t} module "${i.name}" unmounted`),c()}},e.unmount=r=>{e.isMounted(r)&&n(`${t} module "${r.name}" unmounted`),i(r)},()=>{e.mount=r,e.unmount=i}};export{n as devPlugin};
package/dist/effects.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as EventMap, W as Task, u as Effect } from "./action-creator-Bd4TBZgl.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-DQNPBcxx.js";
1
+ import { B as EventMap, W as Task, u as Effect } from "./action-creator-BrZF6hXc.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-DkXCvsmB.js";
3
3
  //#region src/utils/onAbort.d.ts
4
4
  export declare const onAbort: (ctx: {
5
5
  signal?: AbortSignal | undefined;
package/dist/effects.js CHANGED
@@ -1 +1 @@
1
- import{n as e,t}from"./onAbort-BgMfspK4.js";import{a as n,i as r,o as i,t as a}from"./context-CK0ZomWt.js";import{n as o,r as s,t as c}from"./delay-CIHnOh_L.js";const l=(e,n)=>n?.signal?new Promise((r,i)=>{let a=t(n,i);e.then(r,i).finally(a)}):e,u=async(e,n,o,s)=>{n?.signal?.throwIfAborted();let{ctx:c,unlink:u}=r(n??{}),d=a(c,e);i(c,e,`start`),t(c,()=>d(`cancel`));try{let e=await l(o(c),n);return d(`done`),s?.(!1),e}catch(e){throw d(`error`,e),s?.(!0),e}finally{u()}},d=async(e,t)=>{let{ctx:i,unlink:a}=r(e);try{return await n(i,`run`,()=>t(i))}finally{a()}},f=e=>e,p=(e,t)=>n=>e(t,f(n)),m=e=>Array.isArray(e)?Array(e.length):{},h=(e,t)=>{let i=Object.entries(t).map(([t,i])=>{let a=r(e),o={signal:a.ctx.signal,abort:a.ctx.abort},s=()=>i(o);return{key:t,task:new Promise(e=>e(n(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=(n,r)=>n.signal.aborted?Promise.reject(n.signal.reason):new Promise((i,a)=>{let o=[],s=`pending`,c=t=>{try{t()}catch(t){e(`cancel cleanup failed`,t)}},l=t(n,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{r({resolve:u(i),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,n,r,i)=>{if(e.signal.aborted)return Promise.resolve();let a=i.leading??!1,c=i.waitForFn??!1;return u(`poll`,e,e=>new Promise((i,l)=>{let u=0,f=null,p=()=>{f!==null&&(o(f),f=null)},m=e=>{try{f=s(h,typeof r==`function`?r(e):r)}catch(e){p(),l(e)}},h=()=>{f=null,c||m(u+1),g()},g=()=>{let t=u++;d(e,e=>n(e,t)).then(()=>{c&&!e.signal.aborted&&m(u)},e=>{p(),l(e)})};t(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,n,r={}){return u(`take`,e,i=>new Promise((a,o)=>{let{predicate:s}=r,c=[],l=()=>{for(let e of c)e()},u=e=>{l(),o(e)};c.push(e.on(n,e=>{(!s||s(e))&&(l(),a(e))})),c.push(t(i,u)),c.push(t({signal:r.signal},u))}))}const M=(e,t,i)=>u(`timeout`,e,async e=>{let a=r(e),c=s(()=>a.ctx.abort(new DOMException(`Timed out after ${t}ms`,`TimeoutError`)),t);try{return await l(Promise.resolve(n(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,t as onAbort,T as poll,E as race,A as retry,j as take,N as timeout};
1
+ import{n as e,t}from"./onAbort-BgMfspK4.js";import{a as n,i as r,o as i,t as a}from"./context-COgyNlrC.js";import{n as o,r as s,t as c}from"./delay-CIHnOh_L.js";const l=(e,n)=>n?.signal?new Promise((r,i)=>{let a=t(n,i);e.then(r,i).finally(a)}):e,u=async(e,n,o,s)=>{n?.signal?.throwIfAborted();let{ctx:c,unlink:u}=r(n??{}),d=a(c,e);i(c,e,`start`),t(c,()=>d(`cancel`));try{let e=await l(o(c),n);return d(`done`),s?.(!1),e}catch(e){throw d(`error`,e),s?.(!0),e}finally{u()}},d=async(e,t)=>{let{ctx:i,unlink:a}=r(e);try{return await n(i,`run`,()=>t(i))}finally{a()}},f=e=>e,p=(e,t)=>n=>e(t,f(n)),m=e=>Array.isArray(e)?Array(e.length):{},h=(e,t)=>{let i=Object.entries(t).map(([t,i])=>{let a=r(e),o={signal:a.ctx.signal,abort:a.ctx.abort},s=()=>i(o);return{key:t,task:new Promise(e=>e(n(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=(n,r)=>n.signal.aborted?Promise.reject(n.signal.reason):new Promise((i,a)=>{let o=[],s=`pending`,c=t=>{try{t()}catch(t){e(`cancel cleanup failed`,t)}},l=t(n,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{r({resolve:u(i),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)t in e||Object.assign(e,{[t]:(...t)=>n(e,...t)})},t},w=(e,n,r,i)=>{if(e.signal.aborted)return Promise.resolve();let a=i.leading??!1,c=i.waitForFn??!1;return u(`poll`,e,e=>new Promise((i,l)=>{let u=0,f=null,p=()=>{f!==null&&(o(f),f=null)},m=e=>{try{f=s(h,typeof r==`function`?r(e):r)}catch(e){p(),l(e)}},h=()=>{f=null,c||m(u+1),g()},g=()=>{let t=u++;d(e,e=>n(e,t)).then(()=>{c&&!e.signal.aborted&&m(u)},e=>{p(),l(e)})};t(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,n,r={}){return u(`take`,e,i=>new Promise((a,o)=>{let{predicate:s}=r,c=[],l=()=>{for(let e of c)e()},u=e=>{l(),o(e)};c.push(e.on(n,e=>{(!s||s(e))&&(l(),a(e))})),c.push(t(i,u)),c.push(t({signal:r.signal},u))}))}const M=(e,t,i)=>u(`timeout`,e,async e=>{let a=r(e),c=s(()=>a.ctx.abort(new DOMException(`Timed out after ${t}ms`,`TimeoutError`)),t);try{return await l(Promise.resolve(n(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,t as onAbort,T as poll,E as race,A as retry,j as take,N as timeout};
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import { A as HandlerRef, B as EventMap, C as Emit, D as EventPayload, E as EventLike, F as commandCall, G as Trace, H as PayloadOf, I as createBus, J as UnsubscribeCallback, K as TraceEvent, L as Tracer, M as On, N as WithContext, O as EventsOf, P as WithType, R as anyEventType, S as ContextOption, T as EventKey, U as Phase, V as Keys, W as Task, _ as Command, b as Context, g as BusOptions, h as Bus, i as WithPayload, j as Off, k as Handler, m as AnyEvent, p as Action, q as TraceLogger, v as CommandCall, w as Emittable, x as ContextOf, y as Commands, z as EffectName } from "./action-creator-Bd4TBZgl.js";
2
- import { n as NoClash, r as contextPlugin, t as ContextTask } from "./context-plugin-BVNKqkIx.js";
1
+ import { A as HandlerRef, B as EventMap, C as Emit, D as EventPayload, E as EventLike, F as commandCall, G as Trace, H as PayloadOf, I as createBus, J as UnsubscribeCallback, K as TraceEvent, L as Tracer, M as On, N as WithContext, O as EventsOf, P as WithType, R as anyEventType, S as ContextOption, T as EventKey, U as Phase, V as Keys, W as Task, _ as Command, b as Context, g as BusOptions, h as Bus, i as WithPayload, j as Off, k as Handler, m as AnyEvent, p as Action, q as TraceLogger, v as CommandCall, w as Emittable, x as ContextOf, y as Commands, z as EffectName } from "./action-creator-BrZF6hXc.js";
2
+ import { n as NoClash, r as contextPlugin, t as ContextTask } from "./context-plugin--HkNN1ha.js";
3
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 };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import{i as e,n as t,t as n}from"./bus-BAs9x7IQ.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};
1
+ import{a as e,r as t,t as n}from"./bus-CkTHUAvq.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,50 @@
1
+ import { B as EventMap, D as EventPayload, J as UnsubscribeCallback, W as Task, h as Bus, p as Action } from "./action-creator-BrZF6hXc.js";
2
+ //#region src/match/plugin.d.ts
3
+ /** A function over the action of an event: `{ type, payload }`. */
4
+ type Predicate<E extends EventMap> = (action: Action<E>) => boolean;
5
+ /** A predicate that is a type guard narrows the payload that the handler gets. */
6
+ type Guard<E extends EventMap, A extends Action<E>> = (action: Action<E>) => action is A;
7
+ type MatchOn<E extends EventMap> = {
8
+ <A extends Action<E>>(guard: Guard<E, A>, fn: Task<A["payload"], E>): UnsubscribeCallback;
9
+ (predicate: Predicate<E>, fn: Task<EventPayload<E>, E>): UnsubscribeCallback;
10
+ };
11
+ type MatchOff<E extends EventMap> = {
12
+ <A extends Action<E>>(guard: Guard<E, A>, fn?: Task<A["payload"], E>): void;
13
+ (predicate: Predicate<E>, fn?: Task<EventPayload<E>, E>): void;
14
+ };
15
+ /** What `matchPlugin` adds to `on`, `once` and `off` of the bus: the same methods that also take a predicate. */
16
+ type MatchApi<E extends EventMap> = {
17
+ on: MatchOn<E>;
18
+ once: MatchOn<E>;
19
+ off: MatchOff<E>;
20
+ };
21
+ /**
22
+ * Lets `on`, `once` and `off` of the bus take a predicate as the first argument,
23
+ * to subscribe to the events that it picks instead of to one named event. The
24
+ * predicate gets `{ type, payload }` of every event; when it returns true the
25
+ * handler runs with the payload and the task context of that event. A type guard
26
+ * narrows the payload of the handler. An action creator or a command, which have
27
+ * a string `type`, keep their meaning. Returns the same bus.
28
+ *
29
+ * The subscription listens to `"*"`, so it runs after the listeners of the event
30
+ * itself, makes a task for every event whether or not the predicate accepts it,
31
+ * and counts as a listener for `onUnhandled`. For a few known events,
32
+ * `on(creator, handler)` is cheaper.
33
+ *
34
+ * @example
35
+ * ```ts
36
+ * import { createBus } from "nanoeffects";
37
+ * import { matchPlugin } from "nanoeffects/match";
38
+ *
39
+ * const bus = createBus().use(matchPlugin());
40
+ *
41
+ * // every event of the user domain, with the context of that event
42
+ * bus.on(
43
+ * (action) => action.type.startsWith("user/"),
44
+ * (payload, ctx) => console.log(ctx.type, payload),
45
+ * );
46
+ * ```
47
+ */
48
+ export declare const matchPlugin: () => <E extends EventMap>(bus: Bus<E>) => Bus<E> & MatchApi<E>;
49
+ //#endregion
50
+ export type { MatchApi };
package/dist/match.js ADDED
@@ -0,0 +1 @@
1
+ const e=e=>typeof e==`function`&&typeof Reflect.get(e,`type`)!=`string`,t=e=>e,n=()=>n=>{let{on:r,once:i,off:a}=n,o=/* @__PURE__ */ new Map,s=(e,t,i)=>{let a=Reflect.apply(r,n,[`*`,(n,r)=>{if(e({type:Reflect.get(r,`type`),payload:n}))return i&&c(),t(n,r)}]),s={handler:t,remove:c};o.set(e,[...o.get(e)??[],s]);function c(){a();let t=(o.get(e)??[]).filter(e=>e!==s);t.length>0?o.set(e,t):o.delete(e)}return c},c=(t,a,o)=>e(t)?s(t,a,o):Reflect.apply(o?i:r,n,[t,a]);return Object.assign(n,t({on:(e,t)=>c(e,t,!1),once:(e,t)=>c(e,t,!0),off:(t,r)=>{if(r===void 0&&(t===void 0||t===`*`)&&o.clear(),!e(t))return Reflect.apply(a,n,[t,r]);let i=o.get(t)??[],s=i.filter(e=>e.handler===r),c=r===void 0?i:s.slice(0,1);for(let e of c)e.remove()}}))};export{n as matchPlugin};
@@ -1,5 +1,5 @@
1
- import { B as EventMap, H as PayloadOf, J as UnsubscribeCallback, W as Task, _ as Command, b as Context, c as WithScope, h as Bus, o as Scope, v as CommandCall } from "./action-creator-Bd4TBZgl.js";
2
- import { n as Scoped, t as FieldsOfScope } from "./types-BJ0fzV1p.js";
1
+ import { B as EventMap, H as PayloadOf, J as UnsubscribeCallback, W as Task, _ as Command, b as Context, c as WithScope, h as Bus, o as Scope, v as CommandCall, y as Commands } from "./action-creator-BrZF6hXc.js";
2
+ import { n as ScopeSlots, r as Scoped, t as FieldsOfScope } from "./types-KavbvHix.js";
3
3
  //#region src/actions/command.d.ts
4
4
  /** What `createCommand` returns: a command that also tells whether an action is of its type. */
5
5
  type MadeCommand<P, R, T extends string> = Command<P, R> & {
@@ -66,13 +66,21 @@ type Binding<E extends EventMap = EventMap> = readonly [Command<never, unknown>
66
66
  * ```
67
67
  */
68
68
  declare const bindHandler: <P, R, E extends EventMap>(command: Command<P, R>, fn: Task<P, E, R>) => Binding<E>;
69
+ /** The registry of handlers that `commandsPlugin` returns: `run` for the bus, `handle` to bind more. */
70
+ interface Registry$1<E extends EventMap> extends Commands {
71
+ handle<P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
72
+ handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
73
+ handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
74
+ }
69
75
  /**
70
76
  * The plugin that gives a bus the handlers bound to commands:
71
77
  * `bus.use(commandsPlugin(bindings))` makes the registry, sets it as the
72
78
  * commands of the bus and returns it. Each bus has its own, so each test can
73
79
  * have its own implementation. `handle` binds more later and returns the
74
- * function that unbinds. A second `commandsPlugin` on the same bus replaces
75
- * the registry of that bus.
80
+ * function that unbinds. A second `commandsPlugin` on the same bus binds its
81
+ * list in the registry that is there and returns it, so the order of the
82
+ * plugins does not matter. A `commands` that is not such a registry (a custom
83
+ * runner) is replaced.
76
84
  *
77
85
  * What the bus runs for a command: the handler bound last, else the one the
78
86
  * command was created with, else it throws `No handler for command "..."`.
@@ -86,14 +94,7 @@ declare const bindHandler: <P, R, E extends EventMap>(command: Command<P, R>, fn
86
94
  * unbind(); // the command's own handler is back
87
95
  * ```
88
96
  */
89
- declare const commandsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>[]) => (bus: Bus<E>) => {
90
- run: (command: Command, payload: unknown, ctx: unknown) => unknown;
91
- handle: {
92
- <P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
93
- (type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
94
- (bindings: readonly Binding<E>[]): UnsubscribeCallback;
95
- };
96
- };
97
+ declare const commandsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>[]) => (bus: Bus<E>) => Registry$1<E>;
97
98
  //#endregion
98
99
  //#region src/actions/module.d.ts
99
100
  /**
@@ -153,6 +154,25 @@ type Module<E extends EventMap = EventMap> = {
153
154
  declare function createModule<E extends EventMap = EventMap>(name: string, setup: (m: ModuleContext<E>) => void): Module<E>;
154
155
  declare function createModule<E extends EventMap, S extends Scope = Record<never, never>>(name: string, setup: (m: ModuleContext<Scoped<E, S>>) => void, scope: S): Module<E>;
155
156
  type Registry<E extends EventMap> = ReturnType<ReturnType<typeof commandsPlugin<E>>>;
157
+ /**
158
+ * The modules of an app as the plugins that report on them see them: the part
159
+ * of what `modulePlugin` returns that `devPlugin` wraps.
160
+ */
161
+ interface ModuleHost {
162
+ mount(module: {
163
+ readonly name: string;
164
+ }): UnsubscribeCallback;
165
+ unmount(module: {
166
+ readonly name: string;
167
+ }): void;
168
+ isMounted(module: {
169
+ readonly name: string;
170
+ }): boolean;
171
+ }
172
+ /** The slot `modulePlugin` fills; a bus has it in its type once the plugin returned it. */
173
+ interface WithApp {
174
+ app?: ModuleHost | undefined;
175
+ }
156
176
  /** What `modulePlugin` returns. */
157
177
  type ModuleApi<E extends EventMap = EventMap> = {
158
178
  /** The registry of command handlers of the bus: the one it was made with, or the app's own. */
@@ -173,10 +193,15 @@ type ModuleApi<E extends EventMap = EventMap> = {
173
193
  };
174
194
  /**
175
195
  * The plugin that assembles an app from modules: `bus.use(modulePlugin(modules))`
176
- * mounts `modules` at once, in the order given, and returns `mount`, `unmount`,
177
- * `isMounted`, `dispose` and `commands` for the modules that come and go later. The bus runs the commands that the
178
- * modules bind: if `bus.use(commandsPlugin())` was called before, that registry is
179
- * used, otherwise the app attaches its own, as `app.commands`.
196
+ * returns `mount`, `unmount`, `isMounted`, `dispose` and `commands` for the
197
+ * modules that come and go, and mounts `modules`, in the order given, on the
198
+ * first use of the app or of the bus: the first `bus.emit`, or the first call
199
+ * of one of its methods. By then every plugin is on the bus, so the plugins can
200
+ * be used in any order. The `on`, `once` and `off` calls made in between are
201
+ * held and made right after the modules, so the listeners of a module stay
202
+ * ahead of them. The bus runs the commands that the modules bind: the registry
203
+ * that the bus has is used (a later `commandsPlugin` binds in it), otherwise the
204
+ * app attaches its own, as `app.commands`. The app is also `bus.app`.
180
205
  *
181
206
  * A module is known by its `name`: mounting a module whose name is taken
182
207
  * replaces the mounted one, which is unmounted first. That is what hot reload
@@ -205,6 +230,6 @@ type ModuleApi<E extends EventMap = EventMap> = {
205
230
  * app.dispose();
206
231
  * ```
207
232
  */
208
- declare const modulePlugin: <E extends EventMap>(modules?: readonly Module<E>[]) => (bus: Bus<E>) => ModuleApi<E>;
233
+ declare const modulePlugin: <E extends EventMap>(modules?: readonly Module<E>[]) => (bus: Bus<E> & ScopeSlots & WithApp) => ModuleApi<E>;
209
234
  //#endregion
210
- export { modulePlugin as a, MadeCommand as c, createCommand as d, createModule as i, bindHandler as l, ModuleApi as n, Binding as o, ModuleContext as r, CarryingCalls as s, Module as t, commandsPlugin as u };
235
+ export { createModule as a, CarryingCalls as c, commandsPlugin as d, createCommand as f, WithApp as i, MadeCommand as l, ModuleApi as n, modulePlugin as o, ModuleContext as r, Binding as s, Module as t, bindHandler as u };
@@ -224,10 +224,6 @@ interface Bus<E extends EventMap> {
224
224
  readonly trace?: Tracer | undefined;
225
225
  /** Called with every new task context to add fields to it, for what needs the task, like `effectsPlugin`. Chain to the previous one. */
226
226
  addContext?: ((ctx: object) => void) | undefined;
227
- /** Puts the fields of a module's scope on the context of one of its tasks; `scopePlugin` sets it. Without it a module's scope is ignored. */
228
- applyScope?: ((ctx: object, scope: Scope) => void) | undefined;
229
- /** Wraps a handler so it runs with the fields of a module's scope; `scopePlugin` sets it. */
230
- fitScope?: ((scope: Scope, fn: unknown) => unknown) | undefined;
231
227
  }
232
228
  type BusOptions<E extends EventMap> = {
233
229
  /** Tracing of every task phase; make it with `createTracer` from `nanoeffects/trace`. */