nanoeffects 0.2.1 → 0.3.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.
@@ -88,7 +88,7 @@ type Command<P = never, R = unknown> = {
88
88
  readonly wrap?: (run: (payload: never, ctx: never) => unknown) => (payload: never, ctx: never) => unknown;
89
89
  };
90
90
  /**
91
- * What the bus needs to run commands. The implementation, `createCommands` in
91
+ * What the bus needs to run commands. The implementation, `commandsPlugin` in
92
92
  * `nanoeffects/actions`, holds the handlers bound to commands and runs the
93
93
  * right one, so a bus without `commands` carries none of that.
94
94
  */
@@ -183,7 +183,7 @@ interface Bus<E extends EventMap> {
183
183
  use<R>(plugin: (bus: Bus<E>) => R): R;
184
184
  /** `BusOptions.context` and `.trace`, and `commands`, for what makes tasks of its own, like `modulePlugin`. */
185
185
  readonly context?: ContextOption<E> | undefined;
186
- /** What runs the commands; `createCommands(bus)` and `modulePlugin` set it. Without one a command runs its own handler. */
186
+ /** What runs the commands; `commandsPlugin` and `modulePlugin` set it. Without one a command runs its own handler. */
187
187
  commands?: Commands | undefined;
188
188
  readonly trace?: Tracer | undefined;
189
189
  }
package/dist/actions.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { N as Task, c as Command, k as EventMap, n as FreeActionCreator, r as createAction, t as ActionCreator } from "./action-rqZEnRIp.js";
2
- import { a as modulePlugin, c as createCommand, i as createModule, l as createCommands, n as ModuleApi, o as Binding, r as ModuleContext, s as bindHandler, t as Module } from "./module-BSCdR9D1.js";
1
+ import { N as Task, k as EventMap, n as FreeActionCreator, r as createAction, t as ActionCreator } from "./action-Bdfp-Wvd.js";
2
+ import { a as modulePlugin, c as bindHandler, i as createModule, l as commandsPlugin, n as ModuleApi, o as Binding, r as ModuleContext, s as MadeCommand, t as Module, u as createCommand } from "./module-I1ixyJzx.js";
3
3
  //#region src/actions/job.d.ts
4
4
  type Creator = {
5
5
  (...args: never[]): {
@@ -9,22 +9,20 @@ type Creator = {
9
9
  readonly type: string;
10
10
  };
11
11
  type Outcome = string | Creator;
12
- /** What `createJob` returns: the command of the job and the actions of its outcome. */
13
- type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = {
14
- command: Command<P, Promise<Awaited<R> | undefined>> & {
15
- readonly type: T;
16
- };
12
+ /** What `createJob` returns: the command of the job, with its two actions as properties. */
13
+ type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = MadeCommand<P, Promise<Awaited<R> | undefined>, T> & {
17
14
  /** Made from a string with the result as its payload, or the creator that was given. */
18
- successAction: S extends string ? ActionCreator<Awaited<R>, S> : S;
15
+ readonly success: S extends string ? ActionCreator<Awaited<R>, S> : S;
19
16
  /** Made from a string with the error as its payload, or the creator that was given. */
20
- failAction: F extends string ? ActionCreator<unknown, F> : F;
17
+ readonly fail: F extends string ? ActionCreator<unknown, F> : F;
21
18
  };
22
19
  /**
23
20
  * Creates a job: a command whose outcome is sent on as actions. When the
24
- * handler succeeds, `successAction(result)` is emitted on the bus, and when it
25
- * fails, `failAction(error)`. It is made for the case where nobody waits for
21
+ * handler succeeds, `job.success(result)` is emitted on the bus, and when it
22
+ * fails, `job.fail(error)`. It is made for the case where nobody waits for
26
23
  * the result and the bus carries it on, like `createAsyncThunk` or an effector
27
- * effect. It returns the three together: `{ command, successAction, failAction }`.
24
+ * effect. It returns the command, with the two actions on it: `job.success` and
25
+ * `job.fail`.
28
26
  *
29
27
  * `success` and `fail` are a type string, from which the job makes an action
30
28
  * creator with `createAction`, or an action creator that exists already, which
@@ -32,7 +30,7 @@ type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = {
32
30
  * `<type>/success` or `<type>/fail`.
33
31
  *
34
32
  * `bus.emit(command, payload)` returns a promise of the result. An error of the
35
- * handler always counts as handled: it goes to `failAction` and the promise
33
+ * handler always counts as handled: it goes to `job.fail` and the promise
36
34
  * resolves with `undefined`; a command is the tool for a result that must reject.
37
35
  * The actions are emitted as the task that ran the job, also for a handler bound
38
36
  * with `commands.handle`, and are skipped once the task is aborted. A missing
@@ -41,11 +39,13 @@ type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = {
41
39
  *
42
40
  * @example
43
41
  * ```ts
44
- * const { command: loadUser, successAction: userLoaded, failAction: userFailed } =
45
- * createJob("user/load", fetchUser, { success: "user/loaded", fail: "user/failed" });
42
+ * const loadUser = createJob("user/load", fetchUser, {
43
+ * success: "user/loaded",
44
+ * fail: "user/failed",
45
+ * });
46
46
  *
47
- * bus.on(userLoaded, (user) => render(user));
48
- * bus.emit(loadUser, "1"); // userLoaded(user) or userFailed(error) comes later
47
+ * bus.on(loadUser.success, (user) => render(user));
48
+ * bus.emit(loadUser, "1"); // loadUser.success(user) or loadUser.fail(error) comes later
49
49
  * ```
50
50
  */
51
51
  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`>(type: T, handler?: Task<P, E, R>, outcomes?: {
@@ -55,4 +55,4 @@ export declare const createJob: <P = void, R = void, T extends string = string,
55
55
  fail?: F;
56
56
  }) => Job<P, R, T, S, F>;
57
57
  //#endregion
58
- export { type ActionCreator, type Binding, type FreeActionCreator, type Job, type Module, type ModuleApi, type ModuleContext, bindHandler, createAction, createCommand, createCommands, createModule, modulePlugin };
58
+ export { type ActionCreator, type Binding, type FreeActionCreator, type Job, type Module, type ModuleApi, type ModuleContext, bindHandler, commandsPlugin, createAction, 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-DlA80GOA.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,t)=>Object.assign((r,i)=>{if(!t)throw new a(`No handler for command "${e}"`);return t(r,i??n({event:{type:e,payload:r}}).ctx)},{type:e}),s=(e,t)=>[e,t],c=(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(t);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 e.commands=o,o},l=e=>typeof e==`string`?i(e):e,u=(e,t,n)=>{let r=e.emit;r(Reflect.apply(t,null,[n]))},d=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof a)throw e;return Promise.reject(e)}},f=(e,t,n={})=>{let r=o(e,t),i=l(n.success??`${e}/success`),a=l(n.fail??`${e}/fail`),s=(e,t,n)=>{let r=n;return d(()=>Reflect.apply(e,null,[t,n])).then(e=>(u(r,i,e),e),e=>{u(r,a,e)})};return{command:Object.assign((e,t)=>t?s(r,e,t):d(()=>r(e)),{type:e,wrap:e=>(t,n)=>s(e,t,n)}),successAction:i,failAction:a}},p=(e,t)=>({name:e,setup:t}),m=(r=[])=>i=>{let a=i.commands??c(i),o={handle:(...e)=>{if(!a.handle)throw Error("modulePlugin: the `commands` of the bus is not a registry from `createCommands()`");return Reflect.apply(a.handle,null,e)}},s=n({event:{type:`app`,payload:void 0},bus:i,tracer:i.trace}),l=n=>{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=t(n,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=(t,n)=>{let r=Reflect.apply(o.handle,null,[t,n]);return e(d,r),r},h=(...e)=>{let t=e.map(e=>typeof e==`function`?m(e,e):f.mount(e));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 r)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,f as createJob,p as createModule,m as modulePlugin};
1
+ import{t as e}from"./onAbort-BgMfspK4.js";import{i as t,n}from"./context-DlA80GOA.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,t)=>Object.assign((r,i)=>{if(!t)throw new a(`No handler for command "${e}"`);return t(r,i??n({event:{type:e,payload:r}}).ctx)},{type:e,match:t=>t.type===e}),s=(e,t)=>[e,t],c=(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},l=e=>typeof e==`string`?i(e):e,u=(e,t,n)=>{let r=e.emit;r(Reflect.apply(t,null,[n]))},d=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof a)throw e;return Promise.reject(e)}},f=(e,t,n={})=>{let r=o(e,t),i=l(n.success??`${e}/success`),a=l(n.fail??`${e}/fail`),s=(e,t,n)=>{let r=n;return d(()=>Reflect.apply(e,null,[t,n])).then(e=>(u(r,i,e),e),e=>{u(r,a,e)})};return Object.assign((e,t)=>t?s(r,e,t):d(()=>r(e)),{type:e,match:r.match,wrap:e=>(t,n)=>s(e,t,n),success:i,fail:a})},p=(e,t)=>({name:e,setup:t}),m=(r=[])=>i=>{let a=i.commands??c()(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}),l=n=>{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=t(n,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=(t,n)=>{let r=Reflect.apply(o.handle,null,[t,n]);return e(d,r),r},h=(...e)=>{let t=e.map(e=>typeof e==`function`?m(e,e):f.mount(e));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 r)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,c as commandsPlugin,i as createAction,o as createCommand,f as createJob,p as createModule,m as modulePlugin};
package/dist/dev.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { L as UnsubscribeCallback, k as EventMap, o as Bus } from "./action-rqZEnRIp.js";
2
- import { n as ModuleApi } from "./module-BSCdR9D1.js";
1
+ import { L as UnsubscribeCallback, k as EventMap, o as Bus } from "./action-Bdfp-Wvd.js";
2
+ import { n as ModuleApi } from "./module-I1ixyJzx.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">;
package/dist/effects.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as Keys, N as Task, k as EventMap, u as Context } from "./action-rqZEnRIp.js";
1
+ import { A as Keys, N as Task, k as EventMap, u as Context } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/utils/delay.d.ts
3
3
  /**
4
4
  * Resolves after `ms`, or rejects early if `ctx.signal` aborts. `ms` can be a
package/dist/index.d.ts CHANGED
@@ -1,2 +1,2 @@
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-rqZEnRIp.js";
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-Bdfp-Wvd.js";
2
2
  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 };
@@ -1,5 +1,17 @@
1
- import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as EventMap, o as Bus, u as Context } from "./action-rqZEnRIp.js";
1
+ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as EventMap, o as Bus, u as Context } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/actions/command.d.ts
3
+ /** What `createCommand` returns: a command that also tells whether an action is of its type. */
4
+ type MadeCommand<P, R, T extends string> = Command<P, R> & {
5
+ readonly type: T;
6
+ /** Tells whether an action has the type of this command, and narrows its type. */
7
+ match(action: {
8
+ type: string;
9
+ payload?: unknown;
10
+ }): action is {
11
+ type: T;
12
+ payload: P;
13
+ };
14
+ };
3
15
  /**
4
16
  * Creates a command: a typed request for a result. `bus.emit(command, payload)`
5
17
  * runs its handler as a task, with a context, and returns what the handler
@@ -7,11 +19,13 @@ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as
7
19
  *
8
20
  * The handler is optional. A command without one is only a contract, and the
9
21
  * bus gets its implementation from the `commands` registry (see
10
- * `createCommands` and `bindHandler`). A handler bound there wins over the one
22
+ * `commandsPlugin` and `bindHandler`). A handler bound there wins over the one
11
23
  * the command was created with, so a test can give a bus its own implementation.
12
24
  *
13
25
  * A handler can be wrapped in a policy, e.g. `latest(fn)`. Calling the command
14
26
  * directly, `command(payload)`, runs its own handler outside of any bus.
27
+ * `command.match(action)` tells whether an action has the type of the command,
28
+ * as it does for an action creator.
15
29
  *
16
30
  * @example
17
31
  * ```ts
@@ -20,34 +34,33 @@ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as
20
34
  * );
21
35
  * const sendMail = createCommand<Mail, void>("mail/send"); // implemented elsewhere
22
36
  *
23
- * const commands = createCommands([bindHandler(sendMail, smtpSend)]);
37
+ * bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
24
38
  * const bus = createBus({ commands });
25
39
  * const user = await bus.emit(getUser, "1");
26
40
  *
27
41
  * commands.handle(getUser, async () => fakeUser); // in a test
28
42
  * ```
29
43
  */
30
- 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
- };
44
+ declare const createCommand: <P = void, R = void, T extends string = string, E extends EventMap = EventMap>(type: T, handler?: Task<P, E, R>) => MadeCommand<P, R, T>;
33
45
  /** A command (or its type) with the handler to bind to it; `bindHandler` makes one. */
34
46
  type Binding<E extends EventMap = EventMap> = readonly [Command<never, unknown> | string, Task<never, E, unknown>];
35
47
  /**
36
- * Pairs a command with the handler to bind to it, for `createCommands`. It
48
+ * Pairs a command with the handler to bind to it, for `commandsPlugin`. It
37
49
  * checks that the handler fits the command.
38
50
  *
39
51
  * @example
40
52
  * ```ts
41
- * createCommands([bindHandler(sendMail, smtpSend)]);
53
+ * bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
42
54
  * ```
43
55
  */
44
56
  declare const bindHandler: <P, R, E extends EventMap>(command: Command<P, R>, fn: Task<P, E, R>) => Binding<E>;
45
57
  /**
46
- * The handlers bound to commands of `bus`: it makes the registry, sets it as
47
- * the commands of the bus and returns it. Each bus has its own, so each test
48
- * can have its own implementation. `handle` binds more later and returns the
49
- * function that unbinds. A second `createCommands(bus)` replaces the registry
50
- * of that bus.
58
+ * The plugin that gives a bus the handlers bound to commands:
59
+ * `bus.use(commandsPlugin(bindings))` makes the registry, sets it as the
60
+ * commands of the bus and returns it. Each bus has its own, so each test can
61
+ * have its own implementation. `handle` binds more later and returns the
62
+ * function that unbinds. A second `commandsPlugin` on the same bus replaces
63
+ * the registry of that bus.
51
64
  *
52
65
  * What the bus runs for a command: the handler bound last, else the one the
53
66
  * command was created with, else it throws `No handler for command "..."`.
@@ -55,13 +68,13 @@ declare const bindHandler: <P, R, E extends EventMap>(command: Command<P, R>, fn
55
68
  * @example
56
69
  * ```ts
57
70
  * const bus = createBus<Events>();
58
- * const commands = createCommands(bus, [bindHandler(sendMail, smtpSend)]);
71
+ * const commands = bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
59
72
  *
60
73
  * const unbind = commands.handle(getUser, async () => fakeUser);
61
74
  * unbind(); // the command's own handler is back
62
75
  * ```
63
76
  */
64
- declare const createCommands: <E extends EventMap>(bus: Bus<E>, bindings?: readonly Binding<E>[]) => {
77
+ declare const commandsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>[]) => (bus: Bus<E>) => {
65
78
  run: (command: Command, payload: unknown, ctx: unknown) => unknown;
66
79
  handle: {
67
80
  <P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
@@ -121,7 +134,7 @@ type Module<E extends EventMap = EventMap> = {
121
134
  * ```
122
135
  */
123
136
  declare const createModule: <E extends EventMap = EventMap>(name: string, setup: (m: ModuleContext<E>) => void) => Module<E>;
124
- type Registry<E extends EventMap> = ReturnType<typeof createCommands<E>>;
137
+ type Registry<E extends EventMap> = ReturnType<ReturnType<typeof commandsPlugin<E>>>;
125
138
  /** What `modulePlugin` returns. */
126
139
  type ModuleApi<E extends EventMap = EventMap> = {
127
140
  /** The registry of command handlers of the bus: the one it was made with, or the app's own. */
@@ -137,7 +150,7 @@ type ModuleApi<E extends EventMap = EventMap> = {
137
150
  * The plugin that assembles an app from modules: `bus.use(modulePlugin(modules))`
138
151
  * mounts `modules` at once, in the order given, and returns `mount`, `unmount`,
139
152
  * `isMounted`, `dispose` and `commands` for the modules that come and go later. The bus runs the commands that the
140
- * modules bind: if `createCommands(bus)` was called before, that registry is
153
+ * modules bind: if `bus.use(commandsPlugin())` was called before, that registry is
141
154
  * used, otherwise the app attaches its own, as `app.commands`.
142
155
  *
143
156
  * A module is known by its `name`: mounting a module whose name is taken
@@ -164,4 +177,4 @@ type ModuleApi<E extends EventMap = EventMap> = {
164
177
  */
165
178
  declare const modulePlugin: <E extends EventMap>(modules?: readonly Module<E>[]) => (bus: Bus<E>) => ModuleApi<E>;
166
179
  //#endregion
167
- export { modulePlugin as a, createCommand as c, createModule as i, createCommands as l, ModuleApi as n, Binding as o, ModuleContext as r, bindHandler as s, Module as t };
180
+ export { modulePlugin as a, bindHandler as c, createModule as i, commandsPlugin as l, ModuleApi as n, Binding as o, ModuleContext as r, MadeCommand as s, Module as t, createCommand as u };
@@ -88,7 +88,7 @@ type Command<P = never, R = unknown> = {
88
88
  readonly wrap?: (run: (payload: never, ctx: never) => unknown) => (payload: never, ctx: never) => unknown;
89
89
  };
90
90
  /**
91
- * What the bus needs to run commands. The implementation, `createCommands` in
91
+ * What the bus needs to run commands. The implementation, `commandsPlugin` in
92
92
  * `nanoeffects/actions`, holds the handlers bound to commands and runs the
93
93
  * right one, so a bus without `commands` carries none of that.
94
94
  */
@@ -183,7 +183,7 @@ interface Bus<E extends EventMap> {
183
183
  use<R>(plugin: (bus: Bus<E>) => R): R;
184
184
  /** `BusOptions.context` and `.trace`, and `commands`, for what makes tasks of its own, like `modulePlugin`. */
185
185
  readonly context?: ContextOption<E> | undefined;
186
- /** What runs the commands; `createCommands(bus)` and `modulePlugin` set it. Without one a command runs its own handler. */
186
+ /** What runs the commands; `commandsPlugin` and `modulePlugin` set it. Without one a command runs its own handler. */
187
187
  commands?: Commands | undefined;
188
188
  readonly trace?: Tracer | undefined;
189
189
  }
@@ -1,5 +1,17 @@
1
- import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as EventMap, n as FreeActionCreator, o as Bus, r as createAction, t as ActionCreator, u as Context } from "./action-rqZEnRIp.js";
1
+ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as EventMap, n as FreeActionCreator, o as Bus, r as createAction, t as ActionCreator, u as Context } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/actions/command.d.ts
3
+ /** What `createCommand` returns: a command that also tells whether an action is of its type. */
4
+ type MadeCommand<P, R, T extends string> = Command<P, R> & {
5
+ readonly type: T;
6
+ /** Tells whether an action has the type of this command, and narrows its type. */
7
+ match(action: {
8
+ type: string;
9
+ payload?: unknown;
10
+ }): action is {
11
+ type: T;
12
+ payload: P;
13
+ };
14
+ };
3
15
  /**
4
16
  * Creates a command: a typed request for a result. `bus.emit(command, payload)`
5
17
  * runs its handler as a task, with a context, and returns what the handler
@@ -7,11 +19,13 @@ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as
7
19
  *
8
20
  * The handler is optional. A command without one is only a contract, and the
9
21
  * bus gets its implementation from the `commands` registry (see
10
- * `createCommands` and `bindHandler`). A handler bound there wins over the one
22
+ * `commandsPlugin` and `bindHandler`). A handler bound there wins over the one
11
23
  * the command was created with, so a test can give a bus its own implementation.
12
24
  *
13
25
  * A handler can be wrapped in a policy, e.g. `latest(fn)`. Calling the command
14
26
  * directly, `command(payload)`, runs its own handler outside of any bus.
27
+ * `command.match(action)` tells whether an action has the type of the command,
28
+ * as it does for an action creator.
15
29
  *
16
30
  * @example
17
31
  * ```ts
@@ -20,34 +34,33 @@ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as
20
34
  * );
21
35
  * const sendMail = createCommand<Mail, void>("mail/send"); // implemented elsewhere
22
36
  *
23
- * const commands = createCommands([bindHandler(sendMail, smtpSend)]);
37
+ * bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
24
38
  * const bus = createBus({ commands });
25
39
  * const user = await bus.emit(getUser, "1");
26
40
  *
27
41
  * commands.handle(getUser, async () => fakeUser); // in a test
28
42
  * ```
29
43
  */
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
- };
44
+ export declare const createCommand: <P = void, R = void, T extends string = string, E extends EventMap = EventMap>(type: T, handler?: Task<P, E, R>) => MadeCommand<P, R, T>;
33
45
  /** A command (or its type) with the handler to bind to it; `bindHandler` makes one. */
34
46
  type Binding<E extends EventMap = EventMap> = readonly [Command<never, unknown> | string, Task<never, E, unknown>];
35
47
  /**
36
- * Pairs a command with the handler to bind to it, for `createCommands`. It
48
+ * Pairs a command with the handler to bind to it, for `commandsPlugin`. It
37
49
  * checks that the handler fits the command.
38
50
  *
39
51
  * @example
40
52
  * ```ts
41
- * createCommands([bindHandler(sendMail, smtpSend)]);
53
+ * bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
42
54
  * ```
43
55
  */
44
56
  export declare const bindHandler: <P, R, E extends EventMap>(command: Command<P, R>, fn: Task<P, E, R>) => Binding<E>;
45
57
  /**
46
- * The handlers bound to commands of `bus`: it makes the registry, sets it as
47
- * the commands of the bus and returns it. Each bus has its own, so each test
48
- * can have its own implementation. `handle` binds more later and returns the
49
- * function that unbinds. A second `createCommands(bus)` replaces the registry
50
- * of that bus.
58
+ * The plugin that gives a bus the handlers bound to commands:
59
+ * `bus.use(commandsPlugin(bindings))` makes the registry, sets it as the
60
+ * commands of the bus and returns it. Each bus has its own, so each test can
61
+ * have its own implementation. `handle` binds more later and returns the
62
+ * function that unbinds. A second `commandsPlugin` on the same bus replaces
63
+ * the registry of that bus.
51
64
  *
52
65
  * What the bus runs for a command: the handler bound last, else the one the
53
66
  * command was created with, else it throws `No handler for command "..."`.
@@ -55,13 +68,13 @@ export declare const bindHandler: <P, R, E extends EventMap>(command: Command<P,
55
68
  * @example
56
69
  * ```ts
57
70
  * const bus = createBus<Events>();
58
- * const commands = createCommands(bus, [bindHandler(sendMail, smtpSend)]);
71
+ * const commands = bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
59
72
  *
60
73
  * const unbind = commands.handle(getUser, async () => fakeUser);
61
74
  * unbind(); // the command's own handler is back
62
75
  * ```
63
76
  */
64
- export declare const createCommands: <E extends EventMap>(bus: Bus<E>, bindings?: readonly Binding<E>[]) => {
77
+ export declare const commandsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>[]) => (bus: Bus<E>) => {
65
78
  run: (command: Command, payload: unknown, ctx: unknown) => unknown;
66
79
  handle: {
67
80
  <P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
@@ -79,22 +92,20 @@ type Creator = {
79
92
  readonly type: string;
80
93
  };
81
94
  type Outcome = string | Creator;
82
- /** What `createJob` returns: the command of the job and the actions of its outcome. */
83
- type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = {
84
- command: Command<P, Promise<Awaited<R> | undefined>> & {
85
- readonly type: T;
86
- };
95
+ /** What `createJob` returns: the command of the job, with its two actions as properties. */
96
+ type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = MadeCommand<P, Promise<Awaited<R> | undefined>, T> & {
87
97
  /** Made from a string with the result as its payload, or the creator that was given. */
88
- successAction: S extends string ? ActionCreator<Awaited<R>, S> : S;
98
+ readonly success: S extends string ? ActionCreator<Awaited<R>, S> : S;
89
99
  /** Made from a string with the error as its payload, or the creator that was given. */
90
- failAction: F extends string ? ActionCreator<unknown, F> : F;
100
+ readonly fail: F extends string ? ActionCreator<unknown, F> : F;
91
101
  };
92
102
  /**
93
103
  * Creates a job: a command whose outcome is sent on as actions. When the
94
- * handler succeeds, `successAction(result)` is emitted on the bus, and when it
95
- * fails, `failAction(error)`. It is made for the case where nobody waits for
104
+ * handler succeeds, `job.success(result)` is emitted on the bus, and when it
105
+ * fails, `job.fail(error)`. It is made for the case where nobody waits for
96
106
  * the result and the bus carries it on, like `createAsyncThunk` or an effector
97
- * effect. It returns the three together: `{ command, successAction, failAction }`.
107
+ * effect. It returns the command, with the two actions on it: `job.success` and
108
+ * `job.fail`.
98
109
  *
99
110
  * `success` and `fail` are a type string, from which the job makes an action
100
111
  * creator with `createAction`, or an action creator that exists already, which
@@ -102,7 +113,7 @@ type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = {
102
113
  * `<type>/success` or `<type>/fail`.
103
114
  *
104
115
  * `bus.emit(command, payload)` returns a promise of the result. An error of the
105
- * handler always counts as handled: it goes to `failAction` and the promise
116
+ * handler always counts as handled: it goes to `job.fail` and the promise
106
117
  * resolves with `undefined`; a command is the tool for a result that must reject.
107
118
  * The actions are emitted as the task that ran the job, also for a handler bound
108
119
  * with `commands.handle`, and are skipped once the task is aborted. A missing
@@ -111,11 +122,13 @@ type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = {
111
122
  *
112
123
  * @example
113
124
  * ```ts
114
- * const { command: loadUser, successAction: userLoaded, failAction: userFailed } =
115
- * createJob("user/load", fetchUser, { success: "user/loaded", fail: "user/failed" });
125
+ * const loadUser = createJob("user/load", fetchUser, {
126
+ * success: "user/loaded",
127
+ * fail: "user/failed",
128
+ * });
116
129
  *
117
- * bus.on(userLoaded, (user) => render(user));
118
- * bus.emit(loadUser, "1"); // userLoaded(user) or userFailed(error) comes later
130
+ * bus.on(loadUser.success, (user) => render(user));
131
+ * bus.emit(loadUser, "1"); // loadUser.success(user) or loadUser.fail(error) comes later
119
132
  * ```
120
133
  */
121
134
  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`>(type: T, handler?: Task<P, E, R>, outcomes?: {
@@ -176,7 +189,7 @@ type Module<E extends EventMap = EventMap> = {
176
189
  * ```
177
190
  */
178
191
  export declare const createModule: <E extends EventMap = EventMap>(name: string, setup: (m: ModuleContext<E>) => void) => Module<E>;
179
- type Registry<E extends EventMap> = ReturnType<typeof createCommands<E>>;
192
+ type Registry<E extends EventMap> = ReturnType<ReturnType<typeof commandsPlugin<E>>>;
180
193
  /** What `modulePlugin` returns. */
181
194
  type ModuleApi<E extends EventMap = EventMap> = {
182
195
  /** The registry of command handlers of the bus: the one it was made with, or the app's own. */
@@ -192,7 +205,7 @@ type ModuleApi<E extends EventMap = EventMap> = {
192
205
  * The plugin that assembles an app from modules: `bus.use(modulePlugin(modules))`
193
206
  * mounts `modules` at once, in the order given, and returns `mount`, `unmount`,
194
207
  * `isMounted`, `dispose` and `commands` for the modules that come and go later. The bus runs the commands that the
195
- * modules bind: if `createCommands(bus)` was called before, that registry is
208
+ * modules bind: if `bus.use(commandsPlugin())` was called before, that registry is
196
209
  * used, otherwise the app attaches its own, as `app.commands`.
197
210
  *
198
211
  * A module is known by its `name`: mounting a module whose name is taken
@@ -1 +1 @@
1
- import{i as e,n as t,s as n}from"./context-yAWj0BFZ.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({event:{type:e,payload:r}}).ctx)},{type:e}),s=(e,t)=>[e,t],c=(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(t);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 e.commands=o,o},l=e=>typeof e==`string`?i(e):e,u=(e,t,n)=>{let r=e.emit;r(Reflect.apply(t,null,[n]))},d=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof a)throw e;return Promise.reject(e)}},f=(e,t,n={})=>{let r=o(e,t),i=l(n.success??`${e}/success`),a=l(n.fail??`${e}/fail`),s=(e,t,n)=>{let r=n;return d(()=>Reflect.apply(e,null,[t,n])).then(e=>(u(r,i,e),e),e=>{u(r,a,e)})};return{command:Object.assign((e,t)=>t?s(r,e,t):d(()=>r(e)),{type:e,wrap:e=>(t,n)=>s(e,t,n)}),successAction:i,failAction:a}},p=(e,t)=>({name:e,setup:t}),m=(r=[])=>i=>{let a=i.commands??c(i),o={handle:(...e)=>{if(!a.handle)throw Error("modulePlugin: the `commands` of the bus is not a registry from `createCommands()`");return Reflect.apply(a.handle,null,e)}},s=t({event:{type:`app`,payload:void 0},bus:i,tracer:i.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(e=>typeof e==`function`?m(e,e):f.mount(e));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 r)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,f as createJob,p as createModule,m as modulePlugin};
1
+ import{i as e,n as t,s as n}from"./context-yAWj0BFZ.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({event:{type:e,payload:r}}).ctx)},{type:e,match:t=>t.type===e}),s=(e,t)=>[e,t],c=(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},l=e=>typeof e==`string`?i(e):e,u=(e,t,n)=>{let r=e.emit;r(Reflect.apply(t,null,[n]))},d=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof a)throw e;return Promise.reject(e)}},f=(e,t,n={})=>{let r=o(e,t),i=l(n.success??`${e}/success`),a=l(n.fail??`${e}/fail`),s=(e,t,n)=>{let r=n;return d(()=>Reflect.apply(e,null,[t,n])).then(e=>(u(r,i,e),e),e=>{u(r,a,e)})};return Object.assign((e,t)=>t?s(r,e,t):d(()=>r(e)),{type:e,match:r.match,wrap:e=>(t,n)=>s(e,t,n),success:i,fail:a})},p=(e,t)=>({name:e,setup:t}),m=(r=[])=>i=>{let a=i.commands??c()(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=t({event:{type:`app`,payload:void 0},bus:i,tracer:i.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(e=>typeof e==`function`?m(e,e):f.mount(e));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 r)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,c as commandsPlugin,i as createAction,o as createCommand,f as createJob,p as createModule,m as modulePlugin};
@@ -1,4 +1,4 @@
1
- import { A as Keys, N as Task, k as EventMap, u as Context } from "./action-rqZEnRIp.js";
1
+ import { A as Keys, N as Task, k as EventMap, u as Context } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/utils/delay.d.ts
3
3
  /**
4
4
  * Resolves after `ms`, or rejects early if `ctx.signal` aborts. `ms` can be a
@@ -1,2 +1,2 @@
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-rqZEnRIp.js";
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-Bdfp-Wvd.js";
2
2
  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 };
@@ -1,4 +1,4 @@
1
- import { N as Task, k as EventMap } from "./action-rqZEnRIp.js";
1
+ import { N as Task, k as EventMap } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/policies/keyed.d.ts
3
3
  /** Options shared by every policy that can keep its state per key. */
4
4
  type KeyOption<P> = {
@@ -1,4 +1,4 @@
1
- import { k as EventMap, o as Bus, s as BusOptions } from "./action-rqZEnRIp.js";
1
+ import { k as EventMap, o as Bus, s as BusOptions } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/store/redux/middleware.d.ts
3
3
  /** What Redux passes through a middleware: an action is a plain object with a `type`. */
4
4
  type ReduxAction = {
@@ -1,4 +1,4 @@
1
- import { A as Keys, k as EventMap, o as Bus } from "./action-rqZEnRIp.js";
1
+ import { A as Keys, k as EventMap, o as Bus } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/observable.d.ts
3
3
  declare global {
4
4
  interface SymbolConstructor {
@@ -1,4 +1,4 @@
1
- import { N as Task, k as EventMap } from "./action-rqZEnRIp.js";
1
+ import { N as Task, k as EventMap } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/policies/keyed.d.ts
3
3
  /** Options shared by every policy that can keep its state per key. */
4
4
  type KeyOption<P> = {
package/dist/redux.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { k as EventMap, o as Bus, s as BusOptions } from "./action-rqZEnRIp.js";
1
+ import { k as EventMap, o as Bus, s as BusOptions } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/store/redux/middleware.d.ts
3
3
  /** What Redux passes through a middleware: an action is a plain object with a `type`. */
4
4
  type ReduxAction = {
package/dist/trace.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { E as Tracer, F as TraceEvent, I as TraceLogger, P as Trace } from "./action-rqZEnRIp.js";
1
+ import { E as Tracer, F as TraceEvent, I as TraceLogger, P as Trace } from "./action-Bdfp-Wvd.js";
2
2
  //#region src/trace/console.d.ts
3
3
  type ConsoleLoggerOptions = {
4
4
  /** Defaults to `globalThis.console`. */
package/docs/actions.md CHANGED
@@ -18,8 +18,8 @@ const getUser = createCommand("user/get", (id: string, { signal }) => fetchUser(
18
18
  // a contract without a handler: the code that sends mail is elsewhere
19
19
  const sendMail = createCommand<Mail, void>("mail/send");
20
20
 
21
- // a command whose outcome is sent on as actions: the command and its two actions together
22
- const { command: loadUser, successAction, failAction } = createJob("user/load", fetchUser, {
21
+ // a command whose outcome is sent on as actions: they are its properties, loadUser.success and loadUser.fail
22
+ const loadUser = createJob("user/load", fetchUser, {
23
23
  success: userLoaded, // an action creator that exists: used and returned as it is
24
24
  fail: "user/failed", // a string: the job makes the action creator
25
25
  });
@@ -27,26 +27,26 @@ const { command: loadUser, successAction, failAction } = createJob("user/load",
27
27
 
28
28
  **Actions.** `createAction(type)` returns a creator, with no generics: it keeps the literal type, and the bus checks the payload against its event map (`bus.emit(userLoaded(5))` is an error when `"user/loaded"` is a `User`). Without an event map give the payload type, `createAction<User>("user/loaded")`. The creator: `userLoaded(user)` is `{ type, payload }`, `userLoaded.type` is the type, `userLoaded.match(action)` narrows an action. `createAction(type, prepare)` builds the payload from several arguments. A creator works as the event of its type: `bus.emit(userLoaded(user))`, `bus.on(userLoaded, fn)`.
29
29
 
30
- **Commands.** `bus.emit(command, payload)` tells the listeners of the command's type, then runs its handler as a task, with a context, and returns the result. The handler can be wrapped in a policy, `createCommand("search", latest(fn))`. Calling `command(payload)` runs its own handler without a bus.
30
+ **Commands.** `bus.emit(command, payload)` tells the listeners of the command's type, then runs its handler as a task, with a context, and returns the result. The handler can be wrapped in a policy, `createCommand("search", latest(fn))`. Calling `command(payload)` runs its own handler without a bus. `command.match(action)` tells whether an action has the command's type and narrows it, as `match` of an action creator does.
31
31
 
32
- **Where handlers are registered.** The command may carry a handler. The bus gets the handlers bound to commands from a registry, `createCommands`, and a handler bound there wins over the command's own. The registry belongs to one bus, as an effector scope does with `fork({ handlers })`, so each bus (each test) can have its own.
32
+ **Where handlers are registered.** The command may carry a handler. The bus gets the handlers bound to commands from a registry, `commandsPlugin`, and a handler bound there wins over the command's own. The registry belongs to one bus, as an effector scope does with `fork({ handlers })`, so each bus (each test) can have its own.
33
33
 
34
34
  ```ts
35
- import { createCommands, bindHandler } from "nanoeffects/actions";
35
+ import { commandsPlugin, bindHandler } from "nanoeffects/actions";
36
36
 
37
37
  const bus = createBus<Events>();
38
- const commands = createCommands(bus, [bindHandler(sendMail, smtpSend)]); // attached to the bus
38
+ const commands = bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)])); // attached to the bus
39
39
 
40
40
  const unbind = commands.handle(getUser, async () => fakeUser); // later, e.g. in a test
41
41
  unbind(); // the command's own handler is back; the latest binding wins
42
42
  ```
43
43
 
44
- A command with no handler anywhere throws `No handler for command "..."` from `emit`. The registry lives in `nanoeffects/actions`, so a bus without one carries none of this code; without it `emit(command, payload)` simply runs the command's own handler. `createCommands(bus)` sets the registry as `bus.commands`, and a second call on the same bus replaces it. There is no `commands` option in `createBus`; a custom runner is assigned, `bus.commands = { run }`.
44
+ A command with no handler anywhere throws `No handler for command "..."` from `emit`. The registry lives in `nanoeffects/actions`, so a bus without one carries none of this code; without it `emit(command, payload)` simply runs the command's own handler. `bus.use(commandsPlugin())` sets the registry as `bus.commands`, and a second one on the same bus replaces it. There is no `commands` option in `createBus`; a custom runner is assigned, `bus.commands = { run }`.
45
45
 
46
- **Jobs.** `createJob(type, handler, { success, fail })` makes a command that sends its outcome on as actions, for when nobody waits for the result, and returns `{ command, successAction, failAction }`. When the handler succeeds, `successAction(result)` is emitted on the bus, and when it fails, `failAction(error)`.
46
+ **Jobs.** `createJob(type, handler, { success, fail })` makes a command that sends its outcome on as actions, for when nobody waits for the result, and returns the command itself, with the two actions on it: `loadUser.success` and `loadUser.fail`. When the handler succeeds, `loadUser.success(result)` is emitted on the bus, and when it fails, `loadUser.fail(error)`.
47
47
 
48
48
  - `success` and `fail` are a string, from which the job makes an action creator with `createAction` (the payload is the result, or the error), or an action creator that exists already, which is used and returned as it is. A missing one is made with the type `<type>/success` or `<type>/fail`.
49
- - `bus.emit(command, payload)` returns a promise of the result. An error of the handler always counts as handled: it goes to `failAction` and the promise resolves with `undefined`. For a result that must reject, use a command.
49
+ - `bus.emit(command, payload)` returns a promise of the result. An error of the handler always counts as handled: it goes to `loadUser.fail` and the promise resolves with `undefined`. For a result that must reject, use a command.
50
50
  - The actions are emitted as the task that ran the job, also for a handler bound with `commands.handle`, and are not sent once the task is aborted. A missing handler is not an outcome: `emit` throws `No handler for command "..."`.
51
51
  - Calling `command(payload)` directly runs only the handler.
52
52
 
@@ -72,7 +72,7 @@ app.dispose(); // unmounts every module
72
72
 
73
73
  - **Unmounting undoes everything** the module did: its subscriptions, its bound commands, its sub-modules and its background tasks, which are aborted.
74
74
  - **A module is known by its name.** Mounting a module whose name is taken replaces the mounted one. That is what hot reload needs: see [hmr.md](hmr.md).
75
- - **The registry.** If `createCommands(bus)` was called, that registry is used; otherwise the module plugin attaches its own. Either way it is `bus.commands` and `app.commands`, so the commands that modules bind are the ones the bus runs.
75
+ - **The registry.** If `bus.use(commandsPlugin())` was called, that registry is used; otherwise the module plugin attaches its own. Either way it is `bus.commands` and `app.commands`, so the commands that modules bind are the ones the bus runs.
76
76
  - A disposed app cannot mount modules.
77
77
  - A module context is a task context plus `handle` (give a command a handler: for a contract, or to override), `use` (bring sub-modules and commands that carry a handler: `m.use(getUser, saveUser, subModule)`, in any order; the returned function undoes just that call) and `spawn` (a background task, aborted on unmount).
78
78
  - A command that carries a handler keeps answering after its module is unmounted: the handler is its own, and `use` only brings the command and tracks it in the registry. Use `handle` for a handler that should live only as long as the module.
package/docs/guide.md CHANGED
@@ -85,12 +85,12 @@ Strings are for the plain case, objects for actions that other code already make
85
85
  A command made with a function carries its handler, as above. More often it is only a contract, a name with the types of the request and the result, and the code that does the work is registered separately: in another file, or a fake one in a test.
86
86
 
87
87
  ```ts
88
- import { createCommand, createCommands } from "nanoeffects/actions";
88
+ import { createCommand, commandsPlugin } from "nanoeffects/actions";
89
89
 
90
90
  const getUser = createCommand<string, Promise<User>>("user/get"); // no handler yet
91
91
 
92
92
  const bus = createBus<Events>();
93
- const commands = createCommands(bus); // the handlers of this bus
93
+ const commands = bus.use(commandsPlugin()); // the handlers of this bus
94
94
 
95
95
  bus.emit(getUser, "1"); // throws: No handler for command "user/get"
96
96
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nanoeffects",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "Typed event bus where every handler is a task with an AbortSignal, plus policies (latest, debounce, throttle, queue), effects (retry, timeout, poll) and tracing. About 1.2 kB gzip.",
5
5
  "keywords": [
6
6
  "event-bus",