nanoeffects 0.1.0 → 0.2.1

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 (52) hide show
  1. package/README.md +62 -61
  2. package/dist/{action-BM-UdmJr.d.ts → action-rqZEnRIp.d.ts} +12 -11
  3. package/dist/actions.d.ts +47 -185
  4. package/dist/actions.js +1 -1
  5. package/dist/bus-CRnlwmQ4.js +1 -0
  6. package/dist/context-DlA80GOA.js +1 -0
  7. package/dist/dev.d.ts +46 -0
  8. package/dist/dev.js +1 -0
  9. package/dist/effects.d.ts +61 -21
  10. package/dist/effects.js +1 -1
  11. package/dist/index.d.ts +1 -2
  12. package/dist/index.js +1 -1
  13. package/dist/module-BSCdR9D1.d.ts +167 -0
  14. package/dist/notrace/{action-BM-UdmJr.d.ts → action-rqZEnRIp.d.ts} +12 -11
  15. package/dist/notrace/actions.d.ts +71 -45
  16. package/dist/notrace/actions.js +1 -1
  17. package/dist/notrace/bus-Dx0l9X6h.js +1 -0
  18. package/dist/notrace/context-yAWj0BFZ.js +1 -0
  19. package/dist/notrace/{delay-Cko_Q9hl.js → delay-Cgvn16oY.js} +1 -1
  20. package/dist/notrace/effects.d.ts +61 -21
  21. package/dist/notrace/effects.js +1 -1
  22. package/dist/notrace/index.d.ts +1 -2
  23. package/dist/notrace/index.js +1 -1
  24. package/dist/notrace/policies.d.ts +1 -1
  25. package/dist/notrace/policies.js +1 -1
  26. package/dist/notrace/redux.d.ts +2 -28
  27. package/dist/notrace/redux.js +1 -1
  28. package/dist/observable.d.ts +1 -1
  29. package/dist/policies.d.ts +1 -1
  30. package/dist/policies.js +1 -1
  31. package/dist/production/dev.js +1 -0
  32. package/dist/redux.d.ts +2 -28
  33. package/dist/redux.js +1 -1
  34. package/dist/trace.d.ts +22 -4
  35. package/dist/trace.js +1 -1
  36. package/docs/README.md +4 -1
  37. package/docs/actions.md +21 -11
  38. package/docs/context.md +0 -1
  39. package/docs/effects.md +49 -31
  40. package/docs/errors.md +4 -4
  41. package/docs/guide.md +229 -0
  42. package/docs/hmr.md +20 -58
  43. package/docs/policies.md +4 -4
  44. package/docs/stores.md +0 -2
  45. package/docs/tracing.md +21 -8
  46. package/package.json +25 -5
  47. package/dist/bus-RUiw8f9p.js +0 -1
  48. package/dist/context-BXQ6Einm.js +0 -1
  49. package/dist/index-CaxrMD1A.d.ts +0 -1
  50. package/dist/notrace/bus-CFxgpsRL.js +0 -1
  51. package/dist/notrace/context-DGPIFXxI.js +0 -1
  52. package/dist/notrace/index-CaxrMD1A.d.ts +0 -1
package/dist/effects.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { A as Keys, k as EventMap, u as Context } from "./action-BM-UdmJr.js";
1
+ import { A as Keys, N as Task, k as EventMap, u as Context } from "./action-rqZEnRIp.js";
2
2
  //#region src/utils/delay.d.ts
3
3
  /**
4
4
  * Resolves after `ms`, or rejects early if `ctx.signal` aborts. `ms` can be a
@@ -129,30 +129,36 @@ type PollOptions = {
129
129
  waitForFn?: boolean;
130
130
  };
131
131
  /**
132
- * Calls `fn` every `ms`, like patronum `interval`: the first call comes after
133
- * `ms` (with `leading` also at once), and the next ticks keep a steady rate
134
- * whatever the duration of `fn`, so a slow `fn` may overlap with the next call
135
- * (`waitForFn` starts each pause when the call ends instead). `fn` gets the
136
- * number of the call, starting at 0.
132
+ * Calls a function every `ms`, like patronum `interval`: the first call comes
133
+ * after `ms` (with `leading` also at once), and the next ticks keep a steady
134
+ * rate whatever the duration of the function, so a slow one may overlap with
135
+ * the next call (`waitForFn` starts each pause when the call ends instead). An
136
+ * error stops the polling and rejects; an abort of the caller ends it without
137
+ * an error and clears the timer. Two forms:
138
+ *
139
+ * - `poll(ms, task, options)` wraps a Task `(payload, ctx) => result` and
140
+ * returns a Task. Each call gets a context of its own, a child of the
141
+ * caller's: `bus.on("watch", poll(10_000, refresh))`.
142
+ * - `poll(ctx, fn, ms, options)` is for one call inside a body; `fn` gets the
143
+ * number of the call, starting at 0.
137
144
  *
138
145
  * `ms` can be a function of the number of the call that the pause leads to, for
139
146
  * a growing or random pause: `(call) => Math.min(1000 * 2 ** call, 60_000)`.
140
147
  *
141
- * It stops when `ctx` aborts: the result then resolves, it does not reject, and
142
- * the pending timer is cleared. If a call throws, polling stops and the result
143
- * rejects.
144
- *
145
148
  * @example
146
149
  * ```ts
150
+ * bus.on("watch", poll(10_000, (_, { signal }) => refresh({ signal })));
151
+ *
147
152
  * bus.on("watch", async (_, ctx) => {
148
- * await poll(ctx, () => refresh(), 5000);
149
- * cleanup(); // the task was aborted
153
+ * await poll(ctx, () => refresh(), 10_000);
150
154
  * });
151
155
  * ```
152
156
  */
153
- export declare const poll: (ctx: {
157
+ type PollMs = number | ((call: number) => number);
158
+ export declare function poll<P, E extends EventMap, R>(ms: PollMs, task: Task<P, E, R>, options?: PollOptions): Task<P, E, Promise<void>>;
159
+ export declare function poll(ctx: {
154
160
  signal: AbortSignal;
155
- }, fn: (tick: number) => unknown, ms: number | ((call: number) => number), options?: PollOptions) => Promise<void>;
161
+ }, fn: (tick: number) => unknown, ms: PollMs, options?: PollOptions): Promise<void>;
156
162
  //#endregion
157
163
  //#region src/effects/race.d.ts
158
164
  type RaceStarter<T> = Starter<T>;
@@ -192,9 +198,33 @@ type RetryOptions = {
192
198
  /** Return `false` to stop retrying and throw `error`. Default: always retry. */
193
199
  shouldRetry?: (error: unknown, attempt: number) => boolean;
194
200
  };
195
- export declare const retry: <T>(ctx: {
201
+ /**
202
+ * Calls a function until it succeeds or `times` attempts are used, then throws
203
+ * the last error. If the caller aborts, retrying stops and the result rejects
204
+ * with the abort reason. Two forms:
205
+ *
206
+ * - `retry(task, options)` wraps a Task `(payload, ctx) => result` and returns
207
+ * a Task. Each attempt gets a context of its own, a child of the caller's, so
208
+ * it can go straight into `on` and into `ctx.run`:
209
+ * `bus.on("load", latest(retry(load, { times: 4 })))`. The number of the
210
+ * attempt is not passed; use the other form when it is needed.
211
+ * - `retry(ctx, fn, options)` is for one call inside a body. `fn` gets the
212
+ * number of the attempt, starting at 1.
213
+ *
214
+ * @example
215
+ * ```ts
216
+ * bus.on("load", latest(retry(loadUser, { times: 4, delay: (attempt) => 2 ** attempt * 100 })));
217
+ *
218
+ * bus.on("load", async (id, ctx) => {
219
+ * const user = await retry(ctx, () => fetchUser(id, { signal: ctx.signal }), { times: 4 });
220
+ * });
221
+ * ```
222
+ */
223
+ type RetryFn<T> = (attempt: number) => T | PromiseLike<T>;
224
+ export declare function retry<P, E extends EventMap, R>(task: Task<P, E, R>, options?: RetryOptions): Task<P, E, Promise<Awaited<R>>>;
225
+ export declare function retry<T>(ctx: {
196
226
  signal?: AbortSignal;
197
- }, fn: (attempt: number) => T | PromiseLike<T>, options?: RetryOptions) => Promise<T>;
227
+ }, fn: RetryFn<T>, options?: RetryOptions): Promise<T>;
198
228
  //#endregion
199
229
  //#region src/effects/take.d.ts
200
230
  type TakeOptions<P> = {
@@ -226,19 +256,29 @@ export declare const take: <E extends EventMap, K extends Keys<E>>(ctx: Context<
226
256
  //#endregion
227
257
  //#region src/effects/timeout.d.ts
228
258
  /**
229
- * Runs `starter`; if it takes longer than `ms`, aborts its signal and rejects
230
- * with a `TimeoutError` (a `DOMException`, like `AbortSignal.timeout`), even
231
- * if the starter ignores the signal. If `ctx` aborts, rejects with its reason.
259
+ * Runs a function; if it takes longer than `ms`, aborts its signal and rejects
260
+ * with a `TimeoutError` (a `DOMException`, like `AbortSignal.timeout`), even if
261
+ * it ignores the signal. If the caller aborts, rejects with its reason. Two
262
+ * forms:
263
+ *
264
+ * - `timeout(ms, task)` wraps a Task `(payload, ctx) => result` and returns a
265
+ * Task. The Task gets a context of its own whose `signal` the time limit
266
+ * aborts: `bus.on("load", latest(timeout(5000, load)))`.
267
+ * - `timeout(ctx, ms, starter)` is for one call inside a body; `starter` gets
268
+ * `{ signal, abort }`.
232
269
  *
233
270
  * @example
234
271
  * ```ts
272
+ * bus.on("load", timeout(5000, (id, { signal }) => fetchData(id, { signal })));
273
+ *
235
274
  * bus.on("load", async (id, ctx) => {
236
275
  * const data = await timeout(ctx, 5000, ({ signal }) => fetchData(id, { signal }));
237
276
  * });
238
277
  * ```
239
278
  */
240
- export declare const timeout: <T>(ctx: {
279
+ export declare function timeout<P, E extends EventMap, R>(ms: number, task: Task<P, E, R>): Task<P, E, Promise<Awaited<R>>>;
280
+ export declare function timeout<T>(ctx: {
241
281
  signal?: AbortSignal;
242
- }, ms: number, starter: Starter<T>) => Promise<T>;
282
+ }, ms: number, starter: Starter<T>): Promise<T>;
243
283
  //#endregion
244
284
  export type { CancellableExecutor, CancellableHandle, EffectContext, PollOptions, RaceStarter, RetryOptions, TakeOptions };
package/dist/effects.js CHANGED
@@ -1 +1 @@
1
- import{n as e,t}from"./onAbort-BgMfspK4.js";import{a as n,i as r,o as i,t as a}from"./context-BXQ6Einm.js";import{n as o,r as s,t as c}from"./delay-CIHnOh_L.js";const l=(e,n)=>n?.signal?new Promise((r,i)=>{let a=t(n,i);e.then(r,i).finally(a)}):e,u=e=>Array.isArray(e)?Array(e.length):{},d=(e,o,s)=>{s?.signal?.throwIfAborted();let c=r(s??{}),u=a(c.ctx,o);return i(c.ctx,o,`start`),t(c.ctx,()=>u(`cancel`)),{tasks:Object.entries(e).map(([e,t])=>{let i=r(c.ctx),a={signal:i.ctx.signal,abort:i.ctx.abort};return[e,new Promise(e=>e(n(i.ctx,`run`,()=>t(a)))).finally(i.unlink)]}),cancelAll:()=>c.ctx.abort(),unfollowParent:c.unlink,settle:u,until:e=>l(e,s)}};async function f(e,t){let n=d(t,`all`,e);try{let e=await n.until(Promise.all(n.tasks.map(([,e])=>e))),r=u(t);for(let[t,[i]]of n.tasks.entries())r[i]=e[t];return n.settle(`done`),r}catch(e){throw n.settle(`error`,e),n.cancelAll(),e}finally{n.unfollowParent()}}const p=e=>e.then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}));async function m(e,t){let n=d(t,`allSettled`,e);try{let e=await n.until(Promise.all(n.tasks.map(([,e])=>p(e)))),r=u(t);for(let[t,[i]]of n.tasks.entries())r[i]=e[t];return n.settle(`done`),r}catch(e){throw n.settle(`error`,e),n.cancelAll(),e}finally{n.unfollowParent()}}const h=(n,r)=>n.signal.aborted?Promise.reject(n.signal.reason):new Promise((i,a)=>{let o=[],s=`pending`,c=t=>{try{t()}catch(t){e(`cancel cleanup failed`,t)}},l=t(n,e=>{s=`cancelled`;for(let e of o.reverse())c(e);a(e)}),u=e=>(...t)=>{s===`pending`&&(s=`settled`,l(),o.length=0,e(...t))},d=e=>{s===`pending`?o.push(e):s===`cancelled`&&c(e)};try{r({resolve:u(i),reject:u(a),onCancel:d})}catch(e){u(a)(e)}}),g=async(e,n,o)=>{n?.signal?.throwIfAborted();let{ctx:s,unlink:c}=r(n??{}),u=a(s,e);i(s,e,`start`),t(s,()=>u(`cancel`));try{let e=await l(o(s),n);return u(`done`),e}catch(e){throw u(`error`,e),e}finally{c()}},_=async(e,t)=>{let{ctx:i,unlink:a}=r(e);try{return await n(i,`run`,t)}finally{a()}},v=(e,n,r,i={})=>{if(e.signal.aborted)return Promise.resolve();let a=i.leading??!1,c=i.waitForFn??!1;return g(`poll`,e,e=>new Promise((i,l)=>{let u=0,d=null,f=()=>{d!==null&&(o(d),d=null)},p=e=>{try{d=s(m,typeof r==`function`?r(e):r)}catch(e){f(),l(e)}},m=()=>{d=null,c||p(u+1),h()},h=()=>{let t=u++;_(e,()=>n(t)).then(()=>{c&&!e.signal.aborted&&p(u)},e=>{f(),l(e)})};t(e,f),a?(h(),c||p(u)):p(0)})).catch(t=>{if(!e.signal.aborted)throw t})};async function y(e,t){let n=u(t);if(Object.keys(t).length===0)return n;let r=d(t,`race`,e);try{let[e,t]=await r.until(Promise.race(r.tasks.map(([e,t])=>t.then(t=>[e,t]))));return n[e]=t,r.settle(`done`),n}catch(e){throw r.settle(`error`,e),e}finally{r.unfollowParent(),r.cancelAll()}}const b=(e,t,n)=>typeof e==`function`?e(t,n):e,x=e=>({times:e.times??3,delay:e.delay??0,shouldRetry:e.shouldRetry??(()=>!0)}),S=(e,t,n={})=>g(`retry`,e,async e=>{let{times:r,delay:i,shouldRetry:a}=x(n);for(let n=1;;n++)try{return await _(e,()=>t(n))}catch(t){if(e.signal.throwIfAborted(),n>=r||!a(t,n))throw t;let o=b(i,n,t);o>0&&await c(e,o)}}),C=(e,n,r={})=>g(`take`,e,i=>new Promise((a,o)=>{let{predicate:s}=r,c=[],l=()=>{for(let e of c)e()},u=e=>{l(),o(e)};c.push(e.on(n,e=>{(!s||s(e))&&(l(),a(e))})),c.push(t(i,u)),c.push(t({signal:r.signal},u))})),w=(e,t,i)=>g(`timeout`,e,async e=>{let a=r(e),c=s(()=>a.ctx.abort(new DOMException(`Timed out after ${t}ms`,`TimeoutError`)),t);try{return await l(Promise.resolve(n(a.ctx,`run`,()=>i({signal:a.ctx.signal,abort:a.ctx.abort}))),a.ctx)}finally{o(c),a.unlink()}});export{f as all,m as allSettled,h as cancellable,c as delay,t as onAbort,v as poll,y as race,S as retry,C as take,w as timeout};
1
+ import{n as e,t}from"./onAbort-BgMfspK4.js";import{a as n,i as r,o as i,t as a}from"./context-DlA80GOA.js";import{n as o,r as s,t as c}from"./delay-CIHnOh_L.js";const l=(e,n)=>n?.signal?new Promise((r,i)=>{let a=t(n,i);e.then(r,i).finally(a)}):e,u=async(e,n,o,s)=>{n?.signal?.throwIfAborted();let{ctx:c,unlink:u}=r(n??{}),d=a(c,e);i(c,e,`start`),t(c,()=>d(`cancel`));try{let e=await l(o(c),n);return d(`done`),s?.(!1),e}catch(e){throw d(`error`,e),s?.(!0),e}finally{u()}},d=async(e,t)=>{let{ctx:i,unlink:a}=r(e);try{return await n(i,`run`,()=>t(i))}finally{a()}},f=e=>e,p=(e,t)=>n=>e(t,f(n)),m=e=>Array.isArray(e)?Array(e.length):{},h=(e,t)=>{let i=Object.entries(t).map(([t,i])=>{let a=r(e),o={signal:a.ctx.signal,abort:a.ctx.abort},s=()=>i(o);return{key:t,task:new Promise(e=>e(n(a.ctx,`run`,s))).finally(a.unlink),cancel:a.ctx.abort}});return{tasks:i.map(({key:e,task:t})=>[e,t]),cancelAll:()=>{for(let e of i)e.cancel()}}},g=(e,t,n,r,i)=>{let a=()=>{};return u(e,t,async e=>{let t=h(e,n);return a=t.cancelAll,r(t.tasks)},e=>{(e||i===`end`)&&a()})};function _(e,t){return g(`all`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>e)),r=m(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`)}const v=e=>e.then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}));function y(e,t){return g(`allSettled`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>v(e))),r=m(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`)}const b=(n,r)=>n.signal.aborted?Promise.reject(n.signal.reason):new Promise((i,a)=>{let o=[],s=`pending`,c=t=>{try{t()}catch(t){e(`cancel cleanup failed`,t)}},l=t(n,e=>{s=`cancelled`;for(let e of o.reverse())c(e);a(e)}),u=e=>(...t)=>{s===`pending`&&(s=`settled`,l(),o.length=0,e(...t))},d=e=>{s===`pending`?o.push(e):s===`cancelled`&&c(e)};try{r({resolve:u(i),reject:u(a),onCancel:d})}catch(e){u(a)(e)}}),x=(e,n,r,i)=>{if(e.signal.aborted)return Promise.resolve();let a=i.leading??!1,c=i.waitForFn??!1;return u(`poll`,e,e=>new Promise((i,l)=>{let u=0,f=null,p=()=>{f!==null&&(o(f),f=null)},m=e=>{try{f=s(h,typeof r==`function`?r(e):r)}catch(e){p(),l(e)}},h=()=>{f=null,c||m(u+1),g()},g=()=>{let t=u++;d(e,e=>n(e,t)).then(()=>{c&&!e.signal.aborted&&m(u)},e=>{p(),l(e)})};t(e,p),a?(g(),c||m(u)):m(0)})).catch(t=>{if(!e.signal.aborted)throw t})};function S(e,t,n,r={}){if(typeof e!=`object`){let r=t,i=n??{};return(t,n)=>x(n,p(r,t),e,i)}let i=t;return x(e,(e,t)=>i(t),n,r)}function C(e,t){let n=m(t);return Object.keys(t).length===0?Promise.resolve(n):g(`race`,e,t,async e=>{let[t,r]=await Promise.race(e.map(([e,t])=>t.then(t=>[e,t])));return n[t]=r,n},`end`)}const w=(e,t,n)=>typeof e==`function`?e(t,n):e,T=e=>({times:e.times??3,delay:e.delay??0,shouldRetry:e.shouldRetry??(()=>!0)}),E=(e,t,n)=>u(`retry`,e,async e=>{let{times:r,delay:i,shouldRetry:a}=T(n);for(let n=1;;n++)try{return await d(e,e=>t(e,n))}catch(t){if(e.signal.throwIfAborted(),n>=r||!a(t,n))throw t;let o=w(i,n,t);o>0&&await c(e,o)}});function D(e,t,n={}){if(typeof e==`function`){let n=e;return(e,r)=>E(r,p(n,e),t??{})}let r=t;return E(e,(e,t)=>r(t),n)}const O=(e,n,r={})=>u(`take`,e,i=>new Promise((a,o)=>{let{predicate:s}=r,c=[],l=()=>{for(let e of c)e()},u=e=>{l(),o(e)};c.push(e.on(n,e=>{(!s||s(e))&&(l(),a(e))})),c.push(t(i,u)),c.push(t({signal:r.signal},u))})),k=(e,t,i)=>u(`timeout`,e,async e=>{let a=r(e),c=s(()=>a.ctx.abort(new DOMException(`Timed out after ${t}ms`,`TimeoutError`)),t);try{return await l(Promise.resolve(n(a.ctx,`run`,()=>i(a.ctx))),a.ctx)}finally{o(c),a.unlink()}});function A(e,t,n){if(typeof e==`number`){let n=t;return(t,r)=>k(r,e,p(n,t))}let r=t,i=n;return k(e,r,e=>i({signal:e.signal,abort:e.abort}))}export{_ as all,y as allSettled,b as cancellable,c as delay,t as onAbort,S as poll,C as race,D as retry,O as take,A as timeout};
package/dist/index.d.ts CHANGED
@@ -1,3 +1,2 @@
1
- import { A as Keys, C as WithPayload, D as anyEventType, E as Tracer, F as TraceEvent, I as TraceLogger, L as UnsubscribeCallback, M as Phase, N as Task, O as EffectName, P as Trace, S as WithContext, T as createBus, _ as EventPayload, a as AnyEvent, b as Off, c as Command, d as ContextOf, f as ContextOption, g as EventLike, h as EventKey, i as Action, j as PayloadOf, k as EventMap, l as Commands, m as Emittable, o as Bus, p as Emit, s as BusOptions, u as Context, v as Handler, w as WithType, x as On, y as HandlerRef } from "./action-BM-UdmJr.js";
2
- import "./index-CaxrMD1A.js";
1
+ import { A as Keys, C as WithPayload, D as anyEventType, E as Tracer, F as TraceEvent, I as TraceLogger, L as UnsubscribeCallback, M as Phase, N as Task, O as EffectName, P as Trace, S as WithContext, T as createBus, _ as EventPayload, a as AnyEvent, b as Off, c as Command, d as ContextOf, f as ContextOption, g as EventLike, h as EventKey, i as Action, j as PayloadOf, k as EventMap, l as Commands, m as Emittable, o as Bus, p as Emit, s as BusOptions, u as Context, v as Handler, w as WithType, x as On, y as HandlerRef } from "./action-rqZEnRIp.js";
3
2
  export { type Action, type AnyEvent, type Bus, type BusOptions, type Command, type Commands, type Context, type ContextOf, type ContextOption, type EffectName, type Emit, type Emittable, type EventKey, type EventLike, type EventMap, type EventPayload, type Handler, type HandlerRef, type Keys, type Off, type On, type PayloadOf, type Phase, type Task, type Trace, type TraceEvent, type TraceLogger, type Tracer, type UnsubscribeCallback, type WithContext, type WithPayload, type WithType, anyEventType, createBus };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- export{n as anyEventType,t as createBus}from"./bus-RUiw8f9p.js";
1
+ export{n as anyEventType,t as createBus}from"./bus-CRnlwmQ4.js";
@@ -0,0 +1,167 @@
1
+ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as EventMap, o as Bus, u as Context } from "./action-rqZEnRIp.js";
2
+ //#region src/actions/command.d.ts
3
+ /**
4
+ * Creates a command: a typed request for a result. `bus.emit(command, payload)`
5
+ * runs its handler as a task, with a context, and returns what the handler
6
+ * returns. Listeners of the command's type are told first, as for any event.
7
+ *
8
+ * The handler is optional. A command without one is only a contract, and the
9
+ * bus gets its implementation from the `commands` registry (see
10
+ * `createCommands` and `bindHandler`). A handler bound there wins over the one
11
+ * the command was created with, so a test can give a bus its own implementation.
12
+ *
13
+ * A handler can be wrapped in a policy, e.g. `latest(fn)`. Calling the command
14
+ * directly, `command(payload)`, runs its own handler outside of any bus.
15
+ *
16
+ * @example
17
+ * ```ts
18
+ * const getUser = createCommand("user/get", (id: string, { signal }) =>
19
+ * fetchUser(id, { signal }),
20
+ * );
21
+ * const sendMail = createCommand<Mail, void>("mail/send"); // implemented elsewhere
22
+ *
23
+ * const commands = createCommands([bindHandler(sendMail, smtpSend)]);
24
+ * const bus = createBus({ commands });
25
+ * const user = await bus.emit(getUser, "1");
26
+ *
27
+ * commands.handle(getUser, async () => fakeUser); // in a test
28
+ * ```
29
+ */
30
+ declare const createCommand: <P = void, R = void, T extends string = string, E extends EventMap = EventMap>(type: T, handler?: Task<P, E, R>) => Command<P, R> & {
31
+ readonly type: T;
32
+ };
33
+ /** A command (or its type) with the handler to bind to it; `bindHandler` makes one. */
34
+ type Binding<E extends EventMap = EventMap> = readonly [Command<never, unknown> | string, Task<never, E, unknown>];
35
+ /**
36
+ * Pairs a command with the handler to bind to it, for `createCommands`. It
37
+ * checks that the handler fits the command.
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * createCommands([bindHandler(sendMail, smtpSend)]);
42
+ * ```
43
+ */
44
+ declare const bindHandler: <P, R, E extends EventMap>(command: Command<P, R>, fn: Task<P, E, R>) => Binding<E>;
45
+ /**
46
+ * The handlers bound to commands of `bus`: it makes the registry, sets it as
47
+ * the commands of the bus and returns it. Each bus has its own, so each test
48
+ * can have its own implementation. `handle` binds more later and returns the
49
+ * function that unbinds. A second `createCommands(bus)` replaces the registry
50
+ * of that bus.
51
+ *
52
+ * What the bus runs for a command: the handler bound last, else the one the
53
+ * command was created with, else it throws `No handler for command "..."`.
54
+ *
55
+ * @example
56
+ * ```ts
57
+ * const bus = createBus<Events>();
58
+ * const commands = createCommands(bus, [bindHandler(sendMail, smtpSend)]);
59
+ *
60
+ * const unbind = commands.handle(getUser, async () => fakeUser);
61
+ * unbind(); // the command's own handler is back
62
+ * ```
63
+ */
64
+ declare const createCommands: <E extends EventMap>(bus: Bus<E>, bindings?: readonly Binding<E>[]) => {
65
+ run: (command: Command, payload: unknown, ctx: unknown) => unknown;
66
+ handle: {
67
+ <P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
68
+ (type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
69
+ (bindings: readonly Binding<E>[]): UnsubscribeCallback;
70
+ };
71
+ };
72
+ //#endregion
73
+ //#region src/actions/module.d.ts
74
+ /**
75
+ * What a module's `setup` gets: the context of the module's task, so `on`,
76
+ * `emit` and `run` work as in a handler, plus `handle` to bind commands, `use`
77
+ * to mount sub-modules and `spawn` to start a background task. Everything the
78
+ * module does is undone when it is unmounted.
79
+ */
80
+ type ModuleContext<E extends EventMap = EventMap> = Context<E> & {
81
+ /** Binds the handler of a command, or a list of them; undone on unmount. */
82
+ handle<P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
83
+ handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
84
+ handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
85
+ /**
86
+ * Brings sub-modules and commands, in any order. A sub-module is mounted and
87
+ * unmounted with this one. A command is bound to the handler it carries, for
88
+ * as long as this module is mounted; a command that answers by itself keeps
89
+ * answering after the module is gone, since the handler is its own. The
90
+ * returned function undoes just this call, e.g. for what was added later from
91
+ * a listener.
92
+ */
93
+ use(...items: Array<Module<E> | Command<never, unknown>>): UnsubscribeCallback;
94
+ /**
95
+ * Starts a background task that lives as long as the module: it is aborted
96
+ * on unmount, and an error of it is left unhandled, as in any handler.
97
+ */
98
+ spawn<P>(fn: Task<P, E, unknown>, ...payload: PayloadOf<P>): void;
99
+ };
100
+ type Module<E extends EventMap = EventMap> = {
101
+ readonly name: string;
102
+ readonly setup: (m: ModuleContext<E>) => void;
103
+ };
104
+ /**
105
+ * Describes one domain of an app: the commands it handles, the events it
106
+ * listens to, its sub-modules and its background tasks. The `name` shows up as
107
+ * the type of the module's tasks in the trace.
108
+ *
109
+ * @example
110
+ * ```ts
111
+ * export const userModule = createModule<Events>("user", (m) => {
112
+ * m.handle(getUser, fetchUser);
113
+ * m.handle([bindHandler(sendMail, smtpSend)]);
114
+ * m.use(authModule);
115
+ *
116
+ * m.on(loginRequested, (user, ctx) => ctx.emit(userLoaded(user)));
117
+ * m.spawn(async (_, ctx) => {
118
+ * for (;;) await handleNext(await take(ctx, "job"));
119
+ * });
120
+ * });
121
+ * ```
122
+ */
123
+ declare const createModule: <E extends EventMap = EventMap>(name: string, setup: (m: ModuleContext<E>) => void) => Module<E>;
124
+ type Registry<E extends EventMap> = ReturnType<typeof createCommands<E>>;
125
+ /** What `modulePlugin` returns. */
126
+ type ModuleApi<E extends EventMap = EventMap> = {
127
+ /** The registry of command handlers of the bus: the one it was made with, or the app's own. */
128
+ commands: Registry<E>;
129
+ /** Mounts a module and returns the function that unmounts it; a module that is mounted already is not run again. */
130
+ mount(module: Module<E>): UnsubscribeCallback;
131
+ unmount(module: Module<E>): void;
132
+ isMounted(module: Module<E>): boolean;
133
+ /** Unmounts every module; a disposed app cannot mount modules. */
134
+ dispose(): void;
135
+ };
136
+ /**
137
+ * The plugin that assembles an app from modules: `bus.use(modulePlugin(modules))`
138
+ * mounts `modules` at once, in the order given, and returns `mount`, `unmount`,
139
+ * `isMounted`, `dispose` and `commands` for the modules that come and go later. The bus runs the commands that the
140
+ * modules bind: if `createCommands(bus)` was called before, that registry is
141
+ * used, otherwise the app attaches its own, as `app.commands`.
142
+ *
143
+ * A module is known by its `name`: mounting a module whose name is taken
144
+ * replaces the mounted one, which is unmounted first. That is what hot reload
145
+ * needs (see `docs/hmr.md`): the new version of a module file mounts again and
146
+ * the old version goes away with its subscriptions, commands and tasks.
147
+ *
148
+ * Unmounting undoes everything the module did: its subscriptions, its bound
149
+ * commands, its sub-modules and its background tasks. `dispose` unmounts them
150
+ * all, and a disposed app cannot mount modules.
151
+ *
152
+ * @example
153
+ * ```ts
154
+ * const bus = createBus<Events>();
155
+ * const app = bus.use(modulePlugin([userModule]));
156
+ *
157
+ * const unmount = app.mount(orderModule); // later, e.g. after a lazy import
158
+ * unmount(); // or app.unmount(orderModule)
159
+ *
160
+ * bus.emit(getUser, "1");
161
+ * app.commands.handle(getUser, fakeUser); // in a test
162
+ * app.dispose();
163
+ * ```
164
+ */
165
+ declare const modulePlugin: <E extends EventMap>(modules?: readonly Module<E>[]) => (bus: Bus<E>) => ModuleApi<E>;
166
+ //#endregion
167
+ export { modulePlugin as a, createCommand as c, createModule as i, createCommands as l, ModuleApi as n, Binding as o, ModuleContext as r, bindHandler as s, Module as t };
@@ -175,19 +175,19 @@ interface Bus<E extends EventMap> {
175
175
  on: On<E>;
176
176
  off: Off<E>;
177
177
  emit: Emit<E>;
178
- /** `BusOptions.context`, `.trace` and `.commands`, for what makes tasks of its own, like `registerModules`. */
178
+ /**
179
+ * Calls `plugin` with the bus and returns what it returns: an api, a
180
+ * function that undoes it. A plugin is any function of the bus; the bus keeps
181
+ * no list of them. See `modulePlugin` in `nanoeffects/actions`.
182
+ */
183
+ use<R>(plugin: (bus: Bus<E>) => R): R;
184
+ /** `BusOptions.context` and `.trace`, and `commands`, for what makes tasks of its own, like `modulePlugin`. */
179
185
  readonly context?: ContextOption<E> | undefined;
180
- /** What runs the commands; `registerModules` sets it when the bus was made without. */
186
+ /** What runs the commands; `createCommands(bus)` and `modulePlugin` set it. Without one a command runs its own handler. */
181
187
  commands?: Commands | undefined;
182
188
  readonly trace?: Tracer | undefined;
183
189
  }
184
190
  type BusOptions<E extends EventMap> = {
185
- /**
186
- * Runs commands: make it with `createCommands` from `nanoeffects/actions`.
187
- * Without it an event that is a function runs as it is, with the payload and
188
- * the task context.
189
- */
190
- commands?: Commands;
191
191
  /** Tracing of every task phase; make it with `createTracer` from `nanoeffects/trace`. */
192
192
  trace?: never;
193
193
  /**
@@ -214,9 +214,10 @@ type BusOptions<E extends EventMap> = {
214
214
  /**
215
215
  * Fields added to the context of every task of this bus, its child tasks
216
216
  * and the tasks of effects included: a store, a logger, a client. Their
217
- * types come from `WithContext` in the event map. The fields of the library win over
218
- * these when the names are the same. A function gets `{ type, payload }` of
219
- * the task and returns its fields, for fields that depend on the task.
217
+ * types come from `WithContext` in the event map. The fields of the library
218
+ * win over these when the names are the same. A function gets
219
+ * `{ type, payload }` of the task and returns its fields, for fields that
220
+ * depend on the task.
220
221
  */
221
222
  context?: ContextOption<E>;
222
223
  };
@@ -1,4 +1,4 @@
1
- import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as EventMap, m as Emittable, n as FreeActionCreator, o as Bus, r as createAction, t as ActionCreator, u as Context } from "./action-BM-UdmJr.js";
1
+ import { L as UnsubscribeCallback, N as Task, c as Command, j as PayloadOf, k as EventMap, n as FreeActionCreator, o as Bus, r as createAction, t as ActionCreator, u as Context } from "./action-rqZEnRIp.js";
2
2
  //#region src/actions/command.d.ts
3
3
  /**
4
4
  * Creates a command: a typed request for a result. `bus.emit(command, payload)`
@@ -43,23 +43,25 @@ type Binding<E extends EventMap = EventMap> = readonly [Command<never, unknown>
43
43
  */
44
44
  export declare const bindHandler: <P, R, E extends EventMap>(command: Command<P, R>, fn: Task<P, E, R>) => Binding<E>;
45
45
  /**
46
- * The handlers bound to commands, for `createBus({ commands })`. Each bus gets
47
- * its own, so each test can have its own implementation. `handle` binds more
48
- * later and returns the function that unbinds.
46
+ * The handlers bound to commands of `bus`: it makes the registry, sets it as
47
+ * the commands of the bus and returns it. Each bus has its own, so each test
48
+ * can have its own implementation. `handle` binds more later and returns the
49
+ * function that unbinds. A second `createCommands(bus)` replaces the registry
50
+ * of that bus.
49
51
  *
50
52
  * What the bus runs for a command: the handler bound last, else the one the
51
53
  * command was created with, else it throws `No handler for command "..."`.
52
54
  *
53
55
  * @example
54
56
  * ```ts
55
- * const commands = createCommands([bindHandler(sendMail, smtpSend)]);
56
- * const bus = createBus<Events>({ commands });
57
+ * const bus = createBus<Events>();
58
+ * const commands = createCommands(bus, [bindHandler(sendMail, smtpSend)]);
57
59
  *
58
60
  * const unbind = commands.handle(getUser, async () => fakeUser);
59
61
  * unbind(); // the command's own handler is back
60
62
  * ```
61
63
  */
62
- export declare const createCommands: <E extends EventMap = EventMap>(bindings?: readonly Binding<E>[]) => {
64
+ export declare const createCommands: <E extends EventMap>(bus: Bus<E>, bindings?: readonly Binding<E>[]) => {
63
65
  run: (command: Command, payload: unknown, ctx: unknown) => unknown;
64
66
  handle: {
65
67
  <P, R>(command: Command<P, R>, fn: Task<P, E, R>): UnsubscribeCallback;
@@ -69,39 +71,59 @@ export declare const createCommands: <E extends EventMap = EventMap>(bindings?:
69
71
  };
70
72
  //#endregion
71
73
  //#region src/actions/job.d.ts
74
+ type Creator = {
75
+ (...args: never[]): {
76
+ type: string;
77
+ payload?: unknown;
78
+ };
79
+ readonly type: string;
80
+ };
81
+ type Outcome = string | Creator;
82
+ /** What `createJob` returns: the command of the job and the actions of its outcome. */
83
+ type Job<P, R, T extends string, S extends Outcome, F extends Outcome> = {
84
+ command: Command<P, Promise<Awaited<R> | undefined>> & {
85
+ readonly type: T;
86
+ };
87
+ /** Made from a string with the result as its payload, or the creator that was given. */
88
+ successAction: S extends string ? ActionCreator<Awaited<R>, S> : S;
89
+ /** Made from a string with the error as its payload, or the creator that was given. */
90
+ failAction: F extends string ? ActionCreator<unknown, F> : F;
91
+ };
72
92
  /**
73
- * Creates a command whose outcome is sent on: when the handler succeeds, its
74
- * result goes to `done`, and when it fails, the error goes to `fail`. Each is
75
- * anything `emit` takes as its first argument, and receives the result (or the
76
- * error) as the payload: an event type, an action creator, a command, or a
77
- * plain action. It is made for the case where nobody waits for the result and
78
- * the bus carries it on, like `createAsyncThunk` or an effector effect.
79
- *
80
- * `bus.emit(job, payload)` returns a promise of the result. When `fail` is set
81
- * the error counts as handled: it goes to `fail` and the promise resolves with
82
- * `undefined`; without `fail` the promise rejects. The outcome is routed by the
83
- * bus, also for a handler bound with `commands.handle`, and is skipped once the
84
- * task is aborted. Calling the job directly runs only its handler.
93
+ * Creates a job: a command whose outcome is sent on as actions. When the
94
+ * handler succeeds, `successAction(result)` is emitted on the bus, and when it
95
+ * fails, `failAction(error)`. It is made for the case where nobody waits for
96
+ * the result and the bus carries it on, like `createAsyncThunk` or an effector
97
+ * effect. It returns the three together: `{ command, successAction, failAction }`.
98
+ *
99
+ * `success` and `fail` are a type string, from which the job makes an action
100
+ * creator with `createAction`, or an action creator that exists already, which
101
+ * is used and returned as it is. A missing one is made with the type
102
+ * `<type>/success` or `<type>/fail`.
103
+ *
104
+ * `bus.emit(command, payload)` returns a promise of the result. An error of the
105
+ * handler always counts as handled: it goes to `failAction` and the promise
106
+ * resolves with `undefined`; a command is the tool for a result that must reject.
107
+ * The actions are emitted as the task that ran the job, also for a handler bound
108
+ * with `commands.handle`, and are skipped once the task is aborted. A missing
109
+ * handler is not an outcome: `emit` throws `MissingHandlerError`. Calling the
110
+ * command directly runs only its handler.
85
111
  *
86
112
  * @example
87
113
  * ```ts
88
- * const loaded = createAction<User>("user/loaded");
89
- * const failed = createAction<Error>("user/failed");
90
- *
91
- * const loadUser = createJob("user/load", fetchUser, { done: loaded, fail: failed });
114
+ * const { command: loadUser, successAction: userLoaded, failAction: userFailed } =
115
+ * createJob("user/load", fetchUser, { success: "user/loaded", fail: "user/failed" });
92
116
  *
93
- * bus.on(loaded, (user) => render(user));
94
- * bus.emit(loadUser, "1"); // loaded(user) or failed(error) comes later
117
+ * bus.on(userLoaded, (user) => render(user));
118
+ * bus.emit(loadUser, "1"); // userLoaded(user) or userFailed(error) comes later
95
119
  * ```
96
120
  */
97
- export declare const createJob: <P = void, R = void, T extends string = string, E extends EventMap = EventMap>(type: T, handler?: Task<P, E, R>, outcomes?: {
98
- /** Gets the result when the handler succeeds. */
99
- done?: Emittable<E>;
100
- /** Gets the error when the handler fails. */
101
- fail?: Emittable<E>;
102
- }) => Command<P, Promise<Awaited<R> | undefined>> & {
103
- readonly type: T;
104
- };
121
+ export declare const createJob: <P = void, R = void, T extends string = string, E extends EventMap = EventMap, S extends Outcome = `${T}/success`, F extends Outcome = `${T}/fail`>(type: T, handler?: Task<P, E, R>, outcomes?: {
122
+ /** Gets the result when the handler succeeds: a type to make an action creator of, or an action creator. */
123
+ success?: S;
124
+ /** Gets the error when the handler fails: a type to make an action creator of, or an action creator. */
125
+ fail?: F;
126
+ }) => Job<P, R, T, S, F>;
105
127
  //#endregion
106
128
  //#region src/actions/module.d.ts
107
129
  /**
@@ -116,10 +138,14 @@ type ModuleContext<E extends EventMap = EventMap> = Context<E> & {
116
138
  handle(type: string, fn: Task<never, E, unknown>): UnsubscribeCallback;
117
139
  handle(bindings: readonly Binding<E>[]): UnsubscribeCallback;
118
140
  /**
119
- * Mounts sub-modules; they are unmounted with this one. The returned function
120
- * unmounts just these, e.g. when they were added later from a listener.
141
+ * Brings sub-modules and commands, in any order. A sub-module is mounted and
142
+ * unmounted with this one. A command is bound to the handler it carries, for
143
+ * as long as this module is mounted; a command that answers by itself keeps
144
+ * answering after the module is gone, since the handler is its own. The
145
+ * returned function undoes just this call, e.g. for what was added later from
146
+ * a listener.
121
147
  */
122
- use(...modules: Module<E>[]): UnsubscribeCallback;
148
+ use(...items: Array<Module<E> | Command<never, unknown>>): UnsubscribeCallback;
123
149
  /**
124
150
  * Starts a background task that lives as long as the module: it is aborted
125
151
  * on unmount, and an error of it is left unhandled, as in any handler.
@@ -151,7 +177,7 @@ type Module<E extends EventMap = EventMap> = {
151
177
  */
152
178
  export declare const createModule: <E extends EventMap = EventMap>(name: string, setup: (m: ModuleContext<E>) => void) => Module<E>;
153
179
  type Registry<E extends EventMap> = ReturnType<typeof createCommands<E>>;
154
- /** What `registerModules` returns. */
180
+ /** What `modulePlugin` returns. */
155
181
  type ModuleApi<E extends EventMap = EventMap> = {
156
182
  /** The registry of command handlers of the bus: the one it was made with, or the app's own. */
157
183
  commands: Registry<E>;
@@ -163,11 +189,11 @@ type ModuleApi<E extends EventMap = EventMap> = {
163
189
  dispose(): void;
164
190
  };
165
191
  /**
166
- * Assembles an app from modules on `bus`: mounts `modules` at once, in the
167
- * order given, and returns `mount`, `unmount`, `isMounted` and `dispose` for
168
- * the modules that come and go later. The bus runs the commands that the
169
- * modules bind: if it was made with `commands: createCommands()` that registry
170
- * is used, otherwise the app brings its own, as `app.commands`.
192
+ * The plugin that assembles an app from modules: `bus.use(modulePlugin(modules))`
193
+ * mounts `modules` at once, in the order given, and returns `mount`, `unmount`,
194
+ * `isMounted`, `dispose` and `commands` for the modules that come and go later. The bus runs the commands that the
195
+ * modules bind: if `createCommands(bus)` was called before, that registry is
196
+ * used, otherwise the app attaches its own, as `app.commands`.
171
197
  *
172
198
  * A module is known by its `name`: mounting a module whose name is taken
173
199
  * replaces the mounted one, which is unmounted first. That is what hot reload
@@ -181,7 +207,7 @@ type ModuleApi<E extends EventMap = EventMap> = {
181
207
  * @example
182
208
  * ```ts
183
209
  * const bus = createBus<Events>();
184
- * const app = registerModules(bus, [userModule]);
210
+ * const app = bus.use(modulePlugin([userModule]));
185
211
  *
186
212
  * const unmount = app.mount(orderModule); // later, e.g. after a lazy import
187
213
  * unmount(); // or app.unmount(orderModule)
@@ -191,6 +217,6 @@ type ModuleApi<E extends EventMap = EventMap> = {
191
217
  * app.dispose();
192
218
  * ```
193
219
  */
194
- export declare const registerModules: <E extends EventMap>(bus: Bus<E>, modules?: readonly Module<E>[]) => ModuleApi<E>;
220
+ export declare const modulePlugin: <E extends EventMap>(modules?: readonly Module<E>[]) => (bus: Bus<E>) => ModuleApi<E>;
195
221
  //#endregion
196
- export { type ActionCreator, type Binding, type FreeActionCreator, type Module, type ModuleApi, type ModuleContext, createAction };
222
+ export { type ActionCreator, type Binding, type FreeActionCreator, type Job, type Module, type ModuleApi, type ModuleContext, createAction };
@@ -1 +1 @@
1
- import{i as e,n as t,s as n}from"./context-DGPIFXxI.js";import{t as r}from"./event-0RIBGYqS.js";function i(e,t){return Object.assign((...n)=>({type:e,payload:t?t(...n).payload:n[0]}),{type:e,match:t=>t.type===e,toString:()=>e})}var a=class extends Error{};const o=(e,n)=>Object.assign((r,i)=>{if(!n)throw new a(`No handler for command "${e}"`);return n(r,i??t({type:e,payload:r}).ctx)},{type:e}),s=(e,t)=>[e,t],c=(e=[])=>{let t=/* @__PURE__ */ new Map,n=(e,n)=>{let r={fn:n};return t.set(e,[...t.get(e)??[],r]),()=>{let n=(t.get(e)??[]).filter(e=>e!==r);n.length>0?t.set(e,n):t.delete(e)}};function i(e,t){if(t)return n(r(e),t);let i=e.map(([e,t])=>n(r(e),t));return()=>{for(let e of i)e()}}return i(e),{run:(e,n,r)=>{let i=(t.get(e.type)??[]).at(-1)?.fn,a=i&&e.wrap?e.wrap(i):i??e;return Reflect.apply(a,null,[n,r])},handle:i}},l=(e,t,n)=>{let r=e.emit;typeof t==`string`?r(t,n):typeof t==`function`?r(`match`in t?t.type:t,n):r({type:t.type,payload:n})},u=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof a)throw e;return Promise.reject(e)}},d=(e,t,n={})=>{let r=o(e,t),i=(e,t,r)=>{let i=r;return u(()=>Reflect.apply(e,null,[t,r])).then(e=>(n.done&&l(i,n.done,e),e),e=>{if(!n.fail)throw e;l(i,n.fail,e)})};return Object.assign((e,t)=>t?i(r,e,t):u(()=>r(e)),{type:e,wrap:e=>(t,n)=>i(e,t,n)})},f=(e,t)=>({name:e,setup:t}),p=(r,i=[])=>{let a=r.commands??c();r.commands??=a;let o={handle:(...e)=>{if(!a.handle)throw Error("registerModules: the `commands` of the bus is not a registry from `createCommands()`");return Reflect.apply(a.handle,null,e)}},s=t({type:`app`,payload:void 0},r,r.trace),l=t=>{let r=/* @__PURE__ */ new Map,i=/* @__PURE__ */ new Map;return{mount:a=>{let s=r.get(a);if(s)return s;let c=i.get(a.name);c&&r.get(c)?.();let u=e(t,a.name),d=u.ctx,f=l(d),p=()=>{r.delete(a),i.get(a.name)===a&&i.delete(a.name),d.abort(),u.unlink()};r.set(a,p),i.set(a.name,a);let m=(e,t)=>{let r=Reflect.apply(o.handle,null,[e,t]);return n(d,r),r},h=(...e)=>{let t=e.map(f.mount);return()=>{for(let e of t)e()}},g=(e,...t)=>{d.run(e,...t).catch(e=>{if(!d.signal.aborted)throw e})};try{a.setup(Object.assign(d,{handle:m,use:h,spawn:g}))}catch(e){throw p(),e}return p},unmount:e=>r.get(e)?.(),isMounted:e=>r.has(e)}},u=l(s.ctx);for(let e of i)u.mount(e);return{commands:a,mount:e=>(s.ctx.signal.throwIfAborted(),u.mount(e)),unmount:u.unmount,isMounted:u.isMounted,dispose:()=>s.ctx.abort()}};export{s as bindHandler,i as createAction,o as createCommand,c as createCommands,d as createJob,f as createModule,p as registerModules};
1
+ import{i as e,n as t,s as n}from"./context-yAWj0BFZ.js";import{t as r}from"./event-0RIBGYqS.js";function i(e,t){return Object.assign((...n)=>({type:e,payload:t?t(...n).payload:n[0]}),{type:e,match:t=>t.type===e,toString:()=>e})}var a=class extends Error{};const o=(e,n)=>Object.assign((r,i)=>{if(!n)throw new a(`No handler for command "${e}"`);return n(r,i??t({event:{type:e,payload:r}}).ctx)},{type:e}),s=(e,t)=>[e,t],c=(e,t=[])=>{let n=/* @__PURE__ */ new Map,i=(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 a(e,t){if(t)return i(r(e),t);let n=e.map(([e,t])=>i(r(e),t));return()=>{for(let e of n)e()}}a(t);let o={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:a};return e.commands=o,o},l=e=>typeof e==`string`?i(e):e,u=(e,t,n)=>{let r=e.emit;r(Reflect.apply(t,null,[n]))},d=e=>{try{return Promise.resolve(e())}catch(e){if(e instanceof a)throw e;return Promise.reject(e)}},f=(e,t,n={})=>{let r=o(e,t),i=l(n.success??`${e}/success`),a=l(n.fail??`${e}/fail`),s=(e,t,n)=>{let r=n;return d(()=>Reflect.apply(e,null,[t,n])).then(e=>(u(r,i,e),e),e=>{u(r,a,e)})};return{command:Object.assign((e,t)=>t?s(r,e,t):d(()=>r(e)),{type:e,wrap:e=>(t,n)=>s(e,t,n)}),successAction:i,failAction:a}},p=(e,t)=>({name:e,setup:t}),m=(r=[])=>i=>{let a=i.commands??c(i),o={handle:(...e)=>{if(!a.handle)throw Error("modulePlugin: the `commands` of the bus is not a registry from `createCommands()`");return Reflect.apply(a.handle,null,e)}},s=t({event:{type:`app`,payload:void 0},bus:i,tracer:i.trace}),l=t=>{let r=/* @__PURE__ */ new Map,i=/* @__PURE__ */ new Map;return{mount:a=>{let s=r.get(a);if(s)return s;let c=i.get(a.name);c&&r.get(c)?.();let u=e(t,a.name),d=u.ctx,f=l(d),p=()=>{r.delete(a),i.get(a.name)===a&&i.delete(a.name),d.abort(),u.unlink()};r.set(a,p),i.set(a.name,a);let m=(e,t)=>{let r=Reflect.apply(o.handle,null,[e,t]);return n(d,r),r},h=(...e)=>{let t=e.map(e=>typeof e==`function`?m(e,e):f.mount(e));return()=>{for(let e of t)e()}},g=(e,...t)=>{d.run(e,...t).catch(e=>{if(!d.signal.aborted)throw e})};try{a.setup(Object.assign(d,{handle:m,use:h,spawn:g}))}catch(e){throw p(),e}return p},unmount:e=>r.get(e)?.(),isMounted:e=>r.has(e)}},u=l(s.ctx);for(let e of r)u.mount(e);return{commands:a,mount:e=>(s.ctx.signal.throwIfAborted(),u.mount(e)),unmount:u.unmount,isMounted:u.isMounted,dispose:()=>s.ctx.abort()}};export{s as bindHandler,i as createAction,o as createCommand,c as createCommands,f as createJob,p as createModule,m as modulePlugin};
@@ -0,0 +1 @@
1
+ import{a as e,c as t,n,r}from"./context-yAWj0BFZ.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=/* @__PURE__ */ new WeakSet,n=n=>{let r=e[n]??[];if(!t.has(r))return e[n]=r,r;let i=[...r];return e[n]=i,i},r=(t,r)=>{if(!r){e[t]=[];return}let i=(e[t]??[]).indexOf(r);i>=0&&n(t).splice(i,1)};return{get:n=>{let r=e[n]??[];return t.add(r),r},add:(e,t)=>(n(e).push(t),()=>{r(e,t)}),remove:r}},l=(e,t,n)=>Reflect.apply(e,null,[t,n]),u=(s={})=>{let u=c(),d=(e,t)=>u.add(o(e),t),f=(e,t)=>u.remove(o(e),t),p=(e,a)=>{let{onError:o}=s,{ctx:c}=n({event:a,bus:m,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)}},m={on:d,off:f,emit:(t,i)=>{let c=o(t),d=a(t,i),f={type:c,payload:d},h=[...u.get(c),...u.get(`*`)];h.length===0&&typeof t!=`function`&&s.onUnhandled?.(f);for(let e of h)p(e,f);if(typeof t==`function`){let{ctx:i}=n({event:f,bus:m,tracer:s.trace,parent:{ref:r()}}),a=m.commands?.run??l;return e(i,`command`,()=>a(t,d,i))}},use:e=>e(m),context:s.context,trace:s.trace};return m};export{s as n,u as t};
@@ -0,0 +1 @@
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)}},a=e=>{let t=new AbortController;return{controller:t,unlink:i({signal:e},e=>t.abort(e))}};let o;const s=()=>o,c=()=>{},l=(e,t,n,r)=>{},u=(e,t)=>c,d=(e,t,n)=>n(),f=(e,t)=>typeof e==`function`?e(t):e,p=e=>e,m=({event:e,bus:t,tracer:n,parent:r})=>{let{controller:s,unlink:l}=a(r?.signal),{signal:u}=s,h=(...e)=>{if(u.aborted)return;let n=t?.emit,r=o;o=void 0;try{return n?.(...e)}finally{o=r}},g=(...e)=>{if(u.aborted)return c;let n=t?.on,r=n?.(...e);if(!r)return c;let a=i({signal:u},r);return()=>{a(),r()}},_=async(r,...i)=>{u.throwIfAborted();let a=i[0],o=m({event:{type:e.type,payload:a},bus:t,tracer:n,parent:{signal:u,ref:void 0}});try{return await d(o.ctx,`run`,()=>r(a,o.ctx))}finally{o.unlink()}};return{ctx:p({...f(t?.context,e),type:e.type,payload:e.payload,signal:u,abort:e=>s.abort(e),emit:h,on:g,off:t?.off??c,run:_}),unlink:l}},h=(e,t)=>m({event:{type:t??e.type??``,payload:e.payload},bus:{emit:e.emit,on:e.on,off:e.off,context:e},tracer:void 0,parent:{signal:e.signal,ref:void 0}});export{d as a,e as c,h as i,m as n,l as o,s as r,i as s,u as t};
@@ -1 +1 @@
1
- import{s as e}from"./context-DGPIFXxI.js";const t=2**31-1,n=(e,n)=>{let r={id:null};if(n===1/0)return r;let i=n=>{r.id=setTimeout(()=>{n>t?i(n-t):(r.id=null,e())},Math.min(n,t))};return i(n>0?n:0),r},r=e=>{e.id!==null&&(clearTimeout(e.id),e.id=null)},i=(t,i)=>new Promise((a,o)=>{let s=n(()=>{c(),a()},typeof i==`function`?i():i),c=e(t,e=>{r(s),o(e)})});export{r as n,n as r,i as t};
1
+ import{s as e}from"./context-yAWj0BFZ.js";const t=2**31-1,n=(e,n)=>{let r={id:null};if(n===1/0)return r;let i=n=>{r.id=setTimeout(()=>{n>t?i(n-t):(r.id=null,e())},Math.min(n,t))};return i(n>0?n:0),r},r=e=>{e.id!==null&&(clearTimeout(e.id),e.id=null)},i=(t,i)=>new Promise((a,o)=>{let s=n(()=>{c(),a()},typeof i==`function`?i():i),c=e(t,e=>{r(s),o(e)})});export{r as n,n as r,i as t};