nanoeffects 0.26.0 → 0.28.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 (67) hide show
  1. package/README.md +85 -30
  2. package/dist/{action-creator-Bpa8BUS9.d.ts → action-creator-CcAEvUnw.d.ts} +90 -23
  3. package/dist/actions.d.ts +54 -21
  4. package/dist/actions.js +1 -1
  5. package/dist/bus-DlpEluzd.js +1 -0
  6. package/dist/{context-types-BKIH5a8s.d.ts → context-types-hCKgU8sC.d.ts} +1 -1
  7. package/dist/context.d.ts +2 -2
  8. package/dist/dev.d.ts +2 -2
  9. package/dist/dev.js +1 -1
  10. package/dist/effects.d.ts +2 -2
  11. package/dist/event-DVcW0mME.js +1 -0
  12. package/dist/index.d.ts +2 -2
  13. package/dist/index.js +1 -1
  14. package/dist/match.d.ts +1 -1
  15. package/dist/{module-B6rg5NIb.d.ts → module-C_oEXw1n.d.ts} +40 -57
  16. package/dist/notrace/{action-creator-D2CotugT.d.ts → action-creator-DxOvVo8I.d.ts} +90 -23
  17. package/dist/notrace/actions.d.ts +114 -98
  18. package/dist/notrace/actions.js +1 -1
  19. package/dist/notrace/bus-DmKn4SDD.js +1 -0
  20. package/dist/notrace/effects.d.ts +2 -2
  21. package/dist/notrace/index.d.ts +2 -2
  22. package/dist/notrace/index.js +1 -1
  23. package/dist/notrace/{plugin-Dz6hq8Jg.d.ts → plugin-lJjjd-SN.d.ts} +1 -1
  24. package/dist/notrace/policies.d.ts +1 -1
  25. package/dist/notrace/policies.js +1 -1
  26. package/dist/notrace/redux.d.ts +1 -1
  27. package/dist/observable.d.ts +6 -6
  28. package/dist/oop.d.ts +2 -2
  29. package/dist/oop.js +1 -1
  30. package/dist/{plugin-D-j1DarG.d.ts → plugin-CuvIgjnX.d.ts} +2 -2
  31. package/dist/policies.d.ts +2 -2
  32. package/dist/react.d.ts +2 -2
  33. package/dist/redux.d.ts +1 -1
  34. package/dist/scope.d.ts +2 -2
  35. package/dist/signal.d.ts +1 -1
  36. package/dist/signal.js +1 -1
  37. package/dist/svelte.d.ts +1 -1
  38. package/dist/trace.d.ts +1 -1
  39. package/dist/{types-Bkuhnkq6.d.ts → types-FV8fuvI9.d.ts} +2 -2
  40. package/dist/vue.d.ts +1 -1
  41. package/dist/{with-policy-BeH8wCkX.d.ts → with-policy-3bhFLEXs.d.ts} +1 -1
  42. package/docs/README.md +5 -4
  43. package/docs/actions.md +94 -53
  44. package/docs/chat-example.md +8 -8
  45. package/docs/chat-widget.md +135 -0
  46. package/docs/context.md +1 -1
  47. package/docs/errors.md +1 -1
  48. package/docs/guide.md +26 -26
  49. package/docs/hmr.md +1 -1
  50. package/docs/motivation.md +10 -4
  51. package/docs/oop.md +1 -1
  52. package/docs/package.md +2 -2
  53. package/docs/plugins.md +23 -23
  54. package/docs/query-libraries.md +14 -14
  55. package/docs/scope.md +22 -22
  56. package/docs/server.md +12 -12
  57. package/docs/stability.md +2 -2
  58. package/docs/starter.md +3 -3
  59. package/docs/tracing.md +5 -5
  60. package/docs/typescript.md +16 -16
  61. package/llms-full.txt +380 -194
  62. package/llms.txt +3 -2
  63. package/package.json +5 -4
  64. package/dist/bus-hHp-T7JV.js +0 -1
  65. package/dist/event-0RIBGYqS.js +0 -1
  66. package/dist/notrace/bus-BdyvumpX.js +0 -1
  67. package/dist/notrace/promise-CSLpzwSR.js +0 -1
package/dist/match.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { D as EventPayload, J as UnsubscribeCallback, W as Task, h as Bus, p as Action, z as EventMap } from "./action-creator-Bpa8BUS9.js";
1
+ import { H as EventMap, Z as UnsubscribeCallback, h as Action, k as EventPayload, q as Task, v as Bus } from "./action-creator-CcAEvUnw.js";
2
2
  //#region src/match/plugin.d.ts
3
3
  /** A function over the action of an event: `{ type, payload }`. */
4
4
  type Predicate<E extends EventMap> = (action: Action<E>) => boolean;
@@ -1,5 +1,5 @@
1
- import { 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, z as EventMap } from "./action-creator-Bpa8BUS9.js";
2
- import { n as ScopeSlots, r as Scoped, t as FieldsOfScope } from "./types-Bkuhnkq6.js";
1
+ import { G as PayloadOf, H as EventMap, R as commandCall, S as Context, Z as UnsubscribeCallback, b as Command, c as Scope, g as Actions, q as Task, u as WithScope, v as Bus, x as CommandCall } from "./action-creator-CcAEvUnw.js";
2
+ import { n as ScopeSlots, r as Scoped } from "./types-FV8fuvI9.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> & {
@@ -17,67 +17,46 @@ type MadeCommand<P, R, T extends string> = Command<P, R> & {
17
17
  type CarryingCalls<Made, P, R, F> = [unknown] extends [F] ? Made : ((payload: P) => CommandCall<P, R> & WithScope<F>) & Made & WithScope<F>;
18
18
  /** A command made with a scope: its calls carry the fields of that scope, for the checker. */
19
19
  type ScopedCommand<P, R, T extends string, F> = ((payload: P) => CommandCall<P, R> & WithScope<F>) & MadeCommand<P, R, T> & WithScope<F>;
20
+ /** A command (or its type) with the handler to bind to it; `setHandler` makes one. */
21
+ type Binding<E extends EventMap = EventMap> = readonly [Command<never, unknown> | string, Task<never, E, unknown>];
20
22
  /**
21
- * Creates a command: a typed request for a result. Calling it builds
22
- * `{ type, payload }` like `createAction`. `bus.emit(command(payload))` (or
23
- * `bus.emit(command, payload)`) runs its handler as a task, with a context, and
24
- * returns what the handler returns. Listeners of the command's type are told
25
- * first, as for any event.
26
- *
27
- * The handler is optional. A command without one is only a contract, and the
28
- * bus gets its implementation from the `commands` registry (see
29
- * `commandsPlugin` and `bindHandler`). A handler bound there wins over the one
30
- * the command was created with, so a test can give a bus its own implementation.
31
- *
32
- * A handler can be wrapped in a policy, e.g. `latest(fn)`.
33
- * `command.match(action)` tells whether an action has the type of the command,
34
- * as it does for an action creator.
35
- *
36
- * A scope as the third argument, `{ cache, $effects: { race } }`, puts those fields on
37
- * the context of the handler and of the listeners of the command; the handler
38
- * sees them typed. It works on a bus that uses `scopePlugin` from
39
- * `nanoeffects/scope` and is ignored on any other.
23
+ * Pairs an action with the handler to bind to it, for `actionsPlugin`. For a
24
+ * command (an action made with a handler, or with a `Call` type) it checks that
25
+ * the handler fits; any other action is accepted with a handler of any payload.
40
26
  *
41
27
  * @example
42
28
  * ```ts
43
- * const getUser = createCommand("user/get", (id: string, { signal }) =>
44
- * fetchUser(id, { signal }),
45
- * );
46
- * const sendMail = createCommand<Mail, void>("mail/send"); // implemented elsewhere
47
- *
48
- * const bus = createBus<Events>();
49
- * bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
50
- * const user = await bus.emit(getUser("1"));
51
- *
52
- * commands.handle(getUser, async () => fakeUser); // in a test
29
+ * bus.use(actionsPlugin([setHandler(sendMail, smtpSend)]));
53
30
  * ```
54
31
  */
55
- declare function createCommand<P = void, R = void, T extends string = string, E extends EventMap = EventMap>(type: T, handler?: Task<P, E, R>): MadeCommand<P, R, T>;
56
- declare function createCommand<P, R, T extends string, S extends Scope = Record<never, never>>(type: T, handler: Task<P, Scoped<EventMap, S>, R> | undefined, scope: S): ScopedCommand<P, R, T, FieldsOfScope<EventMap, S>>;
57
- /** A command (or its type) with the handler to bind to it; `bindHandler` makes one. */
58
- type Binding<E extends EventMap = EventMap> = readonly [Command<never, unknown> | string, Task<never, E, unknown>];
32
+ declare function setHandler<P, R, E extends EventMap>(command: Command<P, R>, fn: Task<P, E, R>): Binding<E>;
33
+ declare function setHandler<A extends {
34
+ readonly type: string;
35
+ }, E extends EventMap>(action: A, fn: LooseHandler<A, E>): Binding<E>;
59
36
  /**
60
- * Pairs a command with the handler to bind to it, for `commandsPlugin`. It
61
- * checks that the handler fits the command.
62
- *
63
- * @example
64
- * ```ts
65
- * bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
66
- * ```
37
+ * The handler an action that is not a command can have: any. A command
38
+ * (a creator whose calls are command calls) is not accepted here, so its own
39
+ * overload checks the handler against its payload and result.
67
40
  */
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 {
41
+ type LooseHandler<A, E extends EventMap> = A extends ((...args: never[]) => {
42
+ readonly [commandCall]: unknown;
43
+ }) ? never : Task<never, E, unknown>;
44
+ /** The registry of handlers that `actionsPlugin` returns: `run` for the bus, `handle` to bind more. */
45
+ interface Registry$1<E extends EventMap> extends Actions {
71
46
  handle<P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
47
+ /** Also an action made without a handler: what is emitted for its type runs `fn` and returns its result. */
48
+ handle<A extends {
49
+ readonly type: string;
50
+ }>(action: A, fn: LooseHandler<A, E>): UnsubscribeCallback;
72
51
  handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
73
52
  handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
74
53
  }
75
54
  /**
76
55
  * The plugin that gives a bus the handlers bound to commands:
77
- * `bus.use(commandsPlugin(bindings))` makes the registry, sets it as the
56
+ * `bus.use(actionsPlugin(bindings))` makes the registry, sets it as the
78
57
  * commands of the bus and returns it. Each bus has its own, so each test can
79
58
  * have its own implementation. `handle` binds more later and returns the
80
- * function that unbinds. A second `commandsPlugin` on the same bus binds its
59
+ * function that unbinds. A second `actionsPlugin` on the same bus binds its
81
60
  * list in the registry that is there and returns it, so the order of the
82
61
  * plugins does not matter. A `commands` that is not such a registry (a custom
83
62
  * runner) is replaced.
@@ -88,13 +67,13 @@ interface Registry$1<E extends EventMap> extends Commands {
88
67
  * @example
89
68
  * ```ts
90
69
  * const bus = createBus<Events>();
91
- * const commands = bus.use(commandsPlugin([bindHandler(sendMail, smtpSend)]));
70
+ * const commands = bus.use(actionsPlugin([setHandler(sendMail, smtpSend)]));
92
71
  *
93
72
  * const unbind = commands.handle(getUser, async () => fakeUser);
94
73
  * unbind(); // the command's own handler is back
95
74
  * ```
96
75
  */
97
- declare const commandsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>[]) => (bus: Bus<E>) => Registry$1<E>;
76
+ declare const actionsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>[]) => (bus: Bus<E>) => Registry$1<E>;
98
77
  //#endregion
99
78
  //#region src/actions/module.d.ts
100
79
  /**
@@ -106,6 +85,10 @@ declare const commandsPlugin: <E extends EventMap>(bindings?: readonly Binding<E
106
85
  type ModuleContext<E extends EventMap = EventMap> = Context<E> & {
107
86
  /** Binds the handler of a command, or a list of them; undone on unmount. */
108
87
  handle<P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
88
+ /** Also an action made without a handler: the handler answers it as it would a command. */
89
+ handle<A extends {
90
+ readonly type: string;
91
+ }>(action: A, fn: LooseHandler<A, E>): UnsubscribeCallback;
109
92
  handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
110
93
  handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
111
94
  /**
@@ -141,7 +124,7 @@ type Module<E extends EventMap = EventMap> = {
141
124
  * ```ts
142
125
  * export const userModule = createModule<Events>("user", (m) => {
143
126
  * m.handle(getUser, fetchUser);
144
- * m.handle([bindHandler(sendMail, smtpSend)]);
127
+ * m.handle([setHandler(sendMail, smtpSend)]);
145
128
  * m.use(authModule);
146
129
  *
147
130
  * m.on(loginRequested, (user, ctx) => ctx.emit(userLoaded(user)));
@@ -153,7 +136,7 @@ type Module<E extends EventMap = EventMap> = {
153
136
  */
154
137
  declare function createModule<E extends EventMap = EventMap>(name: string, setup: (m: ModuleContext<E>) => void): Module<E>;
155
138
  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>;
156
- type Registry<E extends EventMap> = ReturnType<ReturnType<typeof commandsPlugin<E>>>;
139
+ type Registry<E extends EventMap> = ReturnType<ReturnType<typeof actionsPlugin<E>>>;
157
140
  /**
158
141
  * The modules of an app as the plugins that report on them see them: the part
159
142
  * of what `modulePlugin` returns that `devPlugin` wraps.
@@ -176,7 +159,7 @@ interface WithApp {
176
159
  /** What `modulePlugin` returns. */
177
160
  type ModuleApi<E extends EventMap = EventMap> = {
178
161
  /** The registry of command handlers of the bus: the one it was made with, or the app's own. */
179
- commands: Registry<E>;
162
+ actions: Registry<E>;
180
163
  /**
181
164
  * Mounts modules, in the order given, and returns the function that unmounts them, last
182
165
  * mounted first. A module that is mounted already is not run again. If one of them throws,
@@ -198,15 +181,15 @@ type ModuleApi<E extends EventMap = EventMap> = {
198
181
  };
199
182
  /**
200
183
  * The plugin that assembles an app from modules: `bus.use(modulePlugin(modules))`
201
- * returns `mount`, `unmount`, `isMounted`, `dispose` and `commands` for the
184
+ * returns `mount`, `unmount`, `isMounted`, `dispose` and `actions` for the
202
185
  * modules that come and go, and mounts `modules`, in the order given, on the
203
186
  * first use of the app or of the bus: the first `bus.emit`, or the first call
204
187
  * of one of its methods. By then every plugin is on the bus, so the plugins can
205
188
  * be used in any order. The `on`, `once` and `off` calls made in between are
206
189
  * held and made right after the modules, so the listeners of a module stay
207
190
  * ahead of them. The bus runs the commands that the modules bind: the registry
208
- * that the bus has is used (a later `commandsPlugin` binds in it), otherwise the
209
- * app attaches its own, as `app.commands`. The app is also `bus.app`.
191
+ * that the bus has is used (a later `actionsPlugin` binds in it), otherwise the
192
+ * app attaches its own, as `app.actions`. The app is also `bus.app`.
210
193
  *
211
194
  * A module is known by its `name`: mounting a module whose name is taken
212
195
  * replaces the mounted one, which is unmounted first. That is what hot reload
@@ -231,10 +214,10 @@ type ModuleApi<E extends EventMap = EventMap> = {
231
214
  * });
232
215
  *
233
216
  * bus.emit(getUser, "1");
234
- * app.commands.handle(getUser, fakeUser); // in a test
217
+ * app.actions.handle(getUser, fakeUser); // in a test
235
218
  * app.dispose();
236
219
  * ```
237
220
  */
238
221
  declare const modulePlugin: <E extends EventMap>(modules?: readonly Module<E>[]) => (bus: Bus<E> & ScopeSlots & WithApp) => ModuleApi<E>;
239
222
  //#endregion
240
- 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 };
223
+ export { createModule as a, CarryingCalls as c, actionsPlugin as d, setHandler as f, WithApp as i, MadeCommand as l, ModuleApi as n, modulePlugin as o, ModuleContext as r, Binding as s, Module as t, ScopedCommand as u };
@@ -14,6 +14,27 @@ type UnsubscribeCallback = () => void;
14
14
  //#endregion
15
15
  //#region src/core/store.d.ts
16
16
  declare const anyEventType = "*";
17
+ type AnyType = "*";
18
+ interface UnsubscribeTask<E extends EventMap> {
19
+ (task: Task<DataOf<E[Keys<E>]>, E>): void;
20
+ <K extends AnyType>(key: K, task?: Task<DataOf<E[Keys<E>]>, E>): void;
21
+ <K extends Keys<E>>(key: K, task?: Task<DataOf<E[K]>, E>): void;
22
+ }
23
+ type Store<E extends EventMap> = {
24
+ get: {
25
+ /** Every listener of every event, in the order of the events. */
26
+ (): Task<DataOf<E[Keys<E>]>, E>[];
27
+ (key: AnyType): Task<DataOf<E[Keys<E>]>, E>[];
28
+ <K extends Keys<E>>(key: K): Task<DataOf<E[K]>, E>[];
29
+ };
30
+ add: {
31
+ (key: AnyType, task: Task<DataOf<E[Keys<E>]>, E>): UnsubscribeCallback;
32
+ <K extends Keys<E>>(key: K, task: Task<DataOf<E[K]>, E>): UnsubscribeCallback;
33
+ };
34
+ remove: UnsubscribeTask<E>;
35
+ /** Drops every key; lists already handed out by `get` stay as they were. */
36
+ clear: () => void;
37
+ };
17
38
  //#endregion
18
39
  //#region src/core/tracer.d.ts
19
40
  /**
@@ -49,7 +70,7 @@ interface Tracer<Ref extends object = object> {
49
70
  /** Subscribes to every event; handlers receive the payload of any of them. */
50
71
  type AnyEvent = typeof anyEventType;
51
72
  type EventKey<E extends EventMap> = Keys<E>;
52
- type EventPayload<E extends EventMap> = E[EventKey<E>];
73
+ type EventPayload<E extends EventMap> = DataOf<E[EventKey<E>]>;
53
74
  type WithType<K extends string> = {
54
75
  type: K;
55
76
  };
@@ -69,7 +90,7 @@ type WithSignal = {
69
90
  type HandlerRef<E extends EventMap, Response = unknown> = (action: Action<E>) => Response;
70
91
  type Handler<E extends EventMap, Response = unknown, K extends EventKey<E> = EventKey<E>> = { [P in K]: {
71
92
  type: P;
72
- (payload: E[P]): Response;
93
+ (payload: DataOf<E[P]>): Response;
73
94
  }; }[K];
74
95
  type Action<E extends EventMap> = {
75
96
  type: EventKey<E>;
@@ -103,35 +124,45 @@ type Command<P = never, R = unknown> = {
103
124
  readonly wrap?: (run: (payload: never, ctx: never) => unknown) => (payload: never, ctx: never) => unknown;
104
125
  };
105
126
  /**
106
- * What the bus needs to run commands. The implementation, `commandsPlugin` in
107
- * `nanoeffects/actions`, holds the handlers bound to commands and runs the
108
- * right one, so a bus without `commands` carries none of that.
127
+ * What the bus needs to run the handlers of actions. The implementation,
128
+ * `actionsPlugin` in `nanoeffects/actions`, holds the handlers bound to
129
+ * actions and runs the right one, so a bus without `actions` carries none of
130
+ * that. `bound` tells, for an event type, whether a handler is bound to it: an
131
+ * action with no handler of its own is a command only then. A runner that has
132
+ * no `bound` runs commands only.
109
133
  */
110
- interface Commands {
134
+ interface Actions {
111
135
  run(command: Command, payload: unknown, ctx: unknown): unknown;
136
+ bound?(type: string): Command | undefined;
112
137
  }
113
138
  /** Anything `emit` takes as its first argument: an event type, an action or a command. */
114
139
  type Emittable<E extends EventMap> = EventKey<E> | Command | CommandCall | EventLike<E>;
115
140
  type Emit<E extends EventMap> = {
116
- <K extends EventKey<E>>(event: K, ...payload: PayloadOf<E[K]>): void;
141
+ /**
142
+ * On a bus without an event map the caller can say what a handler bound for
143
+ * the type returns: `bus.emit<string>("user/getId")`. With a map the parameter
144
+ * is `never`, so this form is not taken and no check of names or payloads is lost.
145
+ */
146
+ <R = void>(type: string extends EventKey<E> ? string : never, ...payload: unknown[]): R;
147
+ <K extends EventKey<E>>(event: K, ...payload: PayloadOf<DataOf<E[K]>>): ResultOf<E[K]>;
117
148
  /** Before Handler: a command is callable too, and must return its result type. */
118
149
  <P, R>(command: Command<P, R>, ...payload: PayloadOf<P>): R;
119
150
  /** A scope as the second argument replaces context fields for the tasks of this emit; see `scopePlugin`. */
120
151
  <P, R, F>(call: CommandCall<P, R> & WithScope<F>, scope?: EmitScope<E, F>): R;
121
152
  <P, R>(call: CommandCall<P, R>, scope?: EmitScope<E>): R;
122
- <K extends EventKey<E>, R>(event: Handler<E, R, K>, ...payload: PayloadOf<E[K]>): R;
153
+ <K extends EventKey<E>, R>(event: Handler<E, R, K>, ...payload: PayloadOf<DataOf<E[K]>>): R;
123
154
  <F>(event: EventLike<E> & WithScope<F>, scope?: EmitScope<E, F>): void;
124
155
  (event: EventLike<E>, scope?: EmitScope<E>): void;
125
156
  };
126
157
  type On<E extends EventMap> = {
127
158
  (event: AnyEvent, fn: Task<EventPayload<E>, E>, options?: ListenerOptions): UnsubscribeCallback;
128
- <K extends EventKey<E>>(event: K, fn: Task<E[K], E>, options?: ListenerOptions): UnsubscribeCallback;
159
+ <K extends EventKey<E>>(event: K, fn: Task<DataOf<E[K]>, E>, options?: ListenerOptions): UnsubscribeCallback;
129
160
  /** An action creator without a payload type: the payload comes from the event map. */
130
161
  /** The creators and commands that carry a scope come first: the handler sees their fields. */
131
- <K extends EventKey<E>, F>(creator: FreeActionCreator<K, F> & WithScope<F>, fn: Task<E[K], WithFields<E, F>>, options?: ListenerOptions): UnsubscribeCallback;
162
+ <K extends EventKey<E>, F>(creator: FreeActionCreator<K, F> & WithScope<F>, fn: Task<DataOf<E[K]>, WithFields<E, F>>, options?: ListenerOptions): UnsubscribeCallback;
132
163
  <P, F>(creator: ActionCreator<P, string, PayloadOf<P>, F> & WithScope<F>, fn: Task<P, WithFields<E, F>>, options?: ListenerOptions): UnsubscribeCallback;
133
164
  <P, F>(command: Command<P, unknown> & WithScope<F>, fn: Task<P, WithFields<E, F>>, options?: ListenerOptions): UnsubscribeCallback;
134
- <K extends EventKey<E>>(creator: FreeActionCreator<K>, fn: Task<E[K], E>, options?: ListenerOptions): UnsubscribeCallback;
165
+ <K extends EventKey<E>>(creator: FreeActionCreator<K>, fn: Task<DataOf<E[K]>, E>, options?: ListenerOptions): UnsubscribeCallback;
135
166
  /** An action creator: the payload comes from it, so an event map is not needed. */
136
167
  <P>(creator: ActionCreator<P>, fn: Task<P, E>, options?: ListenerOptions): UnsubscribeCallback;
137
168
  /** A command: the payload comes from it too. */
@@ -140,7 +171,7 @@ type On<E extends EventMap> = {
140
171
  type: K;
141
172
  }>(event: Event & {
142
173
  type: K;
143
- }, fn: Task<E[K], E>, options?: ListenerOptions): UnsubscribeCallback;
174
+ }, fn: Task<DataOf<E[K]>, E>, options?: ListenerOptions): UnsubscribeCallback;
144
175
  };
145
176
  type Off<E extends EventMap> = {
146
177
  /** Removes every listener of every event (including `"*"`). */
@@ -148,12 +179,12 @@ type Off<E extends EventMap> = {
148
179
  (event: AnyEvent): void;
149
180
  (event: AnyEvent, fn: Task<EventPayload<E>, E>): void;
150
181
  <K extends EventKey<E>>(event: K): void;
151
- <K extends EventKey<E>>(event: K, fn: Task<E[K], E>): void;
182
+ <K extends EventKey<E>>(event: K, fn: Task<DataOf<E[K]>, E>): void;
152
183
  <K extends EventKey<E>, Event extends {
153
184
  type: K;
154
185
  }>(event: Event & {
155
186
  type: K;
156
- }, fn: Task<E[K], E>): void;
187
+ }, fn: Task<DataOf<E[K]>, E>): void;
157
188
  <P>(command: Command<P, unknown>, fn?: Task<P, E>): void;
158
189
  };
159
190
  declare const contextKey: unique symbol;
@@ -217,6 +248,24 @@ interface Bus<E extends EventMap> {
217
248
  */
218
249
  once: On<E>;
219
250
  off: Off<E>;
251
+ /**
252
+ * The listeners an event has right now, in the order they run: what `on`,
253
+ * `once`, `ctx.on` and the `on` of a module registered, as the bus holds them
254
+ * (a plugin may have wrapped a function, so compare the length, not the
255
+ * functions). It takes the event name as a string, as the bus stores it, not
256
+ * an action creator: use `creator.type`. `"*"` gives the any-event listeners,
257
+ * which a named event does not include. The array is not changed afterwards: a later `on` or unbind
258
+ * gives the next `get` a new one.
259
+ *
260
+ * @example
261
+ * ```ts
262
+ * const unbind = bus.on("saved", save);
263
+ * bus.get("saved").length; // 1
264
+ * unbind();
265
+ * bus.get("saved").length; // 0
266
+ * ```
267
+ */
268
+ get: Store<E>["get"];
220
269
  emit: Emit<E>;
221
270
  /**
222
271
  * Calls `plugin` with the bus and returns what it returns: an api, a
@@ -224,10 +273,10 @@ interface Bus<E extends EventMap> {
224
273
  * no list of them. See `modulePlugin` in `nanoeffects/actions`.
225
274
  */
226
275
  use<R>(plugin: (bus: Bus<E>) => R): R;
227
- /** `BusOptions.context` and `.trace`, and `commands`, for what makes tasks of its own, like `modulePlugin`. */
276
+ /** `BusOptions.context` and `.trace`, and `actions`, for what makes tasks of its own, like `modulePlugin`. */
228
277
  readonly ctx?: ContextOption<E> | undefined;
229
- /** What runs the commands; `commandsPlugin` and `modulePlugin` set it. Without one a command runs its own handler. */
230
- commands?: Commands | undefined;
278
+ /** What runs the handlers of actions; `actionsPlugin` and `modulePlugin` set it. Without one a command runs its own handler. */
279
+ actions?: Actions | undefined;
231
280
  readonly trace?: Tracer | undefined;
232
281
  /** Called with every new task context to add fields to it, for what needs the task, like `effectsPlugin`. Chain to the previous one. */
233
282
  addContext?: ((ctx: object) => void) | undefined;
@@ -245,8 +294,8 @@ type BusOptions<E extends EventMap> = {
245
294
  onError?: (error: unknown, event: Action<E>) => void;
246
295
  /**
247
296
  * Called when an event is emitted and nobody listens to it: the usual sign
248
- * of a typo in an event name. Not called for commands, which always have a
249
- * handler to run. Typically a warning in development only.
297
+ * of a typo in an event name. Not called for commands, nor for an action with
298
+ * a handler bound in `actions`, which always have a handler to run. Typically a warning in development only.
250
299
  *
251
300
  * @example
252
301
  * ```ts
@@ -336,15 +385,33 @@ type Merge<A, B> = Omit<A, keyof B> & B;
336
385
  type WithFields<E extends EventMap, F> = [unknown] extends [F] ? E : Omit<E, keyof WithContext<object>> & WithContext<Merge<ContextOf<E>, F>>;
337
386
  //#endregion
338
387
  //#region src/core/action-creator.d.ts
339
- type WithPayload<E extends EventMap, K extends Keys<E>> = undefined extends E[K] ? {
388
+ type WithPayload<E extends EventMap, K extends Keys<E>> = undefined extends DataOf<E[K]> ? {
340
389
  type: K;
341
- payload?: E[K];
390
+ payload?: DataOf<E[K]>;
342
391
  } : {
343
392
  type: K;
344
- payload: E[K];
393
+ payload: DataOf<E[K]>;
345
394
  };
346
395
  type Absent<P> = [P] extends [void] ? undefined : P;
347
396
  type Made<P, T extends string> = WithPayload<{ [K in T]: Absent<P>; }, T>;
397
+ declare const callBrand: unique symbol;
398
+ /**
399
+ * A payload type together with the type of what a handler of the action
400
+ * returns, for an event map or `createAction`:
401
+ * `type Events = { "user/getId": Call<void, string> }`, and then
402
+ * `bus.emit("user/getId")` is a `string`. A type only: it adds nothing to a
403
+ * bundle, and an entry that is not a `Call` means a payload, with no result.
404
+ */
405
+ type Call<P = void, R = void> = {
406
+ readonly [callBrand]: {
407
+ payload: P;
408
+ result: R;
409
+ };
410
+ };
411
+ /** The payload type of an entry of an event map: the `P` of a `Call<P, R>`, the entry itself otherwise. */
412
+ type DataOf<T> = T extends Call<infer P, unknown> ? P : T;
413
+ /** What `emit` returns for an entry of an event map: the `R` of a `Call<P, R>`, `void` otherwise. */
414
+ type ResultOf<T> = T extends Call<unknown, infer R> ? R : void;
348
415
  declare const free: unique symbol;
349
416
  type Free = typeof free;
350
417
  /**
@@ -387,4 +454,4 @@ interface ActionCreator<P = void, T extends string = string, A extends unknown[]
387
454
  toString(): T;
388
455
  }
389
456
  //#endregion
390
- export { On as A, EventKey as C, Handler as D, EventsOf as E, EventMap as F, Keys as I, PayloadOf as L, WithSignal as M, WithType as N, HandlerRef as O, createBus as P, Task as R, Emittable as S, EventPayload as T, Commands as _, Scope as a, ContextOption as b, BoundForm as c, Action as d, AnyEvent as f, CommandCall as g, Command as h, WithPayload as i, WithContext as j, Off as k, Effect as l, BusOptions as m, Free as n, WithFields as o, Bus as p, FreeActionCreator as r, WithScope as s, ActionCreator as t, Effects as u, Context as v, EventLike as w, Emit as x, ContextOf as y, UnsubscribeCallback as z };
457
+ export { Off as A, Task as B, Emittable as C, EventsOf as D, EventPayload as E, commandCall as F, createBus as I, EventMap as L, WithContext as M, WithSignal as N, Handler as O, WithType as P, Keys as R, Emit as S, EventLike as T, UnsubscribeCallback as V, Command as _, WithPayload as a, ContextOf as b, WithScope as c, Effects as d, Action as f, BusOptions as g, Bus as h, FreeActionCreator as i, On as j, HandlerRef as k, BoundForm as l, AnyEvent as m, Call as n, Scope as o, Actions as p, Free as r, WithFields as s, ActionCreator as t, Effect as u, CommandCall as v, EventKey as w, ContextOption as x, Context as y, PayloadOf as z };