nanoeffects 0.10.0 → 0.11.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 (63) hide show
  1. package/dist/{action-creator-BrZF6hXc.d.ts → action-creator-9e8jesRa.d.ts} +28 -12
  2. package/dist/actions.d.ts +12 -5
  3. package/dist/actions.js +1 -1
  4. package/dist/bus-Cdw5ajKF.js +1 -0
  5. package/dist/context-CJGW6OWj.js +1 -0
  6. package/dist/{context-plugin--HkNN1ha.d.ts → context-plugin-Xibukkbj.d.ts} +1 -1
  7. package/dist/{delay-CIHnOh_L.js → delay-BnBdGPh7.js} +1 -1
  8. package/dist/dev.d.ts +2 -2
  9. package/dist/effects.d.ts +2 -2
  10. package/dist/effects.js +1 -1
  11. package/dist/index.d.ts +2 -2
  12. package/dist/index.js +1 -1
  13. package/dist/match.d.ts +1 -1
  14. package/dist/match.js +1 -1
  15. package/dist/{module-DqKegXHt.d.ts → module-BlkU3i6B.d.ts} +3 -3
  16. package/dist/notrace/{action-creator-DHAEgwuh.d.ts → action-creator-DQTwMBwP.d.ts} +27 -11
  17. package/dist/notrace/actions.d.ts +12 -5
  18. package/dist/notrace/actions.js +1 -1
  19. package/dist/notrace/bus-G2AdGObY.js +1 -0
  20. package/dist/notrace/{context-plugin-BapQkGwQ.d.ts → context-plugin-DlZCkcX9.d.ts} +1 -1
  21. package/dist/notrace/effects.d.ts +2 -2
  22. package/dist/notrace/index.d.ts +2 -2
  23. package/dist/notrace/index.js +1 -1
  24. package/dist/notrace/origin-key-BbWN3gmN.js +1 -0
  25. package/dist/notrace/origin-key-CxK0SkeG.d.ts +10 -0
  26. package/dist/notrace/{plugin-Cxadz6uU.d.ts → plugin-DOYHG78z.d.ts} +2 -2
  27. package/dist/notrace/policies.d.ts +1 -1
  28. package/dist/notrace/redux.d.ts +4 -3
  29. package/dist/notrace/redux.js +1 -1
  30. package/dist/observable.d.ts +1 -1
  31. package/dist/oop.d.ts +13 -7
  32. package/dist/oop.js +1 -1
  33. package/dist/origin-key-BbWN3gmN.js +1 -0
  34. package/dist/origin-key-CxK0SkeG.d.ts +10 -0
  35. package/dist/{plugin-DkXCvsmB.d.ts → plugin-DHkamZdH.d.ts} +2 -2
  36. package/dist/policies.d.ts +2 -2
  37. package/dist/policies.js +1 -1
  38. package/dist/react.d.ts +15 -8
  39. package/dist/react.js +1 -1
  40. package/dist/redux.d.ts +4 -3
  41. package/dist/redux.js +1 -1
  42. package/dist/scope.d.ts +2 -2
  43. package/dist/scope.js +1 -1
  44. package/dist/signal.d.ts +1 -1
  45. package/dist/signal.js +1 -1
  46. package/dist/trace.d.ts +30 -1
  47. package/dist/trace.js +1 -1
  48. package/dist/{types-KavbvHix.d.ts → types-ByPzv7tw.d.ts} +2 -2
  49. package/dist/{with-policy-DBV9dh2F.js → with-policy-CW50Edgk.js} +1 -1
  50. package/dist/{with-policy-CqUS-VWW.d.ts → with-policy-DpCvSZRk.d.ts} +1 -1
  51. package/docs/oop.md +2 -0
  52. package/docs/package.md +1 -1
  53. package/docs/plugins.md +16 -1
  54. package/docs/scope.md +1 -1
  55. package/docs/stores.md +5 -1
  56. package/docs/tracing.md +121 -1
  57. package/llms-full.txt +147 -6
  58. package/llms.txt +1 -1
  59. package/package.json +3 -3
  60. package/dist/bus-CkTHUAvq.js +0 -1
  61. package/dist/context-COgyNlrC.js +0 -1
  62. package/dist/notrace/bus-BmCTo8BG.js +0 -1
  63. package/dist/onAbort-BgMfspK4.js +0 -1
package/llms-full.txt CHANGED
@@ -9,7 +9,7 @@ Rules that generated code often gets wrong:
9
9
  - A handler gets the payload and a task context: `(payload, ctx)`. The context has `signal`, `emit`, `on`, `run`. Pass `ctx.signal` to `fetch`.
10
10
  - Effects take `ctx` as the first argument: `retry(ctx, fn, options)`, `timeout(ctx, ms, fn)`, `take(ctx, "event")`.
11
11
  - Policies wrap a handler: `bus.on("search", latest(async (query, ctx) => { ... }))`.
12
- - Each part is imported from its own path: `nanoeffects` (`createBus`), `nanoeffects/policies`, `nanoeffects/effects`, `nanoeffects/actions`, `nanoeffects/redux`, `nanoeffects/observable`, `nanoeffects/react` (`reactPlugin`, adds `bus.useEmitter`; `usePolicy`; needs React), `nanoeffects/trace`, `nanoeffects/dev`.
12
+ - Each part is imported from its own path: `nanoeffects` (`createBus`), `nanoeffects/policies`, `nanoeffects/effects`, `nanoeffects/actions`, `nanoeffects/redux`, `nanoeffects/observable`, `nanoeffects/react` (`reactPlugin`, adds `bus.useEmitter`; `usePolicy`; needs React), `nanoeffects/trace` (`createTracer`, loggers, `tracePlugin`), `nanoeffects/dev`.
13
13
  - `bus.emit(command(payload))` runs the command's handler and returns its result. Plain events return nothing.
14
14
 
15
15
  ---
@@ -566,7 +566,7 @@ Imports are split so you only load what you use. `createBus` stays small; the re
566
566
  | `nanoeffects/observable` | `createObserve` |
567
567
  | `nanoeffects/react` | `reactPlugin`: adds the `useEmitter` hook to a bus (needs React 18 or newer) |
568
568
  | `nanoeffects/dev` | `devPlugin` (no-op in production) |
569
- | `nanoeffects/trace` | `createTracer` and the loggers |
569
+ | `nanoeffects/trace` | `createTracer`, the loggers and `tracePlugin` (names for the trace) |
570
570
 
571
571
  The `...Plugin` names above are used with `bus.use`. [Plugins](plugins.md) lists all of them, what each returns, and the order to use them in.
572
572
 
@@ -680,6 +680,7 @@ Add one of these when you meet its need. None of them is required.
680
680
  | [`signalPlugin`](#tie-an-emit-to-an-outside-signal-signalplugin) | `emit(call, { signal })` that aborts its tasks when an outside signal aborts. | `nanoeffects/signal` | The same bus, typed with the new `emit` |
681
681
  | [`matchPlugin`](#listen-to-a-group-of-events-matchplugin) | `on` that listens to a group of events which a function picks. | `nanoeffects/match` | The same bus, typed with the new overloads |
682
682
  | [`emitterPlugin`](#hand-the-bus-to-a-state-manager-emitterplugin) | A callback that emits an action, to give to a state manager. | `nanoeffects/actions` | The same bus, with `emitter` |
683
+ | [`tracePlugin`](#name-the-origin-and-the-flow-of-a-trace-traceplugin) | `traceId` and `traceGroupId` for a trace: the root of an emitter, a flow, a named listener. | `nanoeffects/trace` | The same bus |
683
684
  | [`reactPlugin`](#tell-the-bus-when-a-react-value-changes-reactplugin) | A React hook that emits when a value of a component changes. | `nanoeffects/react` | The same bus, with `useEmitter` |
684
685
  | [`devPlugin`](#find-leaks-while-you-develop-devplugin) | Warnings about listeners that pile up, and messages about modules, while you develop. | `nanoeffects/dev` | A function that disconnects it |
685
686
 
@@ -723,6 +724,20 @@ bus.emit(getUser("1"), { signal: controller.signal }); // runs the command
723
724
  controller.abort(); // ctx.signal of the handler aborts with it
724
725
  ```
725
726
 
727
+ ### Name the origin and the flow of a trace: `tracePlugin`
728
+
729
+ With a tracer on the bus, the plugin lets a trace say which subscription began a chain (`traceId` of `useEmitter` and `bus.emitter`), follow one flow by a `traceGroupId`, and show which listener ran (`bus.on(event, handler, { traceId })`). Without the plugin the options are ignored. More in [Tracing](tracing.md#show-which-subscription-began-a-chain).
730
+
731
+ ```js
732
+ import { createBus } from "nanoeffects";
733
+ import { consoleLogger, createTracer, tracePlugin } from "nanoeffects/trace";
734
+
735
+ // tracePlugin — names the roots, groups and listeners of the trace
736
+ const bus = createBus({ trace: createTracer(consoleLogger()) }).use(tracePlugin());
737
+
738
+ bus.on("name/changed", saveName, { traceId: "saveNotifier" }); // a listener you can find in the log
739
+ ```
740
+
726
741
  ### Listen to a group of events: `matchPlugin`
727
742
 
728
743
  `on`, `once` and `off` take a function that picks the events, such as every `user/*` event. A type guard narrows the payload. The subscription listens to every event, so for a few known events `on(creator, handler)` is cheaper. More in the [Guide](guide.md#pick-events-with-a-function).
@@ -759,7 +774,7 @@ $name.listen(bus.emitter(nameChanged)); // every change of $name emits nameChang
759
774
 
760
775
  ### Tell the bus when a React value changes: `reactPlugin`
761
776
 
762
- `useEmitter(event, value)` emits after a render commits with a new value. It does not emit on mount, and not twice under StrictMode. It needs React 18 or newer. More in [Stores](stores.md#react-sharing-a-value-across-components).
777
+ `useEmitter(event, value, options?)` emits after a render commits with a new value. It does not emit on mount, and not twice under StrictMode. The options are `{ equals, traceId, traceGroupId }`; the last two name the emit in the [trace](tracing.md#show-which-subscription-began-a-chain). It needs React 18 or newer. More in [Stores](stores.md#react-sharing-a-value-across-components).
763
778
 
764
779
  ```jsx
765
780
  import { useState } from "react";
@@ -2126,6 +2141,10 @@ String event names (`"user/requested"`) work the same. Use your usual RTK action
2126
2141
 
2127
2142
  The only option is `filter`, which keeps rejected actions away from the bus. Options of the bus (`onError`, `context`, `trace`) go to `createBus`. Use one bus for one store. Values that are not plain actions (thunks) go through untouched. Nothing here depends on the `redux` package at runtime.
2128
2143
 
2144
+ ### Show which dispatch began a chain
2145
+
2146
+ With a tracer and `tracePlugin` on the bus, each dispatched action reaches the bus from a root task of the trace. Name it with `traceId`, and put the flow in a group with `traceGroupId`: `createEffectsMiddleware(bus, { traceId: "store", traceGroupId: "checkout" })`. Without a `traceId` the root has the type of the action. Without the plugin the options are ignored. More in [Tracing](tracing.md#show-which-subscription-began-a-chain).
2147
+
2129
2148
  ### Type `ctx.store` (optional)
2130
2149
 
2131
2150
  Only if you want TypeScript to know `store` on handlers. **Skip this in JavaScript** — the middleware already puts `store` on the task at runtime. These lines do not connect the store across the app.
@@ -2504,7 +2523,7 @@ export function Results() {
2504
2523
  Two limits to know:
2505
2524
 
2506
2525
  - **All consumers re-render** on any change of the context value. Split it into two contexts (`query` and `items`) if that is slow.
2507
- - **A new object counts as a change.** For a value that is rebuilt with the same content, pass a third argument that says when two values are the same: `useEmitter(profileChanged, profile, (previous, next) => previous.id === next.id)`.
2526
+ - **A new object counts as a change.** For a value that is rebuilt with the same content, pass `equals` in the options, the third argument, to say when two values are the same: `useEmitter(profileChanged, profile, { equals: (previous, next) => previous.id === next.id })`. The same object takes `traceId` and `traceGroupId`, which name the subscription and the flow in the [trace](tracing.md#show-which-subscription-began-a-chain).
2508
2527
 
2509
2528
  `useEmitter` emits after the render, not at the moment of `setQuery`. To emit on every call, even with the same value, call an emitter from the event handler (`bus.emitter(action)`, see [Zustand](#zustand)) instead.
2510
2529
 
@@ -3308,7 +3327,7 @@ When several places set the same field, the strongest one wins:
3308
3327
  | 3 | the scope of the module that owns the handler |
3309
3328
  | 4 (weakest) | the bus: `createBus({ context })`, `contextPlugin`, `effectsPlugin` |
3310
3329
 
3311
- The fields of the library (`signal`, `abort`, `emit`, `on`, `off`, `run`, `type`, `payload`) are never replaced. A child task (`ctx.run`, an attempt of `retry`) has the fields of its parent.
3330
+ The fields of the library (`signal`, `abort`, `emit`, `on`, `off`, `run`, `type`, `payload`) are never replaced. The name `traceGroupId` is reserved: the tracer reads it, and it is not put on `ctx` ([Follow one flow](tracing.md#follow-one-flow-with-a-tracegroupid)). A child task (`ctx.run`, an attempt of `retry`) has the fields of its parent.
3312
3331
 
3313
3332
  ## Keep a generic effect generic
3314
3333
 
@@ -3583,6 +3602,8 @@ Things to know:
3583
3602
  - On a class that `extendBus` did not make, a decorator does nothing.
3584
3603
  - 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.
3585
3604
 
3605
+ Name a method for the [trace](tracing.md#name-a-listener) with `{ traceId }`, as the second argument or, after a wrapper, the third: `@On(queryChanged, { traceId: "searcher" })` or `@On(queryChanged, latest, { traceId: "searcher" })`. It needs `tracePlugin` on the bus and is ignored without it.
3606
+
3586
3607
  ## Decorate the class with `@WithBus`
3587
3608
 
3588
3609
  `@WithBus(bus)` does what `extendBus(bus, Base)` does, as a class decorator. `@WithBus()` makes a bus for the class.
@@ -4540,12 +4561,14 @@ Each `TraceEvent` has:
4540
4561
  | Field | Meaning |
4541
4562
  | ----- | ------- |
4542
4563
  | `id` | Unique task id within the bus |
4543
- | `parent` | Id of the task that started this one (absent for handler tasks) |
4564
+ | `parentId` | Id of the task that started this one (absent for handler tasks) |
4565
+ | `rootId` | Id of the root task of the chain; absent on the root itself, and it is the same through a listener that reports nothing |
4544
4566
  | `type` | Event type the task works on |
4545
4567
  | `effect` | `latest`, `debounce`, `throttle`, `leading`, `run`, `all`, `race`, … |
4546
4568
  | `phase` | `start`, `done`, `error`, `cancel`, or `drop` |
4547
4569
  | `payload` | Event payload |
4548
4570
  | `error` | Thrown value, only for `error` |
4571
+ | `traceGroupId` | The flow of the task, when it or a task above has one |
4549
4572
 
4550
4573
  Phases:
4551
4574
 
@@ -4570,6 +4593,124 @@ bus.on("load", async (id, ctx) => {
4570
4593
  });
4571
4594
  ```
4572
4595
 
4596
+ ## Show which subscription began a chain
4597
+
4598
+ **Problem.** `useEmitter` and `bus.emitter` put an event on the bus from outside any task, such as a render or the callback of a store. In the trace that event has no sign of where it came from. With many such subscriptions it is hard to tell which one started a chain of commands and retries.
4599
+
4600
+ **When.** The bus has a tracer and the project has several `useEmitter` or `bus.emitter` calls. The names come from `tracePlugin`: use it on the bus, or the `traceId` is ignored.
4601
+
4602
+ Give each one a `traceId`. When the bus has a tracer, the emit is made from a root task with that `traceId` as its `type` and `run` as its effect. What the event starts is below it. Without a tracer nothing changes.
4603
+
4604
+ ```js
4605
+ import { createBus } from "nanoeffects";
4606
+ import { createAction, emitterPlugin } from "nanoeffects/actions";
4607
+ import { consoleLogger, createTracer, tracePlugin } from "nanoeffects/trace";
4608
+
4609
+ // createTracer: reports every task phase to the console
4610
+ const bus = createBus({ trace: createTracer(consoleLogger()) })
4611
+ .use(tracePlugin()) // tracePlugin: makes the root task that traceId names
4612
+ .use(emitterPlugin());
4613
+
4614
+ const cartChanged = createAction("cart/changed");
4615
+
4616
+ // emitter: a callback for a store; traceId names it in the trace
4617
+ const emitCartChanged = bus.emitter(cartChanged, { traceId: "cartStore" });
4618
+ ```
4619
+
4620
+ In a component, the same option goes in the options of the hook: `useEmitter(nameChanged, name, { traceId: "Profile" })`. In the console:
4621
+
4622
+ ```
4623
+ [nanoeffects] Profile · run start
4624
+ [nanoeffects] user/save · command start
4625
+ [nanoeffects] user/save · command done
4626
+ [nanoeffects] Profile · run done
4627
+ ```
4628
+
4629
+ A `traceId` is a string you choose and keep stable: the name of the component or of the store. Without one the root has the type of the event.
4630
+
4631
+ Two things to know:
4632
+
4633
+ - **`sample` sees the `traceId`.** The root of an emitter is a task like any other, so a `sample` function gets `{ type, payload }` with the `traceId` as the `type` and the emitted action as the `payload`. A function that matches on the type of the event, such as `event.type === "search"`, does not pick a root that has another `traceId`; match the `traceId`, or the `payload.type`.
4634
+ - **Inside a handler, emit with `ctx.emit`.** `ctx.emit` keeps the chain: what it starts is below the handler. A plain `bus.emit` inside a handler starts a new root with no parent and no `rootId`, so the trace loses the link.
4635
+
4636
+ Every event of a task below another one has `rootId`, the id of the root of the chain, also when a listener, which reports nothing, stands in between. `parentId` is the task directly above, which can be such a listener.
4637
+
4638
+ ## Follow one flow with a traceGroupId
4639
+
4640
+ **Problem.** A flow such as a checkout has several roots (a click, a timer, a store) and many branches. Parent ids give a tree, but you want to filter the log by the flow.
4641
+
4642
+ **When.** One business flow runs through several commands, and you read the log by flow.
4643
+
4644
+ Give the flow a `traceGroupId` in the scope of the command, the job or the action that starts it. Every task that it starts through `ctx.emit` or `ctx.run` has the same `traceGroupId`, and so does every trace event of those tasks. A task that declares its own `traceGroupId` uses it for itself and for what it starts.
4645
+
4646
+ ```js
4647
+ import { createBus } from "nanoeffects";
4648
+ import { createCommand } from "nanoeffects/actions";
4649
+ import { consoleLogger, createTracer, tracePlugin } from "nanoeffects/trace";
4650
+
4651
+ // tracePlugin: reads traceGroupId from the scope of a call
4652
+ const bus = createBus({ trace: createTracer(consoleLogger()) }).use(tracePlugin());
4653
+
4654
+ // the scope names the flow; traceGroupId is for the tracer, not a field of ctx
4655
+ const pay = createCommand("checkout/pay", async () => {}, {
4656
+ traceGroupId: "checkout",
4657
+ });
4658
+ ```
4659
+
4660
+ ```
4661
+ [nanoeffects] [checkout] checkout/pay · command start
4662
+ ```
4663
+
4664
+ The emitters take it too: `useEmitter(cartChanged, cart, { traceId: "Cart", traceGroupId: "checkout" })`. `traceGroupId` works without `scopePlugin`, and needs `tracePlugin`.
4665
+
4666
+ ## Name a listener
4667
+
4668
+ **Problem.** The log shows what started a chain and what it started, but a listener of an event reports nothing, so you cannot tell which of several listeners ran.
4669
+
4670
+ **When.** An event has more than one listener and you read the trace to see which one did the work.
4671
+
4672
+ Give the listener a `traceId` when you register it. The plugin makes each call of it a task with that name, and what it emits with `ctx.emit` is below it. `off` works as before. It also works in a module (`m.on(event, handler, { traceId })`) and on an instance made by `extendBus`.
4673
+
4674
+ ```js
4675
+ import { createBus } from "nanoeffects";
4676
+ import { consoleLogger, createTracer, tracePlugin } from "nanoeffects/trace";
4677
+
4678
+ const bus = createBus({ trace: createTracer(consoleLogger()) }).use(tracePlugin());
4679
+
4680
+ // traceId: the name of this listener in the trace
4681
+ bus.on("name/changed", saveName, { traceId: "saveNotifier" });
4682
+ bus.once("name/changed", (name) => console.log(name), { traceId: "auditLog" });
4683
+ ```
4684
+
4685
+ ```
4686
+ [nanoeffects] saveNotifier · run start
4687
+ [nanoeffects] user/save · command start
4688
+ [nanoeffects] saveNotifier · run done
4689
+ ```
4690
+
4691
+ ## Keep the chain: `ctx.emit`, not `bus.emit`
4692
+
4693
+ Inside a handler, emit with `ctx.emit`. It keeps the chain: what it starts is below the handler, and its events have the `rootId` of the chain. A plain `bus.emit` inside a handler starts a new root with no `parentId` and no `rootId`, so the trace loses the link. The bus cannot warn about it, because it does not know which handler is running.
4694
+
4695
+ The names work wherever an event or a listener is made:
4696
+
4697
+ | Where | How to name it |
4698
+ | ----- | -------------- |
4699
+ | `useEmitter` and `bus.emitter` | `{ traceId, traceGroupId }` in the options |
4700
+ | A Redux dispatch | `createEffectsMiddleware(bus, { traceId, traceGroupId })` |
4701
+ | A listener, `bus.on` and `bus.once` | `{ traceId }` as the third argument |
4702
+ | A listener of a module or of an instance of `extendBus` | the same third argument of its `on` and `once` |
4703
+ | A method with `@On` or `@Once` | `{ traceId }` in the decorator |
4704
+ | A command, a job or an action | `traceGroupId` in its scope |
4705
+
4706
+ ## Turn the names off
4707
+
4708
+ `tracePlugin` is optional, and none of it changes how your code runs:
4709
+
4710
+ - **Without the plugin**, or on a bus without a tracer, `traceId` and `traceGroupId` are ignored. Handlers run as they are, with the same results, errors and rejections, and `onError` sees the same errors.
4711
+ - **The types are the same** with and without the plugin, so you can use it only in development: `if (isDev) bus.use(tracePlugin())` compiles in both builds.
4712
+ - **A `traceGroupId` in a scope** is never put on `ctx`.
4713
+
4573
4714
  ## Use built-in loggers
4574
4715
 
4575
4716
  A logger is `(event) => void`. `createTracer` takes one logger or an array. A logger that throws is reported to `console.error` and never breaks the task or the other loggers.
package/llms.txt CHANGED
@@ -9,7 +9,7 @@ Rules that generated code often gets wrong:
9
9
  - A handler gets the payload and a task context: `(payload, ctx)`. The context has `signal`, `emit`, `on`, `run`. Pass `ctx.signal` to `fetch`.
10
10
  - Effects take `ctx` as the first argument: `retry(ctx, fn, options)`, `timeout(ctx, ms, fn)`, `take(ctx, "event")`.
11
11
  - Policies wrap a handler: `bus.on("search", latest(async (query, ctx) => { ... }))`.
12
- - Each part is imported from its own path: `nanoeffects` (`createBus`), `nanoeffects/policies`, `nanoeffects/effects`, `nanoeffects/actions`, `nanoeffects/redux`, `nanoeffects/observable`, `nanoeffects/react` (`reactPlugin`, adds `bus.useEmitter`; `usePolicy`; needs React), `nanoeffects/trace`, `nanoeffects/dev`.
12
+ - Each part is imported from its own path: `nanoeffects` (`createBus`), `nanoeffects/policies`, `nanoeffects/effects`, `nanoeffects/actions`, `nanoeffects/redux`, `nanoeffects/observable`, `nanoeffects/react` (`reactPlugin`, adds `bus.useEmitter`; `usePolicy`; needs React), `nanoeffects/trace` (`createTracer`, loggers, `tracePlugin`), `nanoeffects/dev`.
13
13
  - `bus.emit(command(payload))` runs the command's handler and returns its result. Plain events return nothing.
14
14
 
15
15
  ## Start here
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nanoeffects",
3
- "version": "0.10.0",
3
+ "version": "0.11.0",
4
4
  "description": "Cancel stale async work and fix race conditions in event handlers: a typed event bus where every handler is a task with an AbortSignal, plus latest, debounce, throttle, queue, retry, timeout and poll. About 1.4 kB gzip.",
5
5
  "keywords": [
6
6
  "event-bus",
@@ -201,7 +201,7 @@
201
201
  {
202
202
  "name": "actions (all)",
203
203
  "path": "dist/actions.js",
204
- "limit": "2.86 kB"
204
+ "limit": "2.87 kB"
205
205
  },
206
206
  {
207
207
  "name": "match (plugin)",
@@ -239,7 +239,7 @@
239
239
  "ignore": [
240
240
  "react"
241
241
  ],
242
- "limit": "1.15 kB"
242
+ "limit": "1.18 kB"
243
243
  },
244
244
  {
245
245
  "name": "dev",
@@ -1 +0,0 @@
1
- import{n as e}from"./onAbort-BgMfspK4.js";import{a as t,n,r}from"./context-COgyNlrC.js";import{n as i}from"./promise-CSLpzwSR.js";import{n as a,t as o}from"./event-0RIBGYqS.js";const s=`*`,c=()=>{let e={},t={},n=n=>(t[n]=void 0,e[n]??=/* @__PURE__ */ new Map,e[n]),r=(e,t)=>{let r=n(e),i=r.get(t)??0;i>1?r.set(t,i-1):t?r.delete(t):r.clear()};return{get:n=>(t[n]??=[...e[n]??[]].flatMap(([e,t])=>Array(t).fill(e)),t[n]),add:(e,t)=>{let i=n(e);return i.set(t,(i.get(t)??0)+1),()=>{r(e,t)}},remove:r,clear:()=>{for(let t of Reflect.ownKeys(e))delete e[t];for(let e of Reflect.ownKeys(t))delete t[e]}}},l=Symbol(),u=(e,t,n)=>{let r={type:t,payload:n};return Object.defineProperty(r,l,{value:e,enumerable:!1}),r},d=e=>{if(typeof e==`function`)return e;if(typeof e==`object`&&e&&l in e)return e[l]},f=(e,t,n)=>Reflect.apply(e,null,[t,n]),p=(s={})=>{let l=c(),u=(e,t)=>l.add(o(e),t),p=(e,t)=>{let n=u(e,(e,r)=>(n(),t(e,r)));return n},m=(e,t)=>{e===void 0?l.clear():l.remove(o(e),t)},h=(t,a)=>{let{onError:o}=s,{ctx:c}=n({event:a,bus:g,tracer:s.trace,parent:{ref:r()}});if(!o){t(a.payload,c);return}let l=t=>{try{o(t,a)}catch(t){e(`onError failed`,t)}};try{let e=t(a.payload,c);i(e)&&Promise.resolve(e).catch(l)}catch(e){l(e)}},g={on:u,once:p,off:m,emit:(e,i)=>{let c=o(e),u=a(e,i),p={type:c,payload:u},m=d(e),_=[...l.get(c),...l.get(`*`)];_.length===0&&!m&&s.onUnhandled?.(p);for(let e of _)h(e,p);if(m){let{ctx:e}=n({event:p,bus:g,tracer:s.trace,parent:{ref:r()}}),i=g.commands?.run??f;return t(e,`command`,()=>i(m,u,e))}},use:e=>e(g),ctx:s.context,trace:s.trace};return g};export{s as a,u as i,d as n,p as r,l as t};
@@ -1 +0,0 @@
1
- import{t as e}from"./onAbort-BgMfspK4.js";const t=t=>{let n=new AbortController;return{controller:n,unlink:e({signal:t},e=>n.abort(e))}},n=Symbol(),r=typeof __NANOEFFECTS_TRACE__>`u`||__NANOEFFECTS_TRACE__,i=/* @__PURE__ */ new WeakMap;let a;const o=()=>a,s=()=>{},c=(e,t,n,a)=>{let o=r&&i.get(e);o&&o.tracer.report(o.ref,t,n,a)},l=(e,t)=>{let n=r&&i.get(e);return n?n.tracer.settler(n.ref,t):s},u=(e,t,n)=>{let a=r&&i.get(e);return a?a.tracer.run(a.ref,t,e.signal,n):n()},d=(e,t)=>typeof e==`function`?e(t):e,f=({event:o,bus:c,tracer:l,parent:p})=>{let{controller:m,unlink:h}=t(p?.signal),{signal:g}=m,_=r&&l?{tracer:l,ref:l.task(o,p?.ref)}:void 0,v=(...e)=>{if(g.aborted&&!x[n])return;let t=c?.emit,r=a;a=_?.ref;try{return t?.(...e)}finally{a=r}},y=(...t)=>{if(g.aborted)return s;let n=c?.on,r=n?.(...t);if(!r)return s;let i=e({signal:g},r);return()=>{i(),r()}},b=async(e,...t)=>{g.throwIfAborted();let n=t[0],r=f({event:{type:o.type,payload:n},bus:c,tracer:l,parent:{signal:g,ref:_?.ref}});try{return await u(r.ctx,`run`,()=>e(n,r.ctx))}finally{r.unlink()}},x={...d(c?.ctx,o),type:o.type,payload:o.payload,signal:g,abort:e=>m.abort(e),emit:v,on:y,off:c?.off??s,run:b};return c?.addContext?.(x),_&&i.set(x,_),{ctx:x,unlink:h}},p=(e,t)=>{let n=r?i.get(e):void 0;return f({event:{type:t??e.type??``,payload:e.payload},bus:{emit:e.emit,on:e.on,off:e.off,ctx:e},tracer:n?.tracer,parent:{signal:e.signal,ref:n?.ref}})};export{u as a,p as i,f as n,c as o,o as r,n as s,l as t};
@@ -1 +0,0 @@
1
- import{a as e,l as t,n,r}from"./context-yYU3_9lq.js";import{n as i}from"./promise-CSLpzwSR.js";const a=e=>typeof e==`string`?e:e.type,o=(e,t)=>typeof e==`object`?e.payload:t,s=`*`,c=()=>{let e={},t={},n=n=>(t[n]=void 0,e[n]??=/* @__PURE__ */ new Map,e[n]),r=(e,t)=>{let r=n(e),i=r.get(t)??0;i>1?r.set(t,i-1):t?r.delete(t):r.clear()};return{get:n=>(t[n]??=[...e[n]??[]].flatMap(([e,t])=>Array(t).fill(e)),t[n]),add:(e,t)=>{let i=n(e);return i.set(t,(i.get(t)??0)+1),()=>{r(e,t)}},remove:r,clear:()=>{for(let t of Reflect.ownKeys(e))delete e[t];for(let e of Reflect.ownKeys(t))delete t[e]}}},l=Symbol(),u=(e,t,n)=>{let r={type:t,payload:n};return Object.defineProperty(r,l,{value:e,enumerable:!1}),r},d=e=>{if(typeof e==`function`)return e;if(typeof e==`object`&&e&&l in e)return e[l]},f=(e,t,n)=>Reflect.apply(e,null,[t,n]),p=(s={})=>{let l=c(),u=(e,t)=>l.add(a(e),t),p=(e,t)=>{let n=u(e,(e,r)=>(n(),t(e,r)));return n},m=(e,t)=>{e===void 0?l.clear():l.remove(a(e),t)},h=(e,a)=>{let{onError:o}=s,{ctx:c}=n({event:a,bus:g,tracer:s.trace,parent:{ref:r()}});if(!o){e(a.payload,c);return}let l=e=>{try{o(e,a)}catch(e){t(`onError failed`,e)}};try{let t=e(a.payload,c);i(t)&&Promise.resolve(t).catch(l)}catch(e){l(e)}},g={on:u,once:p,off:m,emit:(t,i)=>{let c=a(t),u=o(t,i),p={type:c,payload:u},m=d(t),_=[...l.get(c),...l.get(`*`)];_.length===0&&!m&&s.onUnhandled?.(p);for(let e of _)h(e,p);if(m){let{ctx:t}=n({event:p,bus:g,tracer:s.trace,parent:{ref:r()}}),i=g.commands?.run??f;return e(t,`command`,()=>i(m,u,t))}},use:e=>e(g),ctx:s.context,trace:s.trace};return g};export{a,s as i,p as n,u as r,l as t};
@@ -1 +0,0 @@
1
- const e=(e,t)=>{globalThis.console?.error(`[nanoeffects] ${e}`,t)},t=()=>{},n=/* @__PURE__ */ new WeakMap,r=t=>{let r=n.get(t);if(r)return r;let i=/* @__PURE__ */ new Set;return n.set(t,i),t.addEventListener(`abort`,()=>{let n=[...i];i.clear();for(let{fn:r}of n)try{r(t.reason)}catch(t){e(`abort callback failed`,t)}},{once:!0}),i},i=(e,n)=>{let{signal:i}=e;if(!i)return t;if(i.aborted)return n(i.reason),t;let a=r(i),o={fn:n};return a.add(o),()=>{a.delete(o)}};export{e as n,i as t};