nanoeffects 0.25.0 → 0.27.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +76 -23
  2. package/dist/{action-creator-Bpa8BUS9.d.ts → action-creator-D_c223C7.d.ts} +51 -23
  3. package/dist/actions.d.ts +54 -21
  4. package/dist/actions.js +1 -1
  5. package/dist/{bus-hHp-T7JV.js → bus-DQDHUN5e.js} +1 -1
  6. package/dist/{context-types-BKIH5a8s.d.ts → context-types-nGtzhjxD.d.ts} +1 -1
  7. package/dist/context.d.ts +2 -2
  8. package/dist/dev.d.ts +2 -2
  9. package/dist/effects.d.ts +2 -2
  10. package/dist/index.d.ts +2 -2
  11. package/dist/index.js +1 -1
  12. package/dist/match.d.ts +1 -1
  13. package/dist/{module-B5V47MZ0.d.ts → module-WX0Gngnt.d.ts} +40 -57
  14. package/dist/notrace/{action-creator-D2CotugT.d.ts → action-creator-Bux7Zzsl.d.ts} +51 -23
  15. package/dist/notrace/actions.d.ts +114 -98
  16. package/dist/notrace/actions.js +1 -1
  17. package/dist/notrace/{bus-BdyvumpX.js → bus-CGi2lrd5.js} +1 -1
  18. package/dist/notrace/effects.d.ts +2 -2
  19. package/dist/notrace/index.d.ts +2 -2
  20. package/dist/notrace/index.js +1 -1
  21. package/dist/notrace/{plugin-ks-oNq5n.d.ts → plugin-CATXOxtj.d.ts} +10 -9
  22. package/dist/notrace/policies.d.ts +1 -1
  23. package/dist/notrace/redux.d.ts +1 -1
  24. package/dist/observable.d.ts +6 -6
  25. package/dist/oop.d.ts +2 -2
  26. package/dist/oop.js +1 -1
  27. package/dist/{plugin-B6UQyoVd.d.ts → plugin-vvkmIIz2.d.ts} +11 -10
  28. package/dist/policies.d.ts +2 -2
  29. package/dist/react.d.ts +2 -2
  30. package/dist/redux.d.ts +1 -1
  31. package/dist/scope.d.ts +2 -2
  32. package/dist/signal.d.ts +1 -1
  33. package/dist/signal.js +1 -1
  34. package/dist/svelte.d.ts +1 -1
  35. package/dist/trace.d.ts +1 -1
  36. package/dist/{types-DWjyeii7.d.ts → types-Bf-LX_tE.d.ts} +2 -2
  37. package/dist/vue.d.ts +1 -1
  38. package/dist/{with-policy-BeH8wCkX.d.ts → with-policy-CPjx0sLm.d.ts} +1 -1
  39. package/docs/README.md +5 -4
  40. package/docs/actions.md +93 -52
  41. package/docs/chat-example.md +6 -6
  42. package/docs/context.md +1 -1
  43. package/docs/effects.md +2 -2
  44. package/docs/errors.md +1 -1
  45. package/docs/guide.md +25 -25
  46. package/docs/hmr.md +1 -1
  47. package/docs/motivation.md +10 -4
  48. package/docs/oop.md +2 -0
  49. package/docs/package.md +1 -1
  50. package/docs/plugins.md +23 -23
  51. package/docs/query-libraries.md +14 -14
  52. package/docs/scope.md +22 -22
  53. package/docs/server.md +12 -12
  54. package/docs/stability.md +90 -0
  55. package/docs/starter.md +1 -1
  56. package/docs/tracing.md +2 -2
  57. package/docs/typescript.md +16 -16
  58. package/llms-full.txt +326 -183
  59. package/llms.txt +3 -2
  60. package/package.json +4 -3
@@ -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-DWjyeii7.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-D_c223C7.js";
2
+ import { n as ScopeSlots, r as Scoped } from "./types-Bf-LX_tE.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 };
@@ -49,7 +49,7 @@ interface Tracer<Ref extends object = object> {
49
49
  /** Subscribes to every event; handlers receive the payload of any of them. */
50
50
  type AnyEvent = typeof anyEventType;
51
51
  type EventKey<E extends EventMap> = Keys<E>;
52
- type EventPayload<E extends EventMap> = E[EventKey<E>];
52
+ type EventPayload<E extends EventMap> = DataOf<E[EventKey<E>]>;
53
53
  type WithType<K extends string> = {
54
54
  type: K;
55
55
  };
@@ -69,7 +69,7 @@ type WithSignal = {
69
69
  type HandlerRef<E extends EventMap, Response = unknown> = (action: Action<E>) => Response;
70
70
  type Handler<E extends EventMap, Response = unknown, K extends EventKey<E> = EventKey<E>> = { [P in K]: {
71
71
  type: P;
72
- (payload: E[P]): Response;
72
+ (payload: DataOf<E[P]>): Response;
73
73
  }; }[K];
74
74
  type Action<E extends EventMap> = {
75
75
  type: EventKey<E>;
@@ -103,35 +103,45 @@ type Command<P = never, R = unknown> = {
103
103
  readonly wrap?: (run: (payload: never, ctx: never) => unknown) => (payload: never, ctx: never) => unknown;
104
104
  };
105
105
  /**
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.
106
+ * What the bus needs to run the handlers of actions. The implementation,
107
+ * `actionsPlugin` in `nanoeffects/actions`, holds the handlers bound to
108
+ * actions and runs the right one, so a bus without `actions` carries none of
109
+ * that. `bound` tells, for an event type, whether a handler is bound to it: an
110
+ * action with no handler of its own is a command only then. A runner that has
111
+ * no `bound` runs commands only.
109
112
  */
110
- interface Commands {
113
+ interface Actions {
111
114
  run(command: Command, payload: unknown, ctx: unknown): unknown;
115
+ bound?(type: string): Command | undefined;
112
116
  }
113
117
  /** Anything `emit` takes as its first argument: an event type, an action or a command. */
114
118
  type Emittable<E extends EventMap> = EventKey<E> | Command | CommandCall | EventLike<E>;
115
119
  type Emit<E extends EventMap> = {
116
- <K extends EventKey<E>>(event: K, ...payload: PayloadOf<E[K]>): void;
120
+ /**
121
+ * On a bus without an event map the caller can say what a handler bound for
122
+ * the type returns: `bus.emit<string>("user/getId")`. With a map the parameter
123
+ * is `never`, so this form is not taken and no check of names or payloads is lost.
124
+ */
125
+ <R = void>(type: string extends EventKey<E> ? string : never, ...payload: unknown[]): R;
126
+ <K extends EventKey<E>>(event: K, ...payload: PayloadOf<DataOf<E[K]>>): ResultOf<E[K]>;
117
127
  /** Before Handler: a command is callable too, and must return its result type. */
118
128
  <P, R>(command: Command<P, R>, ...payload: PayloadOf<P>): R;
119
129
  /** A scope as the second argument replaces context fields for the tasks of this emit; see `scopePlugin`. */
120
130
  <P, R, F>(call: CommandCall<P, R> & WithScope<F>, scope?: EmitScope<E, F>): R;
121
131
  <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;
132
+ <K extends EventKey<E>, R>(event: Handler<E, R, K>, ...payload: PayloadOf<DataOf<E[K]>>): R;
123
133
  <F>(event: EventLike<E> & WithScope<F>, scope?: EmitScope<E, F>): void;
124
134
  (event: EventLike<E>, scope?: EmitScope<E>): void;
125
135
  };
126
136
  type On<E extends EventMap> = {
127
137
  (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;
138
+ <K extends EventKey<E>>(event: K, fn: Task<DataOf<E[K]>, E>, options?: ListenerOptions): UnsubscribeCallback;
129
139
  /** An action creator without a payload type: the payload comes from the event map. */
130
140
  /** 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;
141
+ <K extends EventKey<E>, F>(creator: FreeActionCreator<K, F> & WithScope<F>, fn: Task<DataOf<E[K]>, WithFields<E, F>>, options?: ListenerOptions): UnsubscribeCallback;
132
142
  <P, F>(creator: ActionCreator<P, string, PayloadOf<P>, F> & WithScope<F>, fn: Task<P, WithFields<E, F>>, options?: ListenerOptions): UnsubscribeCallback;
133
143
  <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;
144
+ <K extends EventKey<E>>(creator: FreeActionCreator<K>, fn: Task<DataOf<E[K]>, E>, options?: ListenerOptions): UnsubscribeCallback;
135
145
  /** An action creator: the payload comes from it, so an event map is not needed. */
136
146
  <P>(creator: ActionCreator<P>, fn: Task<P, E>, options?: ListenerOptions): UnsubscribeCallback;
137
147
  /** A command: the payload comes from it too. */
@@ -140,7 +150,7 @@ type On<E extends EventMap> = {
140
150
  type: K;
141
151
  }>(event: Event & {
142
152
  type: K;
143
- }, fn: Task<E[K], E>, options?: ListenerOptions): UnsubscribeCallback;
153
+ }, fn: Task<DataOf<E[K]>, E>, options?: ListenerOptions): UnsubscribeCallback;
144
154
  };
145
155
  type Off<E extends EventMap> = {
146
156
  /** Removes every listener of every event (including `"*"`). */
@@ -148,12 +158,12 @@ type Off<E extends EventMap> = {
148
158
  (event: AnyEvent): void;
149
159
  (event: AnyEvent, fn: Task<EventPayload<E>, E>): void;
150
160
  <K extends EventKey<E>>(event: K): void;
151
- <K extends EventKey<E>>(event: K, fn: Task<E[K], E>): void;
161
+ <K extends EventKey<E>>(event: K, fn: Task<DataOf<E[K]>, E>): void;
152
162
  <K extends EventKey<E>, Event extends {
153
163
  type: K;
154
164
  }>(event: Event & {
155
165
  type: K;
156
- }, fn: Task<E[K], E>): void;
166
+ }, fn: Task<DataOf<E[K]>, E>): void;
157
167
  <P>(command: Command<P, unknown>, fn?: Task<P, E>): void;
158
168
  };
159
169
  declare const contextKey: unique symbol;
@@ -224,10 +234,10 @@ interface Bus<E extends EventMap> {
224
234
  * no list of them. See `modulePlugin` in `nanoeffects/actions`.
225
235
  */
226
236
  use<R>(plugin: (bus: Bus<E>) => R): R;
227
- /** `BusOptions.context` and `.trace`, and `commands`, for what makes tasks of its own, like `modulePlugin`. */
237
+ /** `BusOptions.context` and `.trace`, and `actions`, for what makes tasks of its own, like `modulePlugin`. */
228
238
  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;
239
+ /** What runs the handlers of actions; `actionsPlugin` and `modulePlugin` set it. Without one a command runs its own handler. */
240
+ actions?: Actions | undefined;
231
241
  readonly trace?: Tracer | undefined;
232
242
  /** Called with every new task context to add fields to it, for what needs the task, like `effectsPlugin`. Chain to the previous one. */
233
243
  addContext?: ((ctx: object) => void) | undefined;
@@ -245,8 +255,8 @@ type BusOptions<E extends EventMap> = {
245
255
  onError?: (error: unknown, event: Action<E>) => void;
246
256
  /**
247
257
  * 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.
258
+ * of a typo in an event name. Not called for commands, nor for an action with
259
+ * a handler bound in `actions`, which always have a handler to run. Typically a warning in development only.
250
260
  *
251
261
  * @example
252
262
  * ```ts
@@ -336,15 +346,33 @@ type Merge<A, B> = Omit<A, keyof B> & B;
336
346
  type WithFields<E extends EventMap, F> = [unknown] extends [F] ? E : Omit<E, keyof WithContext<object>> & WithContext<Merge<ContextOf<E>, F>>;
337
347
  //#endregion
338
348
  //#region src/core/action-creator.d.ts
339
- type WithPayload<E extends EventMap, K extends Keys<E>> = undefined extends E[K] ? {
349
+ type WithPayload<E extends EventMap, K extends Keys<E>> = undefined extends DataOf<E[K]> ? {
340
350
  type: K;
341
- payload?: E[K];
351
+ payload?: DataOf<E[K]>;
342
352
  } : {
343
353
  type: K;
344
- payload: E[K];
354
+ payload: DataOf<E[K]>;
345
355
  };
346
356
  type Absent<P> = [P] extends [void] ? undefined : P;
347
357
  type Made<P, T extends string> = WithPayload<{ [K in T]: Absent<P>; }, T>;
358
+ declare const callBrand: unique symbol;
359
+ /**
360
+ * A payload type together with the type of what a handler of the action
361
+ * returns, for an event map or `createAction`:
362
+ * `type Events = { "user/getId": Call<void, string> }`, and then
363
+ * `bus.emit("user/getId")` is a `string`. A type only: it adds nothing to a
364
+ * bundle, and an entry that is not a `Call` means a payload, with no result.
365
+ */
366
+ type Call<P = void, R = void> = {
367
+ readonly [callBrand]: {
368
+ payload: P;
369
+ result: R;
370
+ };
371
+ };
372
+ /** The payload type of an entry of an event map: the `P` of a `Call<P, R>`, the entry itself otherwise. */
373
+ type DataOf<T> = T extends Call<infer P, unknown> ? P : T;
374
+ /** What `emit` returns for an entry of an event map: the `R` of a `Call<P, R>`, `void` otherwise. */
375
+ type ResultOf<T> = T extends Call<unknown, infer R> ? R : void;
348
376
  declare const free: unique symbol;
349
377
  type Free = typeof free;
350
378
  /**
@@ -387,4 +415,4 @@ interface ActionCreator<P = void, T extends string = string, A extends unknown[]
387
415
  toString(): T;
388
416
  }
389
417
  //#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 };
418
+ 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 };