nanoeffects 0.7.0 → 0.8.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 (47) hide show
  1. package/dist/{action-creator-Bd4TBZgl.d.ts → action-creator-BrZF6hXc.d.ts} +0 -4
  2. package/dist/actions.d.ts +3 -3
  3. package/dist/actions.js +1 -1
  4. package/dist/{context-plugin-BVNKqkIx.d.ts → context-plugin--HkNN1ha.d.ts} +1 -1
  5. package/dist/dev.d.ts +9 -8
  6. package/dist/dev.js +1 -1
  7. package/dist/effects.d.ts +2 -2
  8. package/dist/effects.js +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/match.d.ts +50 -0
  11. package/dist/match.js +1 -0
  12. package/dist/{module-DZ5ngUrM.d.ts → module-DqKegXHt.d.ts} +43 -18
  13. package/dist/notrace/{action-creator-D-y_-xRS.d.ts → action-creator-DHAEgwuh.d.ts} +0 -4
  14. package/dist/notrace/actions.d.ts +52 -17
  15. package/dist/notrace/actions.js +1 -1
  16. package/dist/notrace/{context-plugin-DDfsaErA.d.ts → context-plugin-BapQkGwQ.d.ts} +1 -1
  17. package/dist/notrace/effects.d.ts +2 -2
  18. package/dist/notrace/effects.js +1 -1
  19. package/dist/notrace/index.d.ts +2 -2
  20. package/dist/notrace/{plugin-CDAngHwg.d.ts → plugin-Cxadz6uU.d.ts} +2 -2
  21. package/dist/notrace/policies.d.ts +1 -1
  22. package/dist/notrace/redux.d.ts +1 -1
  23. package/dist/observable.d.ts +1 -1
  24. package/dist/oop.d.ts +131 -0
  25. package/dist/oop.js +1 -0
  26. package/dist/{plugin-DQNPBcxx.d.ts → plugin-DkXCvsmB.d.ts} +2 -2
  27. package/dist/policies.d.ts +1 -1
  28. package/dist/react.d.ts +1 -1
  29. package/dist/redux.d.ts +1 -1
  30. package/dist/scope.d.ts +5 -6
  31. package/dist/trace.d.ts +1 -1
  32. package/dist/{types-BJ0fzV1p.d.ts → types-KavbvHix.d.ts} +13 -3
  33. package/docs/README.md +1 -0
  34. package/docs/actions.md +79 -35
  35. package/docs/guide.md +142 -18
  36. package/docs/hmr.md +6 -5
  37. package/docs/migrating-from-effector.md +49 -16
  38. package/docs/migrating-from-rxjs.md +17 -6
  39. package/docs/oop.md +286 -0
  40. package/docs/package.md +2 -0
  41. package/docs/plugins.md +227 -51
  42. package/docs/react.md +17 -5
  43. package/docs/scope.md +60 -22
  44. package/docs/stores.md +263 -109
  45. package/llms-full.txt +1152 -267
  46. package/llms.txt +1 -0
  47. package/package.json +20 -2
package/docs/hmr.md CHANGED
@@ -21,7 +21,7 @@ A `bus.on` outside a module returns the function that unsubscribes: hand it to t
21
21
 
22
22
  ## Report leaks with `devPlugin`
23
23
 
24
- `bus.use(devPlugin({ app }))` reports what is easy to miss while developing:
24
+ `bus.use(devPlugin())` reports what is easy to miss while developing:
25
25
 
26
26
  ```js
27
27
  import { createBus } from "nanoeffects";
@@ -29,13 +29,14 @@ import { modulePlugin } from "nanoeffects/actions";
29
29
  import { devPlugin } from "nanoeffects/dev";
30
30
 
31
31
  const bus = createBus();
32
- const app = bus.use(modulePlugin([userModule]));
32
+ bus.use(modulePlugin([userModule]));
33
33
  // devPlugin — warn on piled-up listeners; log module mount/replace/unmount
34
- bus.use(devPlugin({ app }));
34
+ // (it finds the app of modulePlugin on the bus, in either order of the two)
35
+ bus.use(devPlugin());
35
36
  ```
36
37
 
37
38
  - **Listeners that pile up.** When more than `maxListeners` (default `10`) listeners of one event were added and not unsubscribed, one warning names the event and the count. The count follows the function that `on` returns; `bus.off(event, fn)` is not seen.
38
- - **Modules.** With `app` it logs `module "user" mounted`, `replaced` when a module of the same name was mounted, and `unmounted`. Only what goes through `app.mount` and `app.unmount` is reported, not sub-modules.
39
+ - **Modules.** For the app of `modulePlugin` (or the `app` option) it logs `module "user" mounted`, `replaced` when a module of the same name was mounted, and `unmounted`. Only what goes through `app.mount` and `app.unmount` is reported, not sub-modules.
39
40
  - **Options.** `leaks: false` and `modules: false` switch a diagnostic off; `maxListeners` sets the limit; `log` receives the messages instead of the console.
40
41
  - **Disconnect.** `bus.use(devPlugin(...))` returns the function that stops the diagnostics and puts `bus.on` and `app.mount` back.
41
42
 
@@ -43,6 +44,6 @@ It changes no behavior: it wraps `bus.on`, `app.mount`, and `app.unmount` and ad
43
44
 
44
45
  ### Keep the import in production
45
46
 
46
- `nanoeffects/dev` is a no-op in a production build. `package.json` maps it to an empty build under the `production` export condition (Vite and webpack set that in production mode), so `bus.use(devPlugin({ app }))` can stay without a guard: it touches nothing and costs a few bytes.
47
+ `nanoeffects/dev` is a no-op in a production build. `package.json` maps it to an empty build under the `production` export condition (Vite and webpack set that in production mode), so `bus.use(devPlugin())` can stay without a guard: it touches nothing and costs a few bytes.
47
48
 
48
49
  If you want even the call gone, guard it (`if (import.meta.env.DEV)` in Vite). An app that does not import the entry does not carry it.
@@ -73,16 +73,26 @@ The store (`$items`) is not here. Keep it in Effector and update it from the `fo
73
73
 
74
74
  Without Effector, something must hold `$items`. A Zustand store does it: `create` replaces `createStore`, and `setState` replaces `.on(searchFx.doneData, …)`. The handler writes the result to the store directly, so the `found` event is not needed. A component reads the store with a selector, as `useUnit($items)` did.
75
75
 
76
- ```jsx
77
- // search-zustand.jsx
78
- import { create } from "zustand";
76
+ ```js
77
+ // bus.js
79
78
  import { createBus } from "nanoeffects";
80
- import { debounce, latest } from "nanoeffects/policies";
79
+
80
+ export const bus = createBus(); // the bus: only the bus
81
+ ```
82
+
83
+ ```js
84
+ // search-store.js
85
+ import { create } from "zustand";
81
86
 
82
87
  // create — Zustand: the store replaces $items
83
- const useSearchStore = create(() => ({ items: [] }));
88
+ export const useSearchStore = create(() => ({ items: [] }));
89
+ ```
84
90
 
85
- const bus = createBus(); // the bus: events and handlers
91
+ ```js
92
+ // search-handlers.js
93
+ import { debounce, latest } from "nanoeffects/policies";
94
+ import { bus } from "./bus";
95
+ import { useSearchStore } from "./search-store";
86
96
 
87
97
  // latest — a newer query aborts the request in flight; debounce — wait 300 ms of quiet
88
98
  const search = latest(async (query, { signal }) => {
@@ -91,6 +101,12 @@ const search = latest(async (query, { signal }) => {
91
101
  });
92
102
 
93
103
  bus.on("query-changed", debounce(300, search));
104
+ ```
105
+
106
+ ```jsx
107
+ // Search.jsx
108
+ import { bus } from "./bus";
109
+ import { useSearchStore } from "./search-store";
94
110
 
95
111
  export function Search() {
96
112
  const items = useSearchStore((state) => state.items); // Zustand: a selector reads items
@@ -166,13 +182,18 @@ formSubmitted.watch((event) => {
166
182
  });
167
183
  ```
168
184
 
169
- The same form with nanoeffects. The values live in React state: nanoeffects holds none, and any store of [Stores](stores.md) works the same way. The effect becomes a handler of the submit event. The values travel in the event, so no `sample` and no `source` are needed. First the bus, in its own file:
185
+ The same form with nanoeffects. The values live in React state: nanoeffects holds none, and any store of [Stores](stores.md) works the same way. The effect becomes a handler of the submit event. The values travel in the event, so no `sample` and no `source` are needed. First the bus and the handler, each in its own file:
170
186
 
171
187
  ```js
172
- // form-bus.js
188
+ // bus.js
173
189
  import { createBus } from "nanoeffects";
174
190
 
175
- export const bus = createBus(); // the bus: events and their handlers
191
+ export const bus = createBus(); // the bus: only the bus
192
+ ```
193
+
194
+ ```js
195
+ // form-handlers.js
196
+ import { bus } from "./bus";
176
197
 
177
198
  // bus.on — the job of sendFormFx: runs when the form is submitted
178
199
  bus.on("form/submitted", (values) => {
@@ -185,7 +206,8 @@ Then the form. `useState` does the work of `$form`, `fieldUpdate` and `prepend`;
185
206
  ```jsx
186
207
  // App.jsx
187
208
  import { useState } from "react";
188
- import { bus } from "./form-bus"; // the bus of the previous snippet
209
+ import { bus } from "./bus"; // the bus of the previous snippet
210
+ import "./form-handlers"; // registers the handler; the app does this once, when it starts
189
211
 
190
212
  function Field({ name, type, label, value, onChange }) {
191
213
  return (
@@ -255,16 +277,27 @@ Retrying a failed network request, and cancelling when the form closes, are in [
255
277
 
256
278
  Keep the Effector stores, and run the effects on the bus. A store calls the bus through `bus.emitter`, and the handler sends the result back as an event that the store listens to.
257
279
 
258
- <!-- docs-check: skip - needs effector, which the project does not depend on -->
259
280
  ```js
260
- import { createEvent, createStore } from "effector";
281
+ // bus.js
261
282
  import { createBus } from "nanoeffects";
262
- import { createAction, emitterPlugin } from "nanoeffects/actions";
263
- import { latest } from "nanoeffects/policies";
283
+ import { emitterPlugin } from "nanoeffects/actions";
264
284
 
265
- const bus = createBus().use(emitterPlugin()); // adds bus.emitter
285
+ export const bus = createBus().use(emitterPlugin()); // adds bus.emitter
286
+ ```
266
287
 
267
- const queryChanged = createAction("query/changed"); // a plain action creator
288
+ ```js
289
+ // search.js
290
+ import { createAction } from "nanoeffects/actions";
291
+
292
+ export const queryChanged = createAction("query/changed"); // a plain action creator
293
+ ```
294
+
295
+ <!-- docs-check: skip - needs effector, which the project does not depend on -->
296
+ ```js
297
+ import { createEvent, createStore } from "effector";
298
+ import { latest } from "nanoeffects/policies";
299
+ import { bus } from "./bus";
300
+ import { queryChanged } from "./search";
268
301
 
269
302
  const found = createEvent(); // Effector: the result comes back as an event
270
303
  const $items = createStore([]).on(found, (_, items) => items);
@@ -90,16 +90,27 @@ Keep RxJS where a stream is how you think, and let events cross to the bus in ei
90
90
 
91
91
  **RxJS to bus.** `bus.emitter(action)` returns a callback that emits the action, so it is the argument of `subscribe` ([Stores](stores.md) has the plugin).
92
92
 
93
- <!-- docs-check: skip - needs rxjs, which the project does not depend on -->
94
93
  ```js
95
- import { combineLatest } from "rxjs";
94
+ // bus.js
96
95
  import { createBus } from "nanoeffects";
97
- import { createAction, emitterPlugin } from "nanoeffects/actions";
98
- import { latest } from "nanoeffects/policies";
96
+ import { emitterPlugin } from "nanoeffects/actions";
97
+
98
+ export const bus = createBus().use(emitterPlugin()); // adds bus.emitter
99
+ ```
100
+
101
+ ```js
102
+ // filters.js
103
+ import { createAction } from "nanoeffects/actions";
99
104
 
100
- const bus = createBus().use(emitterPlugin()); // adds bus.emitter
105
+ export const filtersChanged = createAction("filters/changed"); // a plain action creator
106
+ ```
101
107
 
102
- const filtersChanged = createAction("filters/changed"); // a plain action creator
108
+ <!-- docs-check: skip - needs rxjs, which the project does not depend on -->
109
+ ```js
110
+ import { combineLatest } from "rxjs";
111
+ import { latest } from "nanoeffects/policies";
112
+ import { bus } from "./bus";
113
+ import { filtersChanged } from "./filters";
103
114
 
104
115
  // RxJS: combine two streams into one value; nanoeffects does not do that
105
116
  const subscription = combineLatest([query$, category$]).subscribe(
package/docs/oop.md ADDED
@@ -0,0 +1,286 @@
1
+ # Use the bus from a class
2
+
3
+ Use this page when **your domain logic lives in classes**: a service, a store or a controller that needs the bus inside its methods. A class made with `extendBus` has `on`, `emit` and the other methods of the bus, and remembers what each instance subscribed to, so `dispose()` ends it all.
4
+
5
+ If your logic is plain functions, stay with [modules](actions.md#mount-domains-with-modules): a module is the same idea without a class.
6
+
7
+ ## The problem without it
8
+
9
+ A class that listens to the bus keeps a reference to it, and keeps every unsubscribe function in a list to call when the object goes away. Forget one and the old object keeps handling events. `extendBus` does both for you.
10
+
11
+ ## Give a class the methods of a bus
12
+
13
+ `extendBus(bus, Base)` returns a subclass of `Base`. Its instances have the methods of the bus, and the arguments of `new` go to the constructor of `Base`.
14
+
15
+ ```js
16
+ // bus.js
17
+ import { createBus } from "nanoeffects";
18
+
19
+ // createBus — the bus that the services of the app share
20
+ export const bus = createBus();
21
+ ```
22
+
23
+ ```js
24
+ // search.js
25
+ import { createAction } from "nanoeffects/actions";
26
+
27
+ // createAction — the events of the search domain
28
+ export const queryChanged = createAction("search/query-changed");
29
+ export const resultsLoaded = createAction("search/results-loaded");
30
+ ```
31
+
32
+ ```js
33
+ // search-service.js
34
+ import { extendBus } from "nanoeffects/oop";
35
+ import { bus } from "./bus";
36
+ import { queryChanged, resultsLoaded } from "./search";
37
+
38
+ class SearchServiceBase {
39
+ constructor(api) {
40
+ this.api = api;
41
+ // this.on — a subscription of this instance; dispose() removes it
42
+ this.on(queryChanged, (query, ctx) => this.search(query, ctx)); // an arrow keeps this
43
+ }
44
+
45
+ async search(query, { signal, emit }) {
46
+ const items = await this.api.search(query, { signal });
47
+ emit(resultsLoaded(items));
48
+ }
49
+ }
50
+
51
+ // extendBus — a subclass whose instances have on, once, off, emit and dispose
52
+ export const SearchService = extendBus(bus, SearchServiceBase);
53
+ ```
54
+
55
+ ```js
56
+ import { queryChanged } from "./search";
57
+ import { SearchService } from "./search-service";
58
+
59
+ const service = new SearchService(api); // the arguments go to SearchServiceBase
60
+ service.emit(queryChanged("nano")); // the same bus as bus.emit
61
+ service.dispose(); // its subscriptions are gone
62
+ ```
63
+
64
+ What you get:
65
+
66
+ - The class keeps the name of `Base`, and its instances are instances of `Base`.
67
+ - `on`, `once`, `off` and `emit` act on the bus. They can be destructured: `const { emit } = service`.
68
+ - The other methods of the bus, such as `emitter` from [`emitterPlugin`](plugins.md), are there too. Only the plugins used **before** `extendBus` count: the names are taken when it runs.
69
+ - `bus` is the bus, and `Class.bus` is the same one.
70
+ - `this.on` works in the constructor of `Base`. The methods exist on the prototype of the subclass, which is the prototype of the instance already.
71
+
72
+ ## Let the class make its bus
73
+
74
+ Leave the bus out and the class gets its own, shared by all of its instances.
75
+
76
+ ```js
77
+ // notifier.js
78
+ import { extendBus } from "nanoeffects/oop";
79
+
80
+ class NotifierBase {}
81
+
82
+ // extendBus without a bus — a new bus for this class; two classes have two buses
83
+ export const Notifier = extendBus(NotifierBase);
84
+
85
+ const first = new Notifier();
86
+ const second = new Notifier();
87
+ second.on("notified", (message) => console.log(message));
88
+ first.emit("notified", "hello"); // the instances share Notifier.bus
89
+ ```
90
+
91
+ Pass a bus when you need plugins (`contextPlugin`, `scopePlugin`) or when several classes talk to each other.
92
+
93
+ ## End the subscriptions with `dispose`
94
+
95
+ `dispose()` removes every subscription made through `this.on` and `this.once` of that instance, and nothing else. It is safe to call twice. `instance[Symbol.dispose]()` does the same, so `using service = new SearchService(api)` works where the runtime supports it.
96
+
97
+ ```js
98
+ // dispose.js
99
+ import { createBus } from "nanoeffects";
100
+ import { extendBus } from "nanoeffects/oop";
101
+
102
+ const bus = createBus();
103
+ const Service = extendBus(bus, class {});
104
+
105
+ const service = new Service();
106
+ const stop = service.on("ping", () => console.log("service heard it"));
107
+ bus.on("ping", () => console.log("the bus heard it")); // not a subscription of the service
108
+
109
+ service.dispose();
110
+ bus.emit("ping"); // only "the bus heard it"
111
+ stop(); // the function on returned still works, and does nothing now
112
+ ```
113
+
114
+ A subscription that you removed yourself (the function `on` returned, `this.off`, or a `once` that fired) is forgotten, so the instance holds nothing for it.
115
+
116
+ ## Keep a method of your own
117
+
118
+ The class wins any clash of names. If `Base` has `emit`, `dispose`, `on` or `bus`, yours stays and the bus method is not added. A `Base` with its own `dispose` would never end the subscriptions, so call `disposeBus(this)` from there.
119
+
120
+ ```js
121
+ // cache.js
122
+ import { createBus } from "nanoeffects";
123
+ import { disposeBus, extendBus } from "nanoeffects/oop";
124
+
125
+ const bus = createBus();
126
+
127
+ class CacheBase {
128
+ dispose() {
129
+ this.items.clear(); // your own cleanup
130
+ disposeBus(this); // disposeBus — ends the subscriptions of this instance
131
+ }
132
+
133
+ items = new Map();
134
+ }
135
+
136
+ export const Cache = extendBus(bus, CacheBase);
137
+ ```
138
+
139
+ `disposeBus` does nothing for a value that is not an instance of such a class.
140
+
141
+ ## Subscribe a method with `@On` and `@Once`
142
+
143
+ A decorator turns a method into a handler of an event for each instance, with `this` bound. You write no `this.on` in the constructor, and `dispose()` ends the subscription too.
144
+
145
+ The bus and the events are the same as above, in TypeScript:
146
+
147
+ ```ts
148
+ // bus.ts
149
+ import { createBus } from "nanoeffects";
150
+
151
+ export const bus = createBus();
152
+ ```
153
+
154
+ ```ts
155
+ // search.ts
156
+ import { createAction } from "nanoeffects/actions";
157
+
158
+ export const queryChanged = createAction<string>("search/query-changed");
159
+ export const resultsLoaded = createAction<string[]>("search/results-loaded");
160
+ ```
161
+
162
+ ```ts
163
+ // search-service.ts
164
+ import { latest } from "nanoeffects/policies";
165
+ import { extendBus, On, Once } from "nanoeffects/oop";
166
+ import { bus } from "./bus";
167
+ import { queryChanged, resultsLoaded } from "./search";
168
+
169
+ class SearchServiceBase {
170
+ // On — this method handles queryChanged for each instance, this is the instance;
171
+ // latest — each new query aborts the one before it
172
+ @On(queryChanged, latest)
173
+ async search(query: string, { signal, emit }: { signal: AbortSignal; emit: (event: unknown) => void }) {
174
+ const items = await api.search(query, { signal });
175
+ emit(resultsLoaded(items));
176
+ }
177
+
178
+ // Once — runs for the first event only
179
+ @Once("search/ready")
180
+ ready() {
181
+ console.log("first ready");
182
+ }
183
+ }
184
+
185
+ export const SearchService = extendBus(bus, SearchServiceBase);
186
+ ```
187
+
188
+ Things to know:
189
+
190
+ - The event is a name, an action creator or a command, as for `bus.on`. For a creator or a command the payload of the method is checked against it.
191
+ - The second argument, `wrap`, takes the bound handler and returns the one to subscribe: `latest`, or `(handler) => debounce(300, handler)`. A policy needs it: `latest(this.search)` wraps the function without `this`, and the bound handler is what `wrap` gets.
192
+ - The subscriptions are made right after the constructor of `Base`. An event that is emitted inside that constructor does not reach them.
193
+ - A subclass inherits them. A method that a subclass overrides is subscribed only if the override is decorated.
194
+ - On a class that `extendBus` did not make, a decorator does nothing.
195
+ - Both the decorators of the language and `experimentalDecorators` work. Your compiler has to support the one you use: TypeScript 5 or newer for the first, and the `experimentalDecorators` option for the second.
196
+
197
+ ## Decorate the class with `@WithBus`
198
+
199
+ `@WithBus(bus)` does what `extendBus(bus, Base)` does, as a class decorator. `@WithBus()` makes a bus for the class.
200
+
201
+ <!-- docs-check: continue -->
202
+
203
+ ```ts
204
+ // search-service.ts
205
+ import { type BusMethods, On, WithBus } from "nanoeffects/oop";
206
+ import { bus } from "./bus";
207
+ import { queryChanged } from "./search";
208
+
209
+ // TypeScript does not change the type of a decorated class, so say what it gets;
210
+ // checker only: at run time WithBus already adds the methods
211
+ interface SearchService extends BusMethods<typeof bus> {}
212
+
213
+ // WithBus — replaces the class by extendBus(bus, SearchService)
214
+ @WithBus(bus)
215
+ class SearchService {
216
+ @On(queryChanged)
217
+ search(query: string) {
218
+ console.log(query);
219
+ }
220
+ }
221
+
222
+ export { SearchService };
223
+ ```
224
+
225
+ Prefer `extendBus(bus, Base)` when you can: its types come from the call and need no `interface`.
226
+
227
+ ## Pass a method by hand
228
+
229
+ A handler given to `this.on` is called as the bus calls it, with no `this`. A method passed bare loses `this`, as in plain JavaScript:
230
+
231
+ ```js
232
+ // handlers.js
233
+ import { createBus } from "nanoeffects";
234
+ import { extendBus } from "nanoeffects/oop";
235
+
236
+ class BaseWithHandler {
237
+ name = "handler";
238
+
239
+ handle() {
240
+ console.log(this?.name);
241
+ }
242
+
243
+ listen() {
244
+ this.on("ping", this.handle); // this is lost: prints undefined
245
+ this.on("ping", () => this.handle()); // an arrow keeps it
246
+ }
247
+ }
248
+
249
+ export const Listener = extendBus(createBus(), BaseWithHandler);
250
+ ```
251
+
252
+ Use an arrow or a decorated method. The library does not bind `this` for you: a policy such as `latest(this.handle)` wraps the function, so binding would work in half of the cases.
253
+
254
+ ## Type the instances (optional)
255
+
256
+ `extendBus` returns a class that takes the arguments of `Base`, and its instances are `Base` plus `BusMethods<typeof bus>`: the function members of the bus (`on`, `emit`, and those of plugins used before) with `dispose` and `bus`. A member of `Base` with the same name keeps its own type.
257
+
258
+ ```ts
259
+ // service.ts
260
+ import { createBus } from "nanoeffects";
261
+ import { extendBus } from "nanoeffects/oop";
262
+
263
+ type Events = { "order/placed": { id: string } };
264
+
265
+ // Events — checker only: the payloads of the bus
266
+ const bus = createBus<Events>();
267
+
268
+ class OrderServiceBase {
269
+ name: string;
270
+
271
+ constructor(name: string) {
272
+ this.name = name;
273
+ }
274
+ }
275
+
276
+ export const OrderService = extendBus(bus, OrderServiceBase);
277
+
278
+ const service = new OrderService("main"); // the constructor of OrderServiceBase
279
+ service.emit("order/placed", { id: "o1" }); // checked against Events
280
+ ```
281
+
282
+ ## What is not done
283
+
284
+ - `this` is not bound in a handler that you pass by hand (see above).
285
+ - The methods of a plugin used after `extendBus` are not on the class. Use the plugins first, then `extendBus`.
286
+ - One bus for each instance, mixing the methods into an object that exists, and decorators for fields or parameters are not part of this entry.
package/docs/package.md CHANGED
@@ -8,6 +8,8 @@ Imports are split so you only load what you use. `createBus` stays small; the re
8
8
  | `nanoeffects/policies` | `latest`, `leading`, `debounce`, `throttle`, `queue` |
9
9
  | `nanoeffects/effects` | `retry`, `timeout`, `poll`, `delay`, `take`, `all`, `allSettled`, `race`, `effectsPlugin` |
10
10
  | `nanoeffects/actions` | `createAction`, `createCommand`, `createJob`, `createModule`, `modulePlugin`, `commandsPlugin` |
11
+ | `nanoeffects/match` | `matchPlugin`: `on`, `once` and `off` that take a function which picks the events |
12
+ | `nanoeffects/oop` | `extendBus`, `WithBus`, `On`, `Once`, `disposeBus`: the methods of a bus on a class, with the subscriptions of each instance ended by `dispose()` |
11
13
  | `nanoeffects/scope` | `scopePlugin`, `effect`: fields for one command, action, job, module or `emit` (the types `Scope`, `Effect`) |
12
14
  | `nanoeffects/redux` | `createEffectsMiddleware` |
13
15
  | `nanoeffects/observable` | `createObserve` |