nanoeffects 0.32.0 → 0.34.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.
package/README.md CHANGED
@@ -13,7 +13,15 @@ Move business logic and side effects out of React, Vue and Svelte components int
13
13
  npm install nanoeffects
14
14
  ```
15
15
 
16
- `pnpm add nanoeffects` and `yarn add nanoeffects` work the same. The package is ESM only (use `import`, not `require`), has no dependencies and includes its types. It runs on Node 18 or newer and in any bundler.
16
+ ```bash
17
+ pnpm add nanoeffects
18
+ ```
19
+
20
+ ```bash
21
+ yarn add nanoeffects
22
+ ```
23
+
24
+ The package is ESM only (use `import`, not `require`), has no dependencies and includes its types. It runs on Node 18 or newer and in any bundler.
17
25
 
18
26
  New project: `npm create nanoeffects@latest my-app` ([Docs](docs/starter.md)). Try it first: [playground](https://stackblitz.com/github/nanoeffects/nanoeffects/tree/main/examples/playground) in your browser, no install.
19
27
 
package/dist/actions.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { G as PayloadOf, H as EventMap, T as EventKey, a as FreeActionCreator, c as Scope, i as Free, n as Call, q as Task, t as ActionCreator, u as WithScope, v as Bus } from "./action-creator-DprJV-pN.js";
2
2
  import { r as Scoped, t as FieldsOfScope } from "./types-DxPZDzZG.js";
3
- import { a as createModule, c as CarryingCalls, d as actionsPlugin, f as setHandler, l as MadeHandled, n as ModuleApi, o as modulePlugin, r as ModuleContext, s as Binding, t as Module, u as ScopedHandled } from "./module-DPKjzfRk.js";
3
+ import { a as createModule, c as MadeHandled, l as ScopedHandled, n as ModuleApi, o as modulePlugin, r as ModuleContext, s as CarryingCalls, t as Module, u as actionsPlugin } from "./module-Fk4OtkZk.js";
4
4
  import { t as OriginOptions } from "./origin-key-CxK0SkeG.js";
5
5
  //#region src/actions/action.d.ts
6
6
  type Reserved = "handle" | "prepare";
@@ -194,4 +194,4 @@ export declare const createJob: <P = void, R = void, T extends string = string,
194
194
  /** Context values and `$effects` for the handler and for the listeners of the outcome; see `scopePlugin`. */
195
195
  scope?: X) => CarryingCalls<Job<P, R, T, S, F, PE, CE>, P, Promise<Awaited<R> | undefined>, FieldsOfScope<E, X>>;
196
196
  //#endregion
197
- export { type ActionCreator, type Binding, type EmitterApi, type FreeActionCreator, type Job, type Module, type ModuleApi, type ModuleContext, actionsPlugin, createModule, modulePlugin, setHandler };
197
+ export { type ActionCreator, type EmitterApi, type FreeActionCreator, type Job, type Module, type ModuleApi, type ModuleContext, actionsPlugin, createModule, modulePlugin };
package/dist/actions.js CHANGED
@@ -1 +1 @@
1
- import{i as e,t}from"./caller-DULg_ZYV.js";import{n,t as r}from"./onAbort-BgMfspK4.js";import{i,n as a}from"./context-Dp_QRXzb.js";import{t as o}from"./emit-key-C6FL7Ewn.js";import{t as s}from"./event-DVcW0mME.js";import{r as c}from"./bus-Cmk4U1hQ.js";import{n as l,t as u}from"./lifecycle-key-8iX8RUVD.js";import{t as d}from"./origin-key-BbWN3gmN.js";import{t as f}from"./scope-key-B7l7mUS5.js";import{t as p}from"./mount-each-D54UqAhZ.js";const m=(e,t)=>(t&&Object.defineProperty(e,f,{value:t}),e),h=(e,t)=>({...e,...t,$effects:{...e.$effects,...t.$effects}}),g=e=>Reflect.get(e,f),_=e=>{let t=Object.assign(n=>c(t,e,n),{type:e});return t},v=e=>typeof e==`object`&&!!e&&Reflect.get(e,`signal`)instanceof AbortSignal&&typeof Reflect.get(e,`emit`)==`function`;var y=class extends Error{};function b(e,t,n){return x(e,t,n)}function x(e,t,n,r){let i=t=>t.type===e,a=e=>r?e.length===2&&v(e[1]):typeof e[1]==`object`;function o(...i){let[o,s]=i;if(a(i)){if(!t)throw new y(`No handler for action "${e}"`);return t(o,s)}let u=r&&Reflect.apply(r,null,i),d=u?u.payload:o;return m(c(l,e,d),n)}let s=Object.assign(o,{type:e,match:i,toString:()=>e}),l=m(s,n);return l}function S(e,t){return[e,t]}const C=e=>typeof Reflect.get(e??{},`handle`)==`function`,w=(e=[])=>t=>{let n=t.actions;if(C(n))return n.handle(e),n;let r=/* @__PURE__ */ new Map,i=(e,t)=>{let n={fn:t};return r.set(e,[...r.get(e)??[],n]),()=>{let t=(r.get(e)??[]).filter(e=>e!==n);t.length>0?r.set(e,t):r.delete(e)}};function a(e,t){if(t)return i(s(e),t);let n=e.map(([e,t])=>i(s(e),t));return()=>{for(let e of n)e()}}a(e);let o={run:(e,t,n)=>{let i=(r.get(e.type)??[]).at(-1)?.fn,a=i&&e.wrap?e.wrap(i):i??e;return Reflect.apply(a,null,[t,n])},handle:a,bound:e=>r.has(e)?_(e):void 0};return t.actions=o,o};function T(e,t,n){let{handle:r,prepare:i,scope:a}=E(typeof t==`function`?n:t),o=typeof t==`function`?t:r;return o?x(e,o,a,i):Object.assign(m((...t)=>{let n=i&&Reflect.apply(i,null,t);return m({type:e,payload:n?n.payload:t[0]},a)},a),{type:e,match:t=>t.type===e,toString:()=>e})}const E=e=>{if(!e)return{};let{handle:t,prepare:n,...r}=e,i=typeof t==`function`,a=typeof n==`function`;if(!i&&!a)return{scope:e};let o=Object.keys(r).length>0?r:void 0;return{...i&&{handle:t},...a&&{prepare:n},...o&&{scope:o}}},D=()=>e=>{function t(t,n){return(...r)=>{let i=t(...r),a=Reflect.get(e,d);a?a(i,n):e.emit(i)}}return Object.assign(e,{emitter:t})},O=e=>typeof e==`string`?T(e):e,k=(e,t,n,r)=>{let i=g(t);e.emit(Reflect.apply(t,null,[n]),r&&i?h(r,i):r)},A=(e,t,r,i)=>{let a=e;a[o]=!0;try{k(e,t,r,i)}catch(e){n(`cancel listener`,e)}a[o]=!1},j=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof y)throw e;return Promise.reject(e)}},M=(e,t,i={},a)=>{let o=b(e,t),s=t=>O(i[t]??`${e}/${t}`),d=s(`pending`),f=s(`success`),p=s(`fail`),h=s(`cancel`),g=(e,t,i,o)=>{let s=i,c=`idle`,l=()=>{},m=()=>{c=`closed`,l()},g=e=>{c===`started`&&(m(),A(s,h,e,a))},_=()=>{c===`idle`&&(c=`started`,l=r(s,g),k(s,d,t,a))},v=e=>{c===`started`&&(m(),s.signal.aborted?A(s,h,s.signal.reason,a):`error`in e?k(s,p,e.error,a):k(s,f,e.value,a))};return Reflect.set(s,u,{start:_,cancel:g,done:v,drop:()=>{c===`idle`&&(c=`closed`)}}),j(()=>(o||_(),Reflect.apply(e,null,[t,i]))).then(e=>(v({value:e}),e),e=>{if(c===`idle`)try{_()}catch(e){n(`pending listener`,e)}v({error:e})})},_=e=>{let t=Reflect.get(e,l)===!0;return(n,r)=>g(e,n,r,t)},v=Reflect.get(t??{},l)===!0;function y(n,r){return typeof r==`object`?t?g(o,n,r,v):Reflect.apply(o,null,[n,r]):m(c(S,e,n),a)}let x=Object.assign(y,{type:e,match:o.match,wrap:_,pending:d,success:f,fail:p,cancel:h}),S=m(x,a);return S},N=e=>typeof e==`object`&&!!e,P=e=>{if(typeof e==`string`)return e;if(N(e)||typeof e==`function`){let t=Reflect.get(e,`type`);return typeof t==`string`?t:e}return e},F=(e,t)=>{let[n,r]=e;return n===void 0||Object.is(P(n),P(t[0]))&&(r===void 0||Object.is(r,t[1]))},I=n=>{let r={on:n.on,once:n.once,off:n.off},i=[],a=!0,o=(e,t)=>Reflect.apply(e,n,t),s=(e,n)=>(...r)=>{if(!a)return o(n,r);let s={kind:e,args:r,stack:t(),dropped:!1};return i.push(s),()=>{s.live?s.live():s.dropped=!0}},c=e=>(...t)=>{if(!a)return o(e,t);for(let e of i)e.kind!==`off`&&F(t,e.args)&&(e.dropped=!0);i.push({kind:`off`,args:t,dropped:!1})},l=s(`on`,r.on),u=s(`once`,r.once),d=c(r.off);return n.on=l,n.once=u,n.off=d,{release:()=>{a=!1,n.on===l&&(n.on=r.on),n.once===u&&(n.once=r.once),n.off===d&&(n.off=r.off)},replay:()=>{for(let t of i.splice(0))if(!t.dropped){if(t.kind===`off`)o(r.off,t.args);else{let n=t.kind===`on`?r.on:r.once;t.live=e(()=>o(n,t.args),t.stack)}}}}};function L(e,t,n){return n?{name:e,setup:t,scope:n}:{name:e,setup:t}}const R=(e,t)=>n=>t?e.fitScope?.(t,n)??n:n,z=(e,t,n)=>{n&&e.applyScope?.(t,n)},B=(e,t,n)=>Array.isArray(t)?[t.map(([t,n])=>[t,e(n)]),n]:[t,e(n)],V=(t,n)=>{let r=t.on;return(...t)=>{let[i,a,...o]=t;return e(()=>Reflect.apply(r,null,[i,n(a),...o]))}},H=e=>(t,...n)=>{e.run(t,...n).catch(t=>{if(!e.signal.aborted)throw t})},U=(e=[])=>t=>{let o=t.actions??w()(t),s={handle:(...e)=>{if(!o.handle)throw Error("modulePlugin: the `actions` of the bus is not a registry from `actionsPlugin()`");return Reflect.apply(o.handle,null,e)}},c=e=>{let n=/* @__PURE__ */ new Map,a=/* @__PURE__ */ new Map;return{mount:o=>{let l=n.get(o);if(l)return l;let u=a.get(o.name);u&&n.get(u)?.();let d=i(e,o.name),f=d.ctx,p=c(f),m=()=>{n.delete(o),a.get(o.name)===o&&a.delete(o.name),f.abort(),d.unlink()};n.set(o,m),a.set(o.name,o);let h=o.scope,g=R(t,h),_=(e,t)=>{let n=Reflect.apply(s.handle,null,B(g,e,t));return r(f,n),n},v=(...e)=>{let t=e.map(e=>typeof e==`function`?_(e,e):p.mount(e));return()=>{for(let e of t)e()}},y=H(f),b=V(f,g);try{z(t,f,h),o.setup(Object.assign(f,{handle:_,use:v,spawn:y,on:b}))}catch(e){throw m(),e}return m},unmount:e=>n.get(e)?.(),isMounted:e=>n.has(e)}},l=I(t),u=t.emit,d=t.get,f,m=(n=!0)=>{if(f)return f;l.release(),t.emit===h&&(t.emit=u);let r=a({event:{type:`app`,payload:void 0},bus:t,tracer:t.trace});f={root:r,apps:p(c(r.ctx))};try{n&&f.apps.mount(...e)}finally{l.replay()}return f},h=(...e)=>(m(),Reflect.apply(u,t,e));t.emit=h,t.get=((...e)=>(m(),Reflect.apply(d,t,e))),e.length>0&&queueMicrotask(()=>{try{m()}catch(e){n(`the modules of the app could not start`,e)}});let g={get actions(){return m(),o},mount:(...e)=>{let{root:t,apps:n}=m();return t.ctx.signal.throwIfAborted(),n.mount(...e)},unmount:(...e)=>m().apps.unmount(...e),isMounted:e=>m().apps.isMounted(e),dispose:()=>m(!1).root.ctx.abort(),createModule:L};return t.app=g,g};export{w as actionsPlugin,T as createAction,M as createJob,L as createModule,D as emitterPlugin,U as modulePlugin,S as setHandler};
1
+ import{i as e,t}from"./caller-DULg_ZYV.js";import{n,t as r}from"./onAbort-BgMfspK4.js";import{i,n as a}from"./context-Dp_QRXzb.js";import{t as o}from"./emit-key-C6FL7Ewn.js";import{t as s}from"./event-DVcW0mME.js";import{r as c}from"./bus-Cmk4U1hQ.js";import{n as l,t as u}from"./lifecycle-key-8iX8RUVD.js";import{t as d}from"./origin-key-BbWN3gmN.js";import{t as f}from"./scope-key-B7l7mUS5.js";import{t as p}from"./mount-each-D54UqAhZ.js";const m=(e,t)=>(t&&Object.defineProperty(e,f,{value:t}),e),h=(e,t)=>({...e,...t,$effects:{...e.$effects,...t.$effects}}),g=e=>Reflect.get(e,f),_=e=>{let t=Object.assign(n=>c(t,e,n),{type:e});return t},v=e=>typeof e==`object`&&!!e&&Reflect.get(e,`signal`)instanceof AbortSignal&&typeof Reflect.get(e,`emit`)==`function`;var y=class extends Error{};function b(e,t,n){return x(e,t,n)}function x(e,t,n,r){let i=t=>t.type===e,a=e=>r?e.length===2&&v(e[1]):typeof e[1]==`object`;function o(...i){let[o,s]=i;if(a(i)){if(!t)throw new y(`No handler for action "${e}"`);return t(o,s)}let u=r&&Reflect.apply(r,null,i),d=u?u.payload:o;return m(c(l,e,d),n)}let s=Object.assign(o,{type:e,match:i,toString:()=>e}),l=m(s,n);return l}const S=e=>typeof Reflect.get(e??{},`handle`)==`function`,C=()=>e=>{let t=e.actions;if(S(t))return t;let n=/* @__PURE__ */ new Map,r=(e,t)=>{let r={fn:t};return n.set(e,[...n.get(e)??[],r]),()=>{let t=(n.get(e)??[]).filter(e=>e!==r);t.length>0?n.set(e,t):n.delete(e)}};function i(e,t){return r(s(e),t)}let a={run:(e,t,r)=>{let i=(n.get(e.type)??[]).at(-1)?.fn,a=i&&e.wrap?e.wrap(i):i??e;return Reflect.apply(a,null,[t,r])},handle:i,bound:e=>n.has(e)?_(e):void 0};return e.actions=a,a};function w(e,t,n){let{handle:r,prepare:i,scope:a}=T(typeof t==`function`?n:t),o=typeof t==`function`?t:r;return o?x(e,o,a,i):Object.assign(m((...t)=>{let n=i&&Reflect.apply(i,null,t);return m({type:e,payload:n?n.payload:t[0]},a)},a),{type:e,match:t=>t.type===e,toString:()=>e})}const T=e=>{if(!e)return{};let{handle:t,prepare:n,...r}=e,i=typeof t==`function`,a=typeof n==`function`;if(!i&&!a)return{scope:e};let o=Object.keys(r).length>0?r:void 0;return{...i&&{handle:t},...a&&{prepare:n},...o&&{scope:o}}},E=()=>e=>{function t(t,n){return(...r)=>{let i=t(...r),a=Reflect.get(e,d);a?a(i,n):e.emit(i)}}return Object.assign(e,{emitter:t})},D=e=>typeof e==`string`?w(e):e,O=(e,t,n,r)=>{let i=g(t);e.emit(Reflect.apply(t,null,[n]),r&&i?h(r,i):r)},k=(e,t,r,i)=>{let a=e;a[o]=!0;try{O(e,t,r,i)}catch(e){n(`cancel listener`,e)}a[o]=!1},A=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof y)throw e;return Promise.reject(e)}},j=(e,t,i={},a)=>{let o=b(e,t),s=t=>D(i[t]??`${e}/${t}`),d=s(`pending`),f=s(`success`),p=s(`fail`),h=s(`cancel`),g=(e,t,i,o)=>{let s=i,c=`idle`,l=()=>{},m=()=>{c=`closed`,l()},g=e=>{c===`started`&&(m(),k(s,h,e,a))},_=()=>{c===`idle`&&(c=`started`,l=r(s,g),O(s,d,t,a))},v=e=>{c===`started`&&(m(),s.signal.aborted?k(s,h,s.signal.reason,a):`error`in e?O(s,p,e.error,a):O(s,f,e.value,a))};return Reflect.set(s,u,{start:_,cancel:g,done:v,drop:()=>{c===`idle`&&(c=`closed`)}}),A(()=>(o||_(),Reflect.apply(e,null,[t,i]))).then(e=>(v({value:e}),e),e=>{if(c===`idle`)try{_()}catch(e){n(`pending listener`,e)}v({error:e})})},_=e=>{let t=Reflect.get(e,l)===!0;return(n,r)=>g(e,n,r,t)},v=Reflect.get(t??{},l)===!0;function y(n,r){return typeof r==`object`?t?g(o,n,r,v):Reflect.apply(o,null,[n,r]):m(c(S,e,n),a)}let x=Object.assign(y,{type:e,match:o.match,wrap:_,pending:d,success:f,fail:p,cancel:h}),S=m(x,a);return S},M=e=>typeof e==`object`&&!!e,N=e=>{if(typeof e==`string`)return e;if(M(e)||typeof e==`function`){let t=Reflect.get(e,`type`);return typeof t==`string`?t:e}return e},P=(e,t)=>{let[n,r]=e;return n===void 0||Object.is(N(n),N(t[0]))&&(r===void 0||Object.is(r,t[1]))},F=n=>{let r={on:n.on,once:n.once,off:n.off},i=[],a=!0,o=(e,t)=>Reflect.apply(e,n,t),s=(e,n)=>(...r)=>{if(!a)return o(n,r);let s={kind:e,args:r,stack:t(),dropped:!1};return i.push(s),()=>{s.live?s.live():s.dropped=!0}},c=e=>(...t)=>{if(!a)return o(e,t);for(let e of i)e.kind!==`off`&&P(t,e.args)&&(e.dropped=!0);i.push({kind:`off`,args:t,dropped:!1})},l=s(`on`,r.on),u=s(`once`,r.once),d=c(r.off);return n.on=l,n.once=u,n.off=d,{release:()=>{a=!1,n.on===l&&(n.on=r.on),n.once===u&&(n.once=r.once),n.off===d&&(n.off=r.off)},replay:()=>{for(let t of i.splice(0))if(!t.dropped){if(t.kind===`off`)o(r.off,t.args);else{let n=t.kind===`on`?r.on:r.once;t.live=e(()=>o(n,t.args),t.stack)}}}}};function I(e,t,n){return n?{name:e,setup:t,scope:n}:{name:e,setup:t}}const L=(e,t)=>n=>t?e.fitScope?.(t,n)??n:n,R=(e,t,n)=>{n&&e.applyScope?.(t,n)},z=(e,t,n)=>[t,e(n)],B=(t,n)=>{let r=t.on;return(...t)=>{let[i,a,...o]=t;return e(()=>Reflect.apply(r,null,[i,n(a),...o]))}},V=e=>(t,...n)=>{e.run(t,...n).catch(t=>{if(!e.signal.aborted)throw t})},H=(e=[])=>t=>{let o=t.actions??C()(t),s={handle:(...e)=>{if(!o.handle)throw Error("modulePlugin: the `actions` of the bus is not a registry from `actionsPlugin()`");return Reflect.apply(o.handle,null,e)}},c=e=>{let n=/* @__PURE__ */ new Map,a=/* @__PURE__ */ new Map;return{mount:o=>{let l=n.get(o);if(l)return l;let u=a.get(o.name);u&&n.get(u)?.();let d=i(e,o.name),f=d.ctx,p=c(f),m=()=>{n.delete(o),a.get(o.name)===o&&a.delete(o.name),f.abort(),d.unlink()};n.set(o,m),a.set(o.name,o);let h=o.scope,g=L(t,h),_=(e,t)=>{let n=Reflect.apply(s.handle,null,z(g,e,t));return r(f,n),n},v=(...e)=>{let t=e.map(e=>typeof e==`function`?_(e,e):p.mount(e));return()=>{for(let e of t)e()}},y=V(f),b=B(f,g);try{R(t,f,h),o.setup(Object.assign(f,{handle:_,use:v,spawn:y,on:b}))}catch(e){throw m(),e}return m},unmount:e=>n.get(e)?.(),isMounted:e=>n.has(e)}},l=F(t),u=t.emit,d=t.get,f,m=(n=!0)=>{if(f)return f;l.release(),t.emit===h&&(t.emit=u);let r=a({event:{type:`app`,payload:void 0},bus:t,tracer:t.trace});f={root:r,apps:p(c(r.ctx))};try{n&&f.apps.mount(...e)}finally{l.replay()}return f},h=(...e)=>(m(),Reflect.apply(u,t,e));t.emit=h,t.get=((...e)=>(m(),Reflect.apply(d,t,e))),e.length>0&&queueMicrotask(()=>{try{m()}catch(e){n(`the modules of the app could not start`,e)}});let g={get actions(){return m(),o},mount:(...e)=>{let{root:t,apps:n}=m();return t.ctx.signal.throwIfAborted(),n.mount(...e)},unmount:(...e)=>m().apps.unmount(...e),isMounted:e=>m().apps.isMounted(e),dispose:()=>m(!1).root.ctx.abort(),createModule:I};return t.app=g,g};export{C as actionsPlugin,w as createAction,j as createJob,I as createModule,E as emitterPlugin,H as modulePlugin};
package/dist/dev.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { H as EventMap, Q as UnsubscribeCallback, v as Bus } from "./action-creator-DprJV-pN.js";
2
- import { i as WithApp, n as ModuleApi } from "./module-DPKjzfRk.js";
2
+ import { i as WithApp, n as ModuleApi } from "./module-Fk4OtkZk.js";
3
3
  //#region src/dev/types.d.ts
4
4
  /** The parts of what `modulePlugin` returned that the diagnostics report. */
5
5
  type ReportedApp<E extends EventMap> = Pick<ModuleApi<E>, "mount" | "unmount" | "isMounted">;
@@ -17,22 +17,6 @@ type MadeHandled<P, R, T extends string> = Handled<P, R> & {
17
17
  type CarryingCalls<Made, P, R, F> = [unknown] extends [F] ? Made : ((payload: P) => HandledCall<P, R> & WithScope<F>) & Made & WithScope<F>;
18
18
  /** An action made with a scope: its calls carry the fields of that scope, for the checker. */
19
19
  type ScopedHandled<P, R, T extends string, F> = ((payload: P) => HandledCall<P, R> & WithScope<F>) & MadeHandled<P, R, T> & WithScope<F>;
20
- /** An action (or its type) with the handler to bind to it; `setHandler` makes one. */
21
- type Binding<E extends EventMap = EventMap> = readonly [Handled<never, unknown> | string, Task<never, E, unknown>];
22
- /**
23
- * Pairs an action with the handler to bind to it, for `actionsPlugin`. For a
24
- * action (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.
26
- *
27
- * @example
28
- * ```ts
29
- * bus.use(actionsPlugin([setHandler(sendMail, smtpSend)]));
30
- * ```
31
- */
32
- declare function setHandler<P, R, E extends EventMap>(handled: Handled<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>;
36
20
  /**
37
21
  * The handler an action that is not an action can have: any. An action
38
22
  * (a creator whose calls are calls of an action with a handler) is not accepted here, so its own
@@ -49,15 +33,14 @@ interface Registry$1<E extends EventMap> extends Actions {
49
33
  readonly type: string;
50
34
  }>(action: A, fn: LooseHandler<A, E>): UnsubscribeCallback;
51
35
  handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
52
- handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
53
36
  }
54
37
  /**
55
38
  * The plugin that gives a bus the handlers bound to actions:
56
- * `bus.use(actionsPlugin(bindings))` makes the registry, sets it as the
39
+ * `bus.use(actionsPlugin())` makes the registry, sets it as the
57
40
  * actions of the bus and returns it. Each bus has its own, so each test can
58
- * have its own implementation. `handle` binds more later and returns the
59
- * function that unbinds. A second `actionsPlugin` on the same bus binds its
60
- * list in the registry that is there and returns it, so the order of the
41
+ * have its own implementation. `handle` binds a handler and returns the
42
+ * function that unbinds. A second `actionsPlugin` on the same bus returns the
43
+ * registry that is there, so the order of the
61
44
  * plugins does not matter. A `actions` that is not such a registry (a custom
62
45
  * runner) is replaced.
63
46
  *
@@ -67,13 +50,14 @@ interface Registry$1<E extends EventMap> extends Actions {
67
50
  * @example
68
51
  * ```ts
69
52
  * const bus = createBus<Events>();
70
- * const actions = bus.use(actionsPlugin([setHandler(sendMail, smtpSend)]));
53
+ * const actions = bus.use(actionsPlugin());
54
+ * actions.handle(sendMail, smtpSend);
71
55
  *
72
56
  * const unbind = actions.handle(getUser, async () => fakeUser);
73
57
  * unbind(); // the action's own handler is back
74
58
  * ```
75
59
  */
76
- declare const actionsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>[]) => (bus: Bus<E>) => Registry$1<E>;
60
+ declare const actionsPlugin: <E extends EventMap>() => (bus: Bus<E>) => Registry$1<E>;
77
61
  //#endregion
78
62
  //#region src/actions/module.d.ts
79
63
  /**
@@ -83,14 +67,13 @@ declare const actionsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>
83
67
  * module does is undone when it is unmounted.
84
68
  */
85
69
  type ModuleContext<E extends EventMap = EventMap> = Context<E> & {
86
- /** Binds the handler of an action, or a list of them; undone on unmount. */
70
+ /** Binds the handler of an action; undone on unmount. */
87
71
  handle<P, R>(handled: Handled<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
88
72
  /** Also an action made without a handler: the handler answers it as it would one made with a handler. */
89
73
  handle<A extends {
90
74
  readonly type: string;
91
75
  }>(action: A, fn: LooseHandler<A, E>): UnsubscribeCallback;
92
76
  handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
93
- handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
94
77
  /**
95
78
  * Brings sub-modules and actions, in any order. A sub-module is mounted and
96
79
  * unmounted with this one. An action is bound to the handler it carries, for
@@ -124,7 +107,7 @@ type Module<E extends EventMap = EventMap> = {
124
107
  * ```ts
125
108
  * export const userModule = createModule<Events>("user", (m) => {
126
109
  * m.handle(getUser, fetchUser);
127
- * m.handle([setHandler(sendMail, smtpSend)]);
110
+ * m.handle(sendMail, smtpSend);
128
111
  * m.use(authModule);
129
112
  *
130
113
  * m.on(loginRequested, (user, ctx) => ctx.emit(userLoaded(user)));
@@ -220,4 +203,4 @@ type ModuleApi<E extends EventMap = EventMap> = {
220
203
  */
221
204
  declare const modulePlugin: <E extends EventMap>(modules?: readonly Module<E>[]) => (bus: Bus<E> & ScopeSlots & WithApp) => ModuleApi<E>;
222
205
  //#endregion
223
- export { createModule as a, CarryingCalls as c, actionsPlugin as d, setHandler as f, WithApp as i, MadeHandled as l, ModuleApi as n, modulePlugin as o, ModuleContext as r, Binding as s, Module as t, ScopedHandled as u };
206
+ export { createModule as a, MadeHandled as c, WithApp as i, ScopedHandled as l, ModuleApi as n, modulePlugin as o, ModuleContext as r, CarryingCalls as s, Module as t, actionsPlugin as u };
@@ -40,22 +40,6 @@ type MadeHandled<P, R, T extends string> = Handled<P, R> & {
40
40
  type CarryingCalls<Made, P, R, F> = [unknown] extends [F] ? Made : ((payload: P) => HandledCall<P, R> & WithScope<F>) & Made & WithScope<F>;
41
41
  /** An action made with a scope: its calls carry the fields of that scope, for the checker. */
42
42
  type ScopedHandled<P, R, T extends string, F> = ((payload: P) => HandledCall<P, R> & WithScope<F>) & MadeHandled<P, R, T> & WithScope<F>;
43
- /** An action (or its type) with the handler to bind to it; `setHandler` makes one. */
44
- type Binding<E extends EventMap = EventMap> = readonly [Handled<never, unknown> | string, Task<never, E, unknown>];
45
- /**
46
- * Pairs an action with the handler to bind to it, for `actionsPlugin`. For a
47
- * action (an action made with a handler, or with a `Call` type) it checks that
48
- * the handler fits; any other action is accepted with a handler of any payload.
49
- *
50
- * @example
51
- * ```ts
52
- * bus.use(actionsPlugin([setHandler(sendMail, smtpSend)]));
53
- * ```
54
- */
55
- export declare function setHandler<P, R, E extends EventMap>(handled: Handled<P, R>, fn: Task<P, E, R>): Binding<E>;
56
- export declare function setHandler<A extends {
57
- readonly type: string;
58
- }, E extends EventMap>(action: A, fn: LooseHandler<A, E>): Binding<E>;
59
43
  /**
60
44
  * The handler an action that is not an action can have: any. An action
61
45
  * (a creator whose calls are calls of an action with a handler) is not accepted here, so its own
@@ -72,15 +56,14 @@ interface Registry$1<E extends EventMap> extends Actions {
72
56
  readonly type: string;
73
57
  }>(action: A, fn: LooseHandler<A, E>): UnsubscribeCallback;
74
58
  handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
75
- handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
76
59
  }
77
60
  /**
78
61
  * The plugin that gives a bus the handlers bound to actions:
79
- * `bus.use(actionsPlugin(bindings))` makes the registry, sets it as the
62
+ * `bus.use(actionsPlugin())` makes the registry, sets it as the
80
63
  * actions of the bus and returns it. Each bus has its own, so each test can
81
- * have its own implementation. `handle` binds more later and returns the
82
- * function that unbinds. A second `actionsPlugin` on the same bus binds its
83
- * list in the registry that is there and returns it, so the order of the
64
+ * have its own implementation. `handle` binds a handler and returns the
65
+ * function that unbinds. A second `actionsPlugin` on the same bus returns the
66
+ * registry that is there, so the order of the
84
67
  * plugins does not matter. A `actions` that is not such a registry (a custom
85
68
  * runner) is replaced.
86
69
  *
@@ -90,13 +73,14 @@ interface Registry$1<E extends EventMap> extends Actions {
90
73
  * @example
91
74
  * ```ts
92
75
  * const bus = createBus<Events>();
93
- * const actions = bus.use(actionsPlugin([setHandler(sendMail, smtpSend)]));
76
+ * const actions = bus.use(actionsPlugin());
77
+ * actions.handle(sendMail, smtpSend);
94
78
  *
95
79
  * const unbind = actions.handle(getUser, async () => fakeUser);
96
80
  * unbind(); // the action's own handler is back
97
81
  * ```
98
82
  */
99
- export declare const actionsPlugin: <E extends EventMap>(bindings?: readonly Binding<E>[]) => (bus: Bus<E>) => Registry$1<E>;
83
+ export declare const actionsPlugin: <E extends EventMap>() => (bus: Bus<E>) => Registry$1<E>;
100
84
  //#endregion
101
85
  //#region src/actions/action.d.ts
102
86
  type Reserved = "handle" | "prepare";
@@ -298,14 +282,13 @@ scope?: X) => CarryingCalls<Job<P, R, T, S, F, PE, CE>, P, Promise<Awaited<R> |
298
282
  * module does is undone when it is unmounted.
299
283
  */
300
284
  type ModuleContext<E extends EventMap = EventMap> = Context<E> & {
301
- /** Binds the handler of an action, or a list of them; undone on unmount. */
285
+ /** Binds the handler of an action; undone on unmount. */
302
286
  handle<P, R>(handled: Handled<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
303
287
  /** Also an action made without a handler: the handler answers it as it would one made with a handler. */
304
288
  handle<A extends {
305
289
  readonly type: string;
306
290
  }>(action: A, fn: LooseHandler<A, E>): UnsubscribeCallback;
307
291
  handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
308
- handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
309
292
  /**
310
293
  * Brings sub-modules and actions, in any order. A sub-module is mounted and
311
294
  * unmounted with this one. An action is bound to the handler it carries, for
@@ -339,7 +322,7 @@ type Module<E extends EventMap = EventMap> = {
339
322
  * ```ts
340
323
  * export const userModule = createModule<Events>("user", (m) => {
341
324
  * m.handle(getUser, fetchUser);
342
- * m.handle([setHandler(sendMail, smtpSend)]);
325
+ * m.handle(sendMail, smtpSend);
343
326
  * m.use(authModule);
344
327
  *
345
328
  * m.on(loginRequested, (user, ctx) => ctx.emit(userLoaded(user)));
@@ -435,4 +418,4 @@ type ModuleApi<E extends EventMap = EventMap> = {
435
418
  */
436
419
  export declare const modulePlugin: <E extends EventMap>(modules?: readonly Module<E>[]) => (bus: Bus<E> & ScopeSlots & WithApp) => ModuleApi<E>;
437
420
  //#endregion
438
- export type { ActionCreator, Binding, EmitterApi, FreeActionCreator, Job, Module, ModuleApi, ModuleContext };
421
+ export type { ActionCreator, EmitterApi, FreeActionCreator, Job, Module, ModuleApi, ModuleContext };
@@ -1 +1 @@
1
- import{c as e,i as t,l as n,n as r,s as i}from"./context-_HWcdjZf.js";import{n as a,r as o}from"./bus-37nlVljc.js";import{n as s,t as c}from"./lifecycle-key-8iX8RUVD.js";import{t as l}from"./origin-key-BbWN3gmN.js";const u=(e,t)=>e(),d=Symbol.for(`nanoeffects.scope`),f=(e,t)=>(t&&Object.defineProperty(e,d,{value:t}),e),p=(e,t)=>({...e,...t,$effects:{...e.$effects,...t.$effects}}),m=e=>Reflect.get(e,d),h=e=>{let t=Object.assign(n=>a(t,e,n),{type:e});return t},g=e=>typeof e==`object`&&!!e&&Reflect.get(e,`signal`)instanceof AbortSignal&&typeof Reflect.get(e,`emit`)==`function`;var _=class extends Error{};function v(e,t,n){return y(e,t,n)}function y(e,t,n,r){let i=t=>t.type===e,o=e=>r?e.length===2&&g(e[1]):typeof e[1]==`object`;function s(...i){let[s,c]=i;if(o(i)){if(!t)throw new _(`No handler for action "${e}"`);return t(s,c)}let u=r&&Reflect.apply(r,null,i),d=u?u.payload:s;return f(a(l,e,d),n)}let c=Object.assign(s,{type:e,match:i,toString:()=>e}),l=f(c,n);return l}function b(e,t){return[e,t]}const x=e=>typeof Reflect.get(e??{},`handle`)==`function`,S=(e=[])=>t=>{let n=t.actions;if(x(n))return n.handle(e),n;let r=/* @__PURE__ */ new Map,i=(e,t)=>{let n={fn:t};return r.set(e,[...r.get(e)??[],n]),()=>{let t=(r.get(e)??[]).filter(e=>e!==n);t.length>0?r.set(e,t):r.delete(e)}};function a(e,t){if(t)return i(o(e),t);let n=e.map(([e,t])=>i(o(e),t));return()=>{for(let e of n)e()}}a(e);let s={run:(e,t,n)=>{let i=(r.get(e.type)??[]).at(-1)?.fn,a=i&&e.wrap?e.wrap(i):i??e;return Reflect.apply(a,null,[t,n])},handle:a,bound:e=>r.has(e)?h(e):void 0};return t.actions=s,s};function C(e,t,n){let{handle:r,prepare:i,scope:a}=w(typeof t==`function`?n:t),o=typeof t==`function`?t:r;return o?y(e,o,a,i):Object.assign(f((...t)=>{let n=i&&Reflect.apply(i,null,t);return f({type:e,payload:n?n.payload:t[0]},a)},a),{type:e,match:t=>t.type===e,toString:()=>e})}const w=e=>{if(!e)return{};let{handle:t,prepare:n,...r}=e,i=typeof t==`function`,a=typeof n==`function`;if(!i&&!a)return{scope:e};let o=Object.keys(r).length>0?r:void 0;return{...i&&{handle:t},...a&&{prepare:n},...o&&{scope:o}}},T=()=>e=>{function t(t,n){return(...r)=>{let i=t(...r),a=Reflect.get(e,l);a?a(i,n):e.emit(i)}}return Object.assign(e,{emitter:t})},E=e=>typeof e==`string`?C(e):e,D=(e,t,n,r)=>{let i=m(t);e.emit(Reflect.apply(t,null,[n]),r&&i?p(r,i):r)},O=(e,t,r,a)=>{let o=e;o[i]=!0;try{D(e,t,r,a)}catch(e){n(`cancel listener`,e)}o[i]=!1},k=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof _)throw e;return Promise.reject(e)}},A=(t,r,i={},o)=>{let l=v(t,r),u=e=>E(i[e]??`${t}/${e}`),d=u(`pending`),p=u(`success`),m=u(`fail`),h=u(`cancel`),g=(t,r,i,a)=>{let s=i,l=`idle`,u=()=>{},f=()=>{l=`closed`,u()},g=e=>{l===`started`&&(f(),O(s,h,e,o))},_=()=>{l===`idle`&&(l=`started`,u=e(s,g),D(s,d,r,o))},v=e=>{l===`started`&&(f(),s.signal.aborted?O(s,h,s.signal.reason,o):`error`in e?D(s,m,e.error,o):D(s,p,e.value,o))};return Reflect.set(s,c,{start:_,cancel:g,done:v,drop:()=>{l===`idle`&&(l=`closed`)}}),k(()=>(a||_(),Reflect.apply(t,null,[r,i]))).then(e=>(v({value:e}),e),e=>{if(l===`idle`)try{_()}catch(e){n(`pending listener`,e)}v({error:e})})},_=e=>{let t=Reflect.get(e,s)===!0;return(n,r)=>g(e,n,r,t)},y=Reflect.get(r??{},s)===!0;function b(e,n){return typeof n==`object`?r?g(l,e,n,y):Reflect.apply(l,null,[e,n]):f(a(S,t,e),o)}let x=Object.assign(b,{type:t,match:l.match,wrap:_,pending:d,success:p,fail:m,cancel:h}),S=f(x,o);return S},j=e=>typeof e==`object`&&!!e,M=e=>{if(typeof e==`string`)return e;if(j(e)||typeof e==`function`){let t=Reflect.get(e,`type`);return typeof t==`string`?t:e}return e},N=(e,t)=>{let[n,r]=e;return n===void 0||Object.is(M(n),M(t[0]))&&(r===void 0||Object.is(r,t[1]))},P=e=>{let t={on:e.on,once:e.once,off:e.off},n=[],r=!0,i=(t,n)=>Reflect.apply(t,e,n),a=(e,t)=>(...a)=>{if(!r)return i(t,a);let o={kind:e,args:a,stack:void 0,dropped:!1};return n.push(o),()=>{o.live?o.live():o.dropped=!0}},o=e=>(...t)=>{if(!r)return i(e,t);for(let e of n)e.kind!==`off`&&N(t,e.args)&&(e.dropped=!0);n.push({kind:`off`,args:t,dropped:!1})},s=a(`on`,t.on),c=a(`once`,t.once),l=o(t.off);return e.on=s,e.once=c,e.off=l,{release:()=>{r=!1,e.on===s&&(e.on=t.on),e.once===c&&(e.once=t.once),e.off===l&&(e.off=t.off)},replay:()=>{for(let e of n.splice(0))if(!e.dropped){if(e.kind===`off`)i(t.off,e.args);else{let n=e.kind===`on`?t.on:t.once;e.live=u(()=>i(n,e.args),e.stack)}}}}},F=e=>({mount:(...t)=>{let[n]=t;if(t.length===1&&n!==void 0)return e.mount(n);let r=[],i=()=>{for(let e of r.splice(0).reverse())e()};try{for(let n of t)e.isMounted(n)||r.push(e.mount(n))}catch(e){throw i(),e}return i},unmount:(...t)=>{for(let n of[...t].reverse())e.unmount(n)},isMounted:e.isMounted});function I(e,t,n){return n?{name:e,setup:t,scope:n}:{name:e,setup:t}}const L=(e,t)=>n=>t?e.fitScope?.(t,n)??n:n,R=(e,t,n)=>{n&&e.applyScope?.(t,n)},z=(e,t,n)=>Array.isArray(t)?[t.map(([t,n])=>[t,e(n)]),n]:[t,e(n)],B=(e,t)=>{let n=e.on;return(...e)=>{let[r,i,...a]=e;return u(()=>Reflect.apply(n,null,[r,t(i),...a]))}},V=e=>(t,...n)=>{e.run(t,...n).catch(t=>{if(!e.signal.aborted)throw t})},H=(i=[])=>a=>{let o=a.actions??S()(a),s={handle:(...e)=>{if(!o.handle)throw Error("modulePlugin: the `actions` of the bus is not a registry from `actionsPlugin()`");return Reflect.apply(o.handle,null,e)}},c=n=>{let r=/* @__PURE__ */ new Map,i=/* @__PURE__ */ new Map;return{mount:o=>{let l=r.get(o);if(l)return l;let u=i.get(o.name);u&&r.get(u)?.();let d=t(n,o.name),f=d.ctx,p=c(f),m=()=>{r.delete(o),i.get(o.name)===o&&i.delete(o.name),f.abort(),d.unlink()};r.set(o,m),i.set(o.name,o);let h=o.scope,g=L(a,h),_=(t,n)=>{let r=Reflect.apply(s.handle,null,z(g,t,n));return e(f,r),r},v=(...e)=>{let t=e.map(e=>typeof e==`function`?_(e,e):p.mount(e));return()=>{for(let e of t)e()}},y=V(f),b=B(f,g);try{R(a,f,h),o.setup(Object.assign(f,{handle:_,use:v,spawn:y,on:b}))}catch(e){throw m(),e}return m},unmount:e=>r.get(e)?.(),isMounted:e=>r.has(e)}},l=P(a),u=a.emit,d=a.get,f,p=(e=!0)=>{if(f)return f;l.release(),a.emit===m&&(a.emit=u);let t=r({event:{type:`app`,payload:void 0},bus:a,tracer:a.trace});f={root:t,apps:F(c(t.ctx))};try{e&&f.apps.mount(...i)}finally{l.replay()}return f},m=(...e)=>(p(),Reflect.apply(u,a,e));a.emit=m,a.get=((...e)=>(p(),Reflect.apply(d,a,e))),i.length>0&&queueMicrotask(()=>{try{p()}catch(e){n(`the modules of the app could not start`,e)}});let h={get actions(){return p(),o},mount:(...e)=>{let{root:t,apps:n}=p();return t.ctx.signal.throwIfAborted(),n.mount(...e)},unmount:(...e)=>p().apps.unmount(...e),isMounted:e=>p().apps.isMounted(e),dispose:()=>p(!1).root.ctx.abort(),createModule:I};return a.app=h,h};export{S as actionsPlugin,C as createAction,A as createJob,I as createModule,T as emitterPlugin,H as modulePlugin,b as setHandler};
1
+ import{c as e,i as t,l as n,n as r,s as i}from"./context-_HWcdjZf.js";import{n as a,r as o}from"./bus-37nlVljc.js";import{n as s,t as c}from"./lifecycle-key-8iX8RUVD.js";import{t as l}from"./origin-key-BbWN3gmN.js";const u=(e,t)=>e(),d=Symbol.for(`nanoeffects.scope`),f=(e,t)=>(t&&Object.defineProperty(e,d,{value:t}),e),p=(e,t)=>({...e,...t,$effects:{...e.$effects,...t.$effects}}),m=e=>Reflect.get(e,d),h=e=>{let t=Object.assign(n=>a(t,e,n),{type:e});return t},g=e=>typeof e==`object`&&!!e&&Reflect.get(e,`signal`)instanceof AbortSignal&&typeof Reflect.get(e,`emit`)==`function`;var _=class extends Error{};function v(e,t,n){return y(e,t,n)}function y(e,t,n,r){let i=t=>t.type===e,o=e=>r?e.length===2&&g(e[1]):typeof e[1]==`object`;function s(...i){let[s,c]=i;if(o(i)){if(!t)throw new _(`No handler for action "${e}"`);return t(s,c)}let u=r&&Reflect.apply(r,null,i),d=u?u.payload:s;return f(a(l,e,d),n)}let c=Object.assign(s,{type:e,match:i,toString:()=>e}),l=f(c,n);return l}const b=e=>typeof Reflect.get(e??{},`handle`)==`function`,x=()=>e=>{let t=e.actions;if(b(t))return t;let n=/* @__PURE__ */ new Map,r=(e,t)=>{let r={fn:t};return n.set(e,[...n.get(e)??[],r]),()=>{let t=(n.get(e)??[]).filter(e=>e!==r);t.length>0?n.set(e,t):n.delete(e)}};function i(e,t){return r(o(e),t)}let a={run:(e,t,r)=>{let i=(n.get(e.type)??[]).at(-1)?.fn,a=i&&e.wrap?e.wrap(i):i??e;return Reflect.apply(a,null,[t,r])},handle:i,bound:e=>n.has(e)?h(e):void 0};return e.actions=a,a};function S(e,t,n){let{handle:r,prepare:i,scope:a}=C(typeof t==`function`?n:t),o=typeof t==`function`?t:r;return o?y(e,o,a,i):Object.assign(f((...t)=>{let n=i&&Reflect.apply(i,null,t);return f({type:e,payload:n?n.payload:t[0]},a)},a),{type:e,match:t=>t.type===e,toString:()=>e})}const C=e=>{if(!e)return{};let{handle:t,prepare:n,...r}=e,i=typeof t==`function`,a=typeof n==`function`;if(!i&&!a)return{scope:e};let o=Object.keys(r).length>0?r:void 0;return{...i&&{handle:t},...a&&{prepare:n},...o&&{scope:o}}},w=()=>e=>{function t(t,n){return(...r)=>{let i=t(...r),a=Reflect.get(e,l);a?a(i,n):e.emit(i)}}return Object.assign(e,{emitter:t})},T=e=>typeof e==`string`?S(e):e,E=(e,t,n,r)=>{let i=m(t);e.emit(Reflect.apply(t,null,[n]),r&&i?p(r,i):r)},D=(e,t,r,a)=>{let o=e;o[i]=!0;try{E(e,t,r,a)}catch(e){n(`cancel listener`,e)}o[i]=!1},O=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof _)throw e;return Promise.reject(e)}},k=(t,r,i={},o)=>{let l=v(t,r),u=e=>T(i[e]??`${t}/${e}`),d=u(`pending`),p=u(`success`),m=u(`fail`),h=u(`cancel`),g=(t,r,i,a)=>{let s=i,l=`idle`,u=()=>{},f=()=>{l=`closed`,u()},g=e=>{l===`started`&&(f(),D(s,h,e,o))},_=()=>{l===`idle`&&(l=`started`,u=e(s,g),E(s,d,r,o))},v=e=>{l===`started`&&(f(),s.signal.aborted?D(s,h,s.signal.reason,o):`error`in e?E(s,m,e.error,o):E(s,p,e.value,o))};return Reflect.set(s,c,{start:_,cancel:g,done:v,drop:()=>{l===`idle`&&(l=`closed`)}}),O(()=>(a||_(),Reflect.apply(t,null,[r,i]))).then(e=>(v({value:e}),e),e=>{if(l===`idle`)try{_()}catch(e){n(`pending listener`,e)}v({error:e})})},_=e=>{let t=Reflect.get(e,s)===!0;return(n,r)=>g(e,n,r,t)},y=Reflect.get(r??{},s)===!0;function b(e,n){return typeof n==`object`?r?g(l,e,n,y):Reflect.apply(l,null,[e,n]):f(a(S,t,e),o)}let x=Object.assign(b,{type:t,match:l.match,wrap:_,pending:d,success:p,fail:m,cancel:h}),S=f(x,o);return S},A=e=>typeof e==`object`&&!!e,j=e=>{if(typeof e==`string`)return e;if(A(e)||typeof e==`function`){let t=Reflect.get(e,`type`);return typeof t==`string`?t:e}return e},M=(e,t)=>{let[n,r]=e;return n===void 0||Object.is(j(n),j(t[0]))&&(r===void 0||Object.is(r,t[1]))},N=e=>{let t={on:e.on,once:e.once,off:e.off},n=[],r=!0,i=(t,n)=>Reflect.apply(t,e,n),a=(e,t)=>(...a)=>{if(!r)return i(t,a);let o={kind:e,args:a,stack:void 0,dropped:!1};return n.push(o),()=>{o.live?o.live():o.dropped=!0}},o=e=>(...t)=>{if(!r)return i(e,t);for(let e of n)e.kind!==`off`&&M(t,e.args)&&(e.dropped=!0);n.push({kind:`off`,args:t,dropped:!1})},s=a(`on`,t.on),c=a(`once`,t.once),l=o(t.off);return e.on=s,e.once=c,e.off=l,{release:()=>{r=!1,e.on===s&&(e.on=t.on),e.once===c&&(e.once=t.once),e.off===l&&(e.off=t.off)},replay:()=>{for(let e of n.splice(0))if(!e.dropped){if(e.kind===`off`)i(t.off,e.args);else{let n=e.kind===`on`?t.on:t.once;e.live=u(()=>i(n,e.args),e.stack)}}}}},P=e=>({mount:(...t)=>{let[n]=t;if(t.length===1&&n!==void 0)return e.mount(n);let r=[],i=()=>{for(let e of r.splice(0).reverse())e()};try{for(let n of t)e.isMounted(n)||r.push(e.mount(n))}catch(e){throw i(),e}return i},unmount:(...t)=>{for(let n of[...t].reverse())e.unmount(n)},isMounted:e.isMounted});function F(e,t,n){return n?{name:e,setup:t,scope:n}:{name:e,setup:t}}const I=(e,t)=>n=>t?e.fitScope?.(t,n)??n:n,L=(e,t,n)=>{n&&e.applyScope?.(t,n)},R=(e,t,n)=>[t,e(n)],z=(e,t)=>{let n=e.on;return(...e)=>{let[r,i,...a]=e;return u(()=>Reflect.apply(n,null,[r,t(i),...a]))}},B=e=>(t,...n)=>{e.run(t,...n).catch(t=>{if(!e.signal.aborted)throw t})},V=(i=[])=>a=>{let o=a.actions??x()(a),s={handle:(...e)=>{if(!o.handle)throw Error("modulePlugin: the `actions` of the bus is not a registry from `actionsPlugin()`");return Reflect.apply(o.handle,null,e)}},c=n=>{let r=/* @__PURE__ */ new Map,i=/* @__PURE__ */ new Map;return{mount:o=>{let l=r.get(o);if(l)return l;let u=i.get(o.name);u&&r.get(u)?.();let d=t(n,o.name),f=d.ctx,p=c(f),m=()=>{r.delete(o),i.get(o.name)===o&&i.delete(o.name),f.abort(),d.unlink()};r.set(o,m),i.set(o.name,o);let h=o.scope,g=I(a,h),_=(t,n)=>{let r=Reflect.apply(s.handle,null,R(g,t,n));return e(f,r),r},v=(...e)=>{let t=e.map(e=>typeof e==`function`?_(e,e):p.mount(e));return()=>{for(let e of t)e()}},y=B(f),b=z(f,g);try{L(a,f,h),o.setup(Object.assign(f,{handle:_,use:v,spawn:y,on:b}))}catch(e){throw m(),e}return m},unmount:e=>r.get(e)?.(),isMounted:e=>r.has(e)}},l=N(a),u=a.emit,d=a.get,f,p=(e=!0)=>{if(f)return f;l.release(),a.emit===m&&(a.emit=u);let t=r({event:{type:`app`,payload:void 0},bus:a,tracer:a.trace});f={root:t,apps:P(c(t.ctx))};try{e&&f.apps.mount(...i)}finally{l.replay()}return f},m=(...e)=>(p(),Reflect.apply(u,a,e));a.emit=m,a.get=((...e)=>(p(),Reflect.apply(d,a,e))),i.length>0&&queueMicrotask(()=>{try{p()}catch(e){n(`the modules of the app could not start`,e)}});let h={get actions(){return p(),o},mount:(...e)=>{let{root:t,apps:n}=p();return t.ctx.signal.throwIfAborted(),n.mount(...e)},unmount:(...e)=>p().apps.unmount(...e),isMounted:e=>p().apps.isMounted(e),dispose:()=>p(!1).root.ctx.abort(),createModule:F};return a.app=h,h};export{x as actionsPlugin,S as createAction,k as createJob,F as createModule,w as emitterPlugin,V as modulePlugin};
package/dist/testing.js CHANGED
@@ -1 +1 @@
1
- import{t as e}from"./bus-Cmk4U1hQ.js";import{n as t,t as n}from"./tracer-mMDm5yE7.js";const r=e=>({advance:t=>e.advanceTimersByTimeAsync(t).then(()=>{}),now:()=>Date.now()}),i={start:`s`,done:`d`,error:`e`,cancel:`c`,drop:`x`},a=new Set(Object.values(i)),o=e=>i[e],s=(e,t,n)=>{throw Error(`marble "${e}": ${n} at position ${t}`)},c=(e,t,n)=>{for(let r=0;r<n.length;r+=1){let i=n.charAt(r);(/\s/.test(i)||i===`|`)&&s(e,t+r,`"${i.trim()||`space`}" is not part of a diagram`)}},l=(e,t)=>{let n=e.indexOf(`)`,t);n<0&&s(e,t,`a group that is not closed with ")"`);let r=e.slice(t+1,n);r===``&&s(e,t,`an empty group`);let i=r.indexOf(`(`);i>=0&&s(e,t+1+i,`a group inside a group`);let a=r.indexOf(`-`);return a>=0&&s(e,t+1+a,`"-" inside a group`),c(e,t+1,r),{frame:[...r],next:n+1}},u=(e,t)=>{let n=e.charAt(t);return n===`(`?l(e,t):(n===`)`&&s(e,t,`")" without "("`),c(e,t,n),{frame:n===`-`?[]:[n],next:t+1})},d=e=>{let t=[],n=0;for(;n<e.length;){let{frame:r,next:i}=u(e,n);t.push(r),n=i}return t},f=e=>{let t=d(e),n=0;for(let r of t){for(let t of r)a.has(t)||s(e,n,`"${t}" is not a phase (s d e c x)`);n+=r.length||1}return t},p=(e,t)=>{let n=``;for(let r=0;r<t;r+=1){let t=e[r]??[];t.length===0?n+=`-`:t.length===1?n+=t[0]:n+=`(${t.join(``)})`}return n},m=(e,t)=>e&&Object.hasOwn(e,t)?e[t]:t,h=(e,t,n,r,i)=>{let a=Array.from({length:i},()=>[]);for(let o of e){let e=Math.floor((o.at-n)/r);o.key===t&&e>=0&&e<i&&a[e]?.push(o.letter)}return a},g=(e,t)=>t.includes(`:`)?e.includes(t)?[t]:[]:e.filter(e=>e.endsWith(`:${t}`)),_=(e,t,n)=>`marble row "${e}" differs\n expected ${t}\n received ${n}`,v=(e,t,n,r)=>{let i=[...new Set(e.map(e=>e.key))],a=()=>Object.fromEntries(i.map(i=>[i,p(h(e,i,t,n,r),r)])),o={frames:r,rows:a,expect:e=>{let t=a();for(let[n,a]of Object.entries(e)){let e=g(i,n),[o]=e;if(o===void 0)throw Error(`marble row "${n}" matches no task; rows: ${i.join(`, `)||`none`}`);if(e.length>1)throw Error(`marble row "${n}" matches more than one task (${e.join(`, `)}): give the full key`);let s=p(f(a),r);if(s!==t[o])throw Error(_(o,s,t[o]??``))}return o}};return o},y=r=>{let{clock:i,frame:a=10,...s}=r,c=[],l=e=>{e.effect!==`emit`&&c.push({key:`${e.type}:${e.effect}`,letter:o(e.phase),at:i.now()})},u=e({...s,trace:n(l)});return u.use(t()),{bus:u,run:async({emits:e={},frames:t}={})=>{let n=Object.entries(e).map(([e,t])=>({event:e,frames:d(t.marble),values:t.values})),r=t??Math.max(0,...n.map(e=>e.frames.length));c.length=0;let o=i.now();for(let e=0;e<r;e+=1){for(let t of n)for(let n of t.frames[e]??[])Reflect.apply(u.emit,u,[t.event,m(t.values,n)]);await i.advance(a)}return v(c,o,a,r)}}};export{y as createMarbleBus,r as fakeTimersClock};
1
+ import{t as e}from"./bus-Cmk4U1hQ.js";import{n as t,t as n}from"./tracer-v7m-Qah_.js";const r=e=>({advance:t=>e.advanceTimersByTimeAsync(t).then(()=>{}),now:()=>Date.now()}),i={start:`s`,done:`d`,error:`e`,cancel:`c`,drop:`x`},a=new Set(Object.values(i)),o=e=>i[e],s=(e,t,n)=>{throw Error(`marble "${e}": ${n} at position ${t}`)},c=(e,t,n)=>{for(let r=0;r<n.length;r+=1){let i=n.charAt(r);(/\s/.test(i)||i===`|`)&&s(e,t+r,`"${i.trim()||`space`}" is not part of a diagram`)}},l=(e,t)=>{let n=e.indexOf(`)`,t);n<0&&s(e,t,`a group that is not closed with ")"`);let r=e.slice(t+1,n);r===``&&s(e,t,`an empty group`);let i=r.indexOf(`(`);i>=0&&s(e,t+1+i,`a group inside a group`);let a=r.indexOf(`-`);return a>=0&&s(e,t+1+a,`"-" inside a group`),c(e,t+1,r),{frame:[...r],next:n+1}},u=(e,t)=>{let n=e.charAt(t);return n===`(`?l(e,t):(n===`)`&&s(e,t,`")" without "("`),c(e,t,n),{frame:n===`-`?[]:[n],next:t+1})},d=e=>{let t=[],n=0;for(;n<e.length;){let{frame:r,next:i}=u(e,n);t.push(r),n=i}return t},f=e=>{let t=d(e),n=0;for(let r of t){for(let t of r)a.has(t)||s(e,n,`"${t}" is not a phase (s d e c x)`);n+=r.length||1}return t},p=(e,t)=>{let n=``;for(let r=0;r<t;r+=1){let t=e[r]??[];t.length===0?n+=`-`:t.length===1?n+=t[0]:n+=`(${t.join(``)})`}return n},m=(e,t)=>e&&Object.hasOwn(e,t)?e[t]:t,h=(e,t,n,r,i)=>{let a=Array.from({length:i},()=>[]);for(let o of e){let e=Math.floor((o.at-n)/r);o.key===t&&e>=0&&e<i&&a[e]?.push(o.letter)}return a},g=(e,t)=>t.includes(`:`)?e.includes(t)?[t]:[]:e.filter(e=>e.endsWith(`:${t}`)),_=(e,t,n)=>`marble row "${e}" differs\n expected ${t}\n received ${n}`,v=(e,t,n,r)=>{let i=[...new Set(e.map(e=>e.key))],a=()=>Object.fromEntries(i.map(i=>[i,p(h(e,i,t,n,r),r)])),o={frames:r,rows:a,expect:e=>{let t=a();for(let[n,a]of Object.entries(e)){let e=g(i,n),[o]=e;if(o===void 0)throw Error(`marble row "${n}" matches no task; rows: ${i.join(`, `)||`none`}`);if(e.length>1)throw Error(`marble row "${n}" matches more than one task (${e.join(`, `)}): give the full key`);let s=p(f(a),r);if(s!==t[o])throw Error(_(o,s,t[o]??``))}return o}};return o},y=r=>{let{clock:i,frame:a=10,...s}=r,c=[],l=e=>{e.effect!==`emit`&&c.push({key:`${e.type}:${e.effect}`,letter:o(e.phase),at:i.now()})},u=e({...s,trace:n(l)});return u.use(t()),{bus:u,run:async({emits:e={},frames:t}={})=>{let n=Object.entries(e).map(([e,t])=>({event:e,frames:d(t.marble),values:t.values})),r=t??Math.max(0,...n.map(e=>e.frames.length));c.length=0;let o=i.now();for(let e=0;e<r;e+=1){for(let t of n)for(let n of t.frames[e]??[])Reflect.apply(u.emit,u,[t.event,m(t.values,n)]);await i.advance(a)}return v(c,o,a,r)}}};export{y as createMarbleBus,r as fakeTimersClock};
package/dist/trace.d.ts CHANGED
@@ -136,6 +136,141 @@ type GraphLogger = TraceLogger & {
136
136
  */
137
137
  export declare const graphLogger: (options?: GraphLoggerOptions) => GraphLogger;
138
138
  //#endregion
139
+ //#region src/graph/merge.d.ts
140
+ /**
141
+ * Joins the graphs of several runs (tests, e2e, a manual session) into one, so a
142
+ * listener or an edge that no single run reached can still be seen by another.
143
+ * Counts add up, nodes and edges are the union, and a cycle found twice is one
144
+ * cycle. The snapshots you pass are not changed.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * import { mergeGraphs } from "nanoeffects/trace";
149
+ *
150
+ * // each run wrote `graph.toJSON()` to a file
151
+ * const all = mergeGraphs(unitRun, e2eRun);
152
+ * ```
153
+ */
154
+ export declare const mergeGraphs: (...snapshots: GraphSnapshot[]) => GraphSnapshot;
155
+ //#endregion
156
+ //#region src/graph/orphans.d.ts
157
+ /**
158
+ * A listener that the graph never saw run. `unemitted`: the graph has no node for
159
+ * the event, so nobody emitted it. `unrun`: the event was emitted, this listener
160
+ * did not run.
161
+ */
162
+ type Orphan = {
163
+ event: string;
164
+ listener: string;
165
+ kind: "unemitted" | "unrun";
166
+ };
167
+ /**
168
+ * Compares the listeners a bus has with the graph of what ran, and lists the
169
+ * listeners the graph never saw. Pass `describeBus(bus)` (with or without `source`) and
170
+ * `graph.toJSON()`, or the result of `mergeGraphs` for wider coverage. A listener
171
+ * is a node of the graph once it has run, by its `traceId` or function name;
172
+ * anonymous listeners have no node and are left out. One run shows many false
173
+ * orphans: read the list as a hint, not as a failure.
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * import { describeBus, findOrphans } from "nanoeffects/trace";
178
+ *
179
+ * const described = describeBus(bus);
180
+ * const orphans = findOrphans(described, graph.toJSON());
181
+ * // [{ event: "cart/cleared", listener: "reset", kind: "unemitted" }]
182
+ * ```
183
+ */
184
+ export declare const findOrphans: (described: Readonly<Record<string, readonly string[]>>, snapshot: GraphSnapshot) => Orphan[];
185
+ //#endregion
186
+ //#region src/trace/task-index.d.ts
187
+ /** What the `task` hook told about one task, also a task that reports no event. */
188
+ type KnownTask = {
189
+ type: string;
190
+ parentId?: number;
191
+ source?: string;
192
+ traceGroupId?: string;
193
+ };
194
+ //#endregion
195
+ //#region src/trace/recorder.d.ts
196
+ type Recorder<E = Record<string, unknown>> = TraceLogger<E> & {
197
+ /**
198
+ * The events received so far, oldest first. Without a `capacity` it is one
199
+ * live array; with one, each read is a new array that is a snapshot.
200
+ */
201
+ readonly events: TraceEvent<E>[];
202
+ /**
203
+ * The tasks the tracer told about, by `id`, also the ones that report no event (a plain
204
+ * listener). `chainOf` reads them to keep a path whole. Cut by `capacity` like `events`.
205
+ */
206
+ readonly tasks: ReadonlyMap<number, KnownTask>;
207
+ clear: () => void;
208
+ /**
209
+ * The events as plain data that `JSON.stringify` takes: the payload and the error are made safe, so a
210
+ * circular object, an `Error`, a `Map` or a class instance cannot break it. `JSON.stringify(recorder)` uses it.
211
+ */
212
+ toJSON: () => JsonValue[];
213
+ };
214
+ /**
215
+ * Trace logger that keeps events in memory. With no option it keeps all of
216
+ * them, for tests. With `capacity` it keeps the last events, to send when
217
+ * something goes wrong.
218
+ *
219
+ * `payload` and `error` are kept as they are, and can hold private data: cut
220
+ * what you send. An event has no time, and a `parentId` can name an event that
221
+ * was pushed out: read it as a root.
222
+ *
223
+ * @example
224
+ * ```ts
225
+ * const recorder = createTraceRecorder<Events>();
226
+ * const bus = createBus<Events>({ trace: createTracer(recorder) });
227
+ *
228
+ * bus.emit("search", "re");
229
+ * bus.emit("search", "redux");
230
+ * recorder.events.map((e) => e.phase); // ["start", "cancel", "start", "done"]
231
+ *
232
+ * const lastEvents = createTraceRecorder<Events>({ capacity: 500 });
233
+ * ```
234
+ */
235
+ export declare const createTraceRecorder: <E = Record<string, unknown>>(
236
+ /** `capacity`: keep the last N events (a ring buffer); not a positive integer, or left out: keep all. */
237
+ options?: {
238
+ capacity?: number;
239
+ }) => Recorder<E>;
240
+ //#endregion
241
+ //#region src/trace/chain.d.ts
242
+ /** One task on the way from the root to the task you asked about. */
243
+ type ChainStep = {
244
+ id: number;
245
+ type: string;
246
+ /** Absent for a task that reported no event (a plain listener). */
247
+ effect?: EffectName;
248
+ /** The latest phase of the task; absent when it reported no event. */
249
+ phase?: Phase;
250
+ source?: string;
251
+ traceGroupId?: string;
252
+ };
253
+ type ChainSource<E> = readonly TraceEvent<E>[] | Pick<Recorder<E>, "events" | "tasks">;
254
+ /**
255
+ * The causal path of a task: the tasks that led to it, from the root, ending
256
+ * with the task itself. Use it to answer "what started the task that failed".
257
+ *
258
+ * Give it a recorder to keep the listeners that report no event in the path;
259
+ * a plain list of events (a snapshot, a file read back) shows only the tasks
260
+ * that have events.
261
+ *
262
+ * A parent that is not known (pushed out by a `capacity`) ends the path:
263
+ * it starts at the oldest task that is known. An unknown `id` gives `[]`.
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * const failed = recorder.events.find((event) => event.phase === "error");
268
+ * const path = chainOf(recorder, failed.id);
269
+ * path.map((step) => step.type).join(" → "); // "queryChanged → searchLoaded"
270
+ * ```
271
+ */
272
+ export declare const chainOf: <E = Record<string, unknown>>(source: ChainSource<E>, id: number) => ChainStep[];
273
+ //#endregion
139
274
  //#region src/trace/console.d.ts
140
275
  type ConsoleLoggerOptions = {
141
276
  /** Defaults to `globalThis.console`. */
@@ -144,6 +279,8 @@ type ConsoleLoggerOptions = {
144
279
  prefix?: string;
145
280
  /** Append where the listener was registered, to the lines of events that have it. Default `false`. */
146
281
  source?: boolean;
282
+ /** Append the path from the root, with the listeners that report nothing, to the line of an `error`. Default `false`. */
283
+ chain?: boolean;
147
284
  };
148
285
  /**
149
286
  * Trace logger that prints one line per phase, indented by task depth.
@@ -251,47 +388,6 @@ type TracePluginOptions = {
251
388
  */
252
389
  export declare const tracePlugin: (options?: TracePluginOptions) => <E extends EventMap>(bus: Bus<E>) => Bus<E>;
253
390
  //#endregion
254
- //#region src/trace/recorder.d.ts
255
- type Recorder<E = Record<string, unknown>> = TraceLogger<E> & {
256
- /**
257
- * The events received so far, oldest first. Without a `capacity` it is one
258
- * live array; with one, each read is a new array that is a snapshot.
259
- */
260
- readonly events: TraceEvent<E>[];
261
- clear: () => void;
262
- /**
263
- * The events as plain data that `JSON.stringify` takes: the payload and the error are made safe, so a
264
- * circular object, an `Error`, a `Map` or a class instance cannot break it. `JSON.stringify(recorder)` uses it.
265
- */
266
- toJSON: () => JsonValue[];
267
- };
268
- /**
269
- * Trace logger that keeps events in memory. With no option it keeps all of
270
- * them, for tests. With `capacity` it keeps the last events, to send when
271
- * something goes wrong.
272
- *
273
- * `payload` and `error` are kept as they are, and can hold private data: cut
274
- * what you send. An event has no time, and a `parentId` can name an event that
275
- * was pushed out: read it as a root.
276
- *
277
- * @example
278
- * ```ts
279
- * const recorder = createTraceRecorder<Events>();
280
- * const bus = createBus<Events>({ trace: createTracer(recorder) });
281
- *
282
- * bus.emit("search", "re");
283
- * bus.emit("search", "redux");
284
- * recorder.events.map((e) => e.phase); // ["start", "cancel", "start", "done"]
285
- *
286
- * const lastEvents = createTraceRecorder<Events>({ capacity: 500 });
287
- * ```
288
- */
289
- export declare const createTraceRecorder: <E = Record<string, unknown>>(
290
- /** `capacity`: keep the last N events (a ring buffer); not a positive integer, or left out: keep all. */
291
- options?: {
292
- capacity?: number;
293
- }) => Recorder<E>;
294
- //#endregion
295
391
  //#region src/trace/redux.d.ts
296
392
  type ReduxConnection = {
297
393
  init: (state: unknown) => void;
@@ -389,6 +485,57 @@ type ReduxDevtoolsState = {
389
485
  */
390
486
  export declare const reduxDevtools: (options?: ReduxDevtoolsOptions) => TraceLogger;
391
487
  //#endregion
488
+ //#region src/trace/timing.d.ts
489
+ /** One task of the trace with the time it took, or the time since it started. */
490
+ type TimedTask = {
491
+ id: number;
492
+ type: string;
493
+ effect: EffectName;
494
+ parentId?: number;
495
+ rootId?: number;
496
+ source?: string;
497
+ /** Milliseconds from `start` to the closing phase, or to now for an open task. */
498
+ ms: number;
499
+ };
500
+ /** A task that closed: how it ended and how long it took. */
501
+ type ClosedTask = TimedTask & {
502
+ phase: Exclude<Phase, "start">;
503
+ };
504
+ type TimingLoggerOptions = {
505
+ /** The clock, in ms. Default `performance.now`, or `Date.now` where there is none. */
506
+ now?: () => number;
507
+ /** Keep only the last N closed tasks in `durations`. `pending()` is never cut. Not a positive integer, or left out: keep all. */
508
+ capacity?: number;
509
+ };
510
+ type TimingLogger = TraceLogger & {
511
+ /** The tasks that closed, oldest closed first. One live array. */
512
+ readonly durations: ClosedTask[];
513
+ /** The tasks that started and have not closed, oldest started first, with the time since `start`. */
514
+ pending: () => TimedTask[];
515
+ clear: () => void;
516
+ };
517
+ /**
518
+ * Trace logger that measures time. It stamps each event when it gets it,
519
+ * pairs `start` with the first `done`, `error`, `cancel` or `drop` of the same
520
+ * task and effect, and keeps the result. Use it to find a slow handler, to see
521
+ * how long a request lived before `cancel`, or to check that a test left
522
+ * no task open.
523
+ *
524
+ * The logger sees what the tracer lets through: a task whose `start` was
525
+ * filtered or not sampled never pairs, and its closing event is ignored.
526
+ *
527
+ * @example
528
+ * ```ts
529
+ * const timing = timingLogger();
530
+ * const bus = createBus<Events>({ trace: createTracer(timing) });
531
+ *
532
+ * bus.emit("search", "redux");
533
+ * timing.pending(); // [{ id: 1, type: "search", effect: "latest", ms: 0 }]
534
+ * timing.durations; // after it ends: [{ ..., phase: "done", ms: 120 }]
535
+ * ```
536
+ */
537
+ export declare const timingLogger: (options?: TimingLoggerOptions) => TimingLogger;
538
+ //#endregion
392
539
  //#region src/trace/tracer.d.ts
393
540
  type TracerOptions = {
394
541
  /** Drops the events it returns `false` for, before any logger sees them. */
@@ -424,4 +571,4 @@ type TracerOptions = {
424
571
  */
425
572
  export declare const createTracer: <E = Record<string, unknown>>(trace: Trace<E>, options?: TracerOptions) => Tracer;
426
573
  //#endregion
427
- export type { ConsoleLoggerOptions, DescribeBusOptions, EffectName, ExportOptions, Finding, GraphLogger, GraphLoggerOptions, GraphSnapshot, JsonOptions, JsonValue, PayloadMode, PerformanceLoggerOptions, Phase, PolicyStage, PolicyStages, Recorder, ReduxDevtoolsOptions, ReduxDevtoolsState, ReduxExtension, SerializeOptions, TaskInfo, Trace, TraceEvent, TraceLogger, TracePluginOptions, Tracer, TracerOptions };
574
+ export type { ChainStep, ClosedTask, ConsoleLoggerOptions, DescribeBusOptions, EffectName, ExportOptions, Finding, GraphLogger, GraphLoggerOptions, GraphSnapshot, JsonOptions, JsonValue, Orphan, PayloadMode, PerformanceLoggerOptions, Phase, PolicyStage, PolicyStages, Recorder, ReduxDevtoolsOptions, ReduxDevtoolsState, ReduxExtension, SerializeOptions, TaskInfo, TimedTask, TimingLogger, TimingLoggerOptions, Trace, TraceEvent, TraceLogger, TracePluginOptions, Tracer, TracerOptions };