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.
- package/README.md +62 -61
- package/dist/{action-BM-UdmJr.d.ts → action-rqZEnRIp.d.ts} +12 -11
- package/dist/actions.d.ts +47 -185
- package/dist/actions.js +1 -1
- package/dist/bus-CRnlwmQ4.js +1 -0
- package/dist/context-DlA80GOA.js +1 -0
- package/dist/dev.d.ts +46 -0
- package/dist/dev.js +1 -0
- package/dist/effects.d.ts +61 -21
- package/dist/effects.js +1 -1
- package/dist/index.d.ts +1 -2
- package/dist/index.js +1 -1
- package/dist/module-BSCdR9D1.d.ts +167 -0
- package/dist/notrace/{action-BM-UdmJr.d.ts → action-rqZEnRIp.d.ts} +12 -11
- package/dist/notrace/actions.d.ts +71 -45
- package/dist/notrace/actions.js +1 -1
- package/dist/notrace/bus-Dx0l9X6h.js +1 -0
- package/dist/notrace/context-yAWj0BFZ.js +1 -0
- package/dist/notrace/{delay-Cko_Q9hl.js → delay-Cgvn16oY.js} +1 -1
- package/dist/notrace/effects.d.ts +61 -21
- package/dist/notrace/effects.js +1 -1
- package/dist/notrace/index.d.ts +1 -2
- package/dist/notrace/index.js +1 -1
- package/dist/notrace/policies.d.ts +1 -1
- package/dist/notrace/policies.js +1 -1
- package/dist/notrace/redux.d.ts +2 -28
- package/dist/notrace/redux.js +1 -1
- package/dist/observable.d.ts +1 -1
- package/dist/policies.d.ts +1 -1
- package/dist/policies.js +1 -1
- package/dist/production/dev.js +1 -0
- package/dist/redux.d.ts +2 -28
- package/dist/redux.js +1 -1
- package/dist/trace.d.ts +22 -4
- package/dist/trace.js +1 -1
- package/docs/README.md +4 -1
- package/docs/actions.md +21 -11
- package/docs/context.md +0 -1
- package/docs/effects.md +49 -31
- package/docs/errors.md +4 -4
- package/docs/guide.md +229 -0
- package/docs/hmr.md +20 -58
- package/docs/policies.md +4 -4
- package/docs/stores.md +0 -2
- package/docs/tracing.md +21 -8
- package/package.json +25 -5
- package/dist/bus-RUiw8f9p.js +0 -1
- package/dist/context-BXQ6Einm.js +0 -1
- package/dist/index-CaxrMD1A.d.ts +0 -1
- package/dist/notrace/bus-CFxgpsRL.js +0 -1
- package/dist/notrace/context-DGPIFXxI.js +0 -1
- package/dist/notrace/index-CaxrMD1A.d.ts +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { A as Keys, k as EventMap, u as Context } from "./action-
|
|
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
|
|
133
|
-
* `ms` (with `leading` also at once), and the next ticks keep a steady
|
|
134
|
-
* whatever the duration of
|
|
135
|
-
* (`waitForFn` starts each pause when the call ends instead).
|
|
136
|
-
*
|
|
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(),
|
|
149
|
-
* cleanup(); // the task was aborted
|
|
153
|
+
* await poll(ctx, () => refresh(), 10_000);
|
|
150
154
|
* });
|
|
151
155
|
* ```
|
|
152
156
|
*/
|
|
153
|
-
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
|
230
|
-
* with a `TimeoutError` (a `DOMException`, like `AbortSignal.timeout`), even
|
|
231
|
-
*
|
|
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
|
|
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>)
|
|
282
|
+
}, ms: number, starter: Starter<T>): Promise<T>;
|
|
243
283
|
//#endregion
|
|
244
284
|
export type { CancellableExecutor, CancellableHandle, EffectContext, PollOptions, RaceStarter, RetryOptions, TakeOptions };
|
package/dist/notrace/effects.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,c as t,i as n,o as r,s as i,t as a}from"./context-
|
|
1
|
+
import{a as e,c as t,i as n,o as r,s as i,t as a}from"./context-yAWj0BFZ.js";import{n as o,r as s,t as c}from"./delay-Cgvn16oY.js";const l=(e,t)=>t?.signal?new Promise((n,r)=>{let a=i(t,r);e.then(n,r).finally(a)}):e,u=async(e,t,o,s)=>{t?.signal?.throwIfAborted();let{ctx:c,unlink:u}=n(t??{}),d=a(c,e);r(c,e,`start`),i(c,()=>d(`cancel`));try{let e=await l(o(c),t);return d(`done`),s?.(!1),e}catch(e){throw d(`error`,e),s?.(!0),e}finally{u()}},d=async(t,r)=>{let{ctx:i,unlink:a}=n(t);try{return await e(i,`run`,()=>r(i))}finally{a()}},f=e=>e,p=(e,t)=>n=>e(t,f(n)),m=e=>Array.isArray(e)?Array(e.length):{},h=(t,r)=>{let i=Object.entries(r).map(([r,i])=>{let a=n(t),o={signal:a.ctx.signal,abort:a.ctx.abort},s=()=>i(o);return{key:r,task:new Promise(t=>t(e(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=(e,n)=>e.signal.aborted?Promise.reject(e.signal.reason):new Promise((r,a)=>{let o=[],s=`pending`,c=e=>{try{e()}catch(e){t(`cancel cleanup failed`,e)}},l=i(e,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{n({resolve:u(r),reject:u(a),onCancel:d})}catch(e){u(a)(e)}}),x=(e,t,n,r)=>{if(e.signal.aborted)return Promise.resolve();let a=r.leading??!1,c=r.waitForFn??!1;return u(`poll`,e,e=>new Promise((r,l)=>{let u=0,f=null,p=()=>{f!==null&&(o(f),f=null)},m=e=>{try{f=s(h,typeof n==`function`?n(e):n)}catch(e){p(),l(e)}},h=()=>{f=null,c||m(u+1),g()},g=()=>{let n=u++;d(e,e=>t(e,n)).then(()=>{c&&!e.signal.aborted&&m(u)},e=>{p(),l(e)})};i(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,t,n={})=>u(`take`,e,r=>new Promise((a,o)=>{let{predicate:s}=n,c=[],l=()=>{for(let e of c)e()},u=e=>{l(),o(e)};c.push(e.on(t,e=>{(!s||s(e))&&(l(),a(e))})),c.push(i(r,u)),c.push(i({signal:n.signal},u))})),k=(t,r,i)=>u(`timeout`,t,async t=>{let a=n(t),c=s(()=>a.ctx.abort(new DOMException(`Timed out after ${r}ms`,`TimeoutError`)),r);try{return await l(Promise.resolve(e(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,i as onAbort,S as poll,C as race,D as retry,O as take,A as timeout};
|
package/dist/notrace/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-
|
|
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/notrace/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{n as anyEventType,t as createBus}from"./bus-
|
|
1
|
+
export{n as anyEventType,t as createBus}from"./bus-Dx0l9X6h.js";
|
package/dist/notrace/policies.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,i as t,o as n,s as r,t as i}from"./context-
|
|
1
|
+
import{a as e,i as t,o as n,s as r,t as i}from"./context-yAWj0BFZ.js";import{n as a,r as o,t as s}from"./delay-Cgvn16oY.js";import{n as c,t as l}from"./promise-CSLpzwSR.js";const u=()=>{},d=(e,t)=>{let n=/* @__PURE__ */ new Map;return(r,i)=>{let a=e(r),o=n.get(a);if(!o){let e=t(()=>{n.get(a)===e&&n.delete(a)});o=e,n.set(a,e)}return o(r,i)}},f=(e,t)=>e?d(e,t):t(u),p=(e,t={})=>f(t.key,t=>m(`latest`,(t,n,r)=>(r(),e(t,n)),t)),m=(e,a,o=u)=>{let s=null;return(l,u)=>{if(s?.abort(),u.signal.aborted)return;let{ctx:d,unlink:f}=t(u);s=d;let p=i(d,e),m=!1,h=()=>{d.signal.aborted||(m=!0,n(d,e,`start`))};r(d,()=>p(m?`cancel`:`drop`));let g=()=>{f(),s===d&&(s=null,o())},_=e=>{if(!d.signal.aborted)return p(m?`done`:`drop`),e};try{let e=a(l,d,h);return c(e)?Promise.resolve(e).then(_,e=>{if(!d.signal.aborted)throw p(`error`,e),e}).finally(g):(g(),_(e))}catch(e){if(g(),d.signal.aborted)return;throw p(`error`,e),e}}},h=(e,t,n={})=>f(n.key,r=>_(e,t,n,r)),g=(t,r,i,s)=>{let c=s!==u,l=null,d=null;return(u,f)=>{if(f.signal.aborted)return;let p=Date.now(),m=l===null||p-l>=t||p-l<0;return l=p,d!==null&&a(d),d=c?o(s,t):null,i&&m?Promise.resolve(e(f,`debounce`,()=>r(u,f))):(n(f,`debounce`,`drop`),Promise.resolve(void 0))}},_=(t,n,i,a)=>{let o=i.leading??!1,c=i.trailing??!0;if(!c)return g(t,n,o,a);let l=!1,u=0,d=m(`debounce`,([e,i],a,o)=>{let d=u;return r(a,()=>{u===d&&(l=!1)}),s(a,t).then(()=>{if(l=!1,c&&!i)return o(),n(e,a)})},a);return(t,r)=>{if(r.signal.aborted)return;let i=o&&!l;l=!0,u++;let a=d([t,i],r);return i?Promise.resolve(e(r,`debounce`,()=>n(t,r))):a}},v=(t,i={})=>f(i.key,i=>{let a=null;return(o,s)=>{if(s.signal.aborted)return;if(a){n(s,`leading`,`drop`);return}let c={};a=c;let u=()=>{d(),a===c&&(a=null,i())},d=r(s,u);try{return l(e(s,`leading`,()=>t(o,s)),u)}catch(e){throw u(),e}}}),y=(e,t={})=>f(t.key,n=>b(e,t,n)),b=(t,i,a)=>{let o=i.concurrency??1,s=i.limit??1/0,c=[],l=0,d=()=>{for(;l<o;){let e=c.shift();if(!e)return;e.start()}};return(f,p)=>new Promise((m,h)=>{if(p.signal.aborted){m(void 0);return}let g=u,_=()=>{g(),n(p,`queue`,`drop`),m(void 0)},v=()=>{if(g(),p.signal.aborted){_();return}l++;let n=!0,i=()=>{n&&(n=!1,l--,d(),l===0&&c.length===0&&a())},o=r(p,()=>{i(),m(void 0)}),s;try{s=Promise.resolve(e(p,`queue`,()=>t(f,p)))}catch(e){s=Promise.reject(e)}let u=()=>{o(),i()};s.then(e=>{u(),m(p.signal.aborted?void 0:e)},e=>{u(),p.signal.aborted?m(void 0):h(e)})};if(l<o){v();return}if(c.length>=s){if(i.overflow!==`drop-old`||s<=0){_();return}c.shift()?.drop()}let y={start:v,drop:_};c.push(y),g=r(p,()=>{let e=c.indexOf(y);e>=0&&c.splice(e,1),_()})})},x=(e,t,n={})=>f(n.key,r=>S(e,t,n,r)),S=(t,r,i,s)=>{let c=i.leading??!0,l=i.trailing??!0,d=s!==u,f=null,p=0,m=null,h=null,g=null,_=!1,v=e=>f===null||e-f>=t||e-f<0||e-p>=t,y=e=>n(e,`throttle`,`drop`),b=()=>{let e=g;g=null,e&&(y(e.ctx),e.resolve())},x=(e,t)=>(b(),new Promise((n,r)=>{g={payload:e,ctx:t,resolve:n,reject:r}})),S=(t,n,i)=>{b(),p=i,_=!0;try{return e(n,`throttle`,()=>r(t,n))}finally{_=!1}},C=()=>{d&&(h=o(w,t))},w=()=>{if(h=null,!d||m!==null||g)return;let e=Date.now(),n=Math.max(t-(e-(f??-1/0)),t-(e-p));n<=0?s():h=o(w,n)},T=e=>{m=null;let t=g;if(l&&t&&!t.ctx.signal.aborted){g=null;try{t.resolve(S(t.payload,t.ctx,e))}catch(e){t.reject(e)}}else b();w()},E=()=>{let e=Date.now();v(e)?T(e):m=o(E,Math.min(t-(e-(f??e)),t-(e-p)))},D=()=>{h!==null&&(a(h),h=null)},O=(e,t)=>{if(!l)y(t);else return x(e,t)},k=(e,t,n,r)=>{if(!r)y(t);else if(p=n,C(),!c)y(t);else return S(e,t,n)},A=(e,n,r,i)=>i&&m!==null?(a(m),m=o(E,t),S(e,n,r)):m===null&&(m=o(E,t),i&&(p=r,c))?S(e,n,r):O(e,n);return(e,t)=>{if(t.signal.aborted)return;let n=Date.now(),r=!_&&v(n);return f=n,D(),l?A(e,t,n,r):k(e,t,n,r)}};export{h as debounce,p as latest,v as leading,y as queue,x as throttle};
|
package/dist/notrace/redux.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { k as EventMap, o as Bus, s as BusOptions } from "./action-
|
|
1
|
+
import { k as EventMap, o as Bus, s as BusOptions } from "./action-rqZEnRIp.js";
|
|
2
2
|
//#region src/store/redux/middleware.d.ts
|
|
3
3
|
/** What Redux passes through a middleware: an action is a plain object with a `type`. */
|
|
4
4
|
type ReduxAction = {
|
|
@@ -9,32 +9,6 @@ type NanoeffectsMiddlewareOptions = {
|
|
|
9
9
|
/** Return `false` for the actions that the bus should not get. Default: all of them. */
|
|
10
10
|
filter?: (action: ReduxAction) => boolean;
|
|
11
11
|
};
|
|
12
|
-
/**
|
|
13
|
-
* A Redux middleware that sends every action to the bus, after the reducers
|
|
14
|
-
* have handled it, so a handler that reads the store sees the new state. It
|
|
15
|
-
* does not depend on Redux: it only has the shape of a middleware. Values that
|
|
16
|
-
* are not plain actions (the functions of redux-thunk) go through untouched.
|
|
17
|
-
*
|
|
18
|
-
* The other way needs no adapter: give the store to the tasks with
|
|
19
|
-
* `createBus({ context: { store } })` and dispatch from a handler.
|
|
20
|
-
*
|
|
21
|
-
* Take care of loops: a handler must not dispatch the action it handles.
|
|
22
|
-
* Errors of handlers reach the caller of `dispatch`, as for `bus.emit`; set
|
|
23
|
-
* `onError` on the bus to isolate them.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```ts
|
|
27
|
-
* const store = configureStore({
|
|
28
|
-
* reducer,
|
|
29
|
-
* middleware: (getDefault) => getDefault().concat(nanoeffectsMiddleware(bus)),
|
|
30
|
-
* });
|
|
31
|
-
*
|
|
32
|
-
* bus.on(userRequested, latest(async (id, { store, signal }) => {
|
|
33
|
-
* store.dispatch(userLoaded(await fetchUser(id, { signal })));
|
|
34
|
-
* }));
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export declare const nanoeffectsMiddleware: <E extends EventMap>(bus: Bus<E>, options?: NanoeffectsMiddlewareOptions) => () => (next: (action: unknown) => unknown) => (action: unknown) => unknown;
|
|
38
12
|
//#endregion
|
|
39
13
|
//#region src/store/redux/effects.d.ts
|
|
40
14
|
/** What Redux gives a middleware: the parts of the store that it may use. */
|
|
@@ -89,4 +63,4 @@ export declare const createEffectsMiddleware: <E extends EventMap = EventMap>(op
|
|
|
89
63
|
middleware: (storeApi: ReduxStoreApi) => (next: (action: unknown) => unknown) => (action: unknown) => unknown;
|
|
90
64
|
};
|
|
91
65
|
//#endregion
|
|
92
|
-
export type { EffectsMiddlewareOptions,
|
|
66
|
+
export type { EffectsMiddlewareOptions, ReduxStoreApi };
|
package/dist/notrace/redux.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{c as e}from"./context-
|
|
1
|
+
import{c as e}from"./context-yAWj0BFZ.js";import{t}from"./bus-Dx0l9X6h.js";const n=e=>typeof e==`object`&&!!e&&`type`in e,r=(e,t={})=>{let r=e.emit;return()=>e=>i=>{let a=e(i);return n(i)&&(t.filter?.(i)??!0)&&r(i),a}},i=(n={})=>{let{filter:i,context:a,onError:o,...s}=n,c,l=/* @__PURE__ */ new WeakMap,u=e=>({...a,store:c&&{getState:c.getState,dispatch:t=>{typeof t==`object`&&t&&l.set(t,e.type);let n=t;return c?.dispatch(n)}}}),d=t({...s,onError:o??((t,{type:n})=>{e(`handler of "${n}" failed`,t)}),context:u}),f=r(d,{filter:e=>l.get(e)!==e.type&&(i?.(e)??!0)});return{bus:d,middleware:e=>(c=e,f())}};export{i as createEffectsMiddleware};
|
package/dist/observable.d.ts
CHANGED
package/dist/policies.d.ts
CHANGED
package/dist/policies.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{t as e}from"./onAbort-BgMfspK4.js";import{a as t,i as n,o as r,t as i}from"./context-
|
|
1
|
+
import{t as e}from"./onAbort-BgMfspK4.js";import{a as t,i as n,o as r,t as i}from"./context-DlA80GOA.js";import{n as a,r as o,t as s}from"./delay-CIHnOh_L.js";import{n as c,t as l}from"./promise-CSLpzwSR.js";const u=()=>{},d=(e,t)=>{let n=/* @__PURE__ */ new Map;return(r,i)=>{let a=e(r),o=n.get(a);if(!o){let e=t(()=>{n.get(a)===e&&n.delete(a)});o=e,n.set(a,e)}return o(r,i)}},f=(e,t)=>e?d(e,t):t(u),p=(e,t={})=>f(t.key,t=>m(`latest`,(t,n,r)=>(r(),e(t,n)),t)),m=(t,a,o=u)=>{let s=null;return(l,u)=>{if(s?.abort(),u.signal.aborted)return;let{ctx:d,unlink:f}=n(u);s=d;let p=i(d,t),m=!1,h=()=>{d.signal.aborted||(m=!0,r(d,t,`start`))};e(d,()=>p(m?`cancel`:`drop`));let g=()=>{f(),s===d&&(s=null,o())},_=e=>{if(!d.signal.aborted)return p(m?`done`:`drop`),e};try{let e=a(l,d,h);return c(e)?Promise.resolve(e).then(_,e=>{if(!d.signal.aborted)throw p(`error`,e),e}).finally(g):(g(),_(e))}catch(e){if(g(),d.signal.aborted)return;throw p(`error`,e),e}}},h=(e,t,n={})=>f(n.key,r=>_(e,t,n,r)),g=(e,n,i,s)=>{let c=s!==u,l=null,d=null;return(u,f)=>{if(f.signal.aborted)return;let p=Date.now(),m=l===null||p-l>=e||p-l<0;return l=p,d!==null&&a(d),d=c?o(s,e):null,i&&m?Promise.resolve(t(f,`debounce`,()=>n(u,f))):(r(f,`debounce`,`drop`),Promise.resolve(void 0))}},_=(n,r,i,a)=>{let o=i.leading??!1,c=i.trailing??!0;if(!c)return g(n,r,o,a);let l=!1,u=0,d=m(`debounce`,([t,i],a,o)=>{let d=u;return e(a,()=>{u===d&&(l=!1)}),s(a,n).then(()=>{if(l=!1,c&&!i)return o(),r(t,a)})},a);return(e,n)=>{if(n.signal.aborted)return;let i=o&&!l;l=!0,u++;let a=d([e,i],n);return i?Promise.resolve(t(n,`debounce`,()=>r(e,n))):a}},v=(n,i={})=>f(i.key,i=>{let a=null;return(o,s)=>{if(s.signal.aborted)return;if(a){r(s,`leading`,`drop`);return}let c={};a=c;let u=()=>{d(),a===c&&(a=null,i())},d=e(s,u);try{return l(t(s,`leading`,()=>n(o,s)),u)}catch(e){throw u(),e}}}),y=(e,t={})=>f(t.key,n=>b(e,t,n)),b=(n,i,a)=>{let o=i.concurrency??1,s=i.limit??1/0,c=[],l=0,d=()=>{for(;l<o;){let e=c.shift();if(!e)return;e.start()}};return(f,p)=>new Promise((m,h)=>{if(p.signal.aborted){m(void 0);return}let g=u,_=()=>{g(),r(p,`queue`,`drop`),m(void 0)},v=()=>{if(g(),p.signal.aborted){_();return}l++;let r=!0,i=()=>{r&&(r=!1,l--,d(),l===0&&c.length===0&&a())},o=e(p,()=>{i(),m(void 0)}),s;try{s=Promise.resolve(t(p,`queue`,()=>n(f,p)))}catch(e){s=Promise.reject(e)}let u=()=>{o(),i()};s.then(e=>{u(),m(p.signal.aborted?void 0:e)},e=>{u(),p.signal.aborted?m(void 0):h(e)})};if(l<o){v();return}if(c.length>=s){if(i.overflow!==`drop-old`||s<=0){_();return}c.shift()?.drop()}let y={start:v,drop:_};c.push(y),g=e(p,()=>{let e=c.indexOf(y);e>=0&&c.splice(e,1),_()})})},x=(e,t,n={})=>f(n.key,r=>S(e,t,n,r)),S=(e,n,i,s)=>{let c=i.leading??!0,l=i.trailing??!0,d=s!==u,f=null,p=0,m=null,h=null,g=null,_=!1,v=t=>f===null||t-f>=e||t-f<0||t-p>=e,y=e=>r(e,`throttle`,`drop`),b=()=>{let e=g;g=null,e&&(y(e.ctx),e.resolve())},x=(e,t)=>(b(),new Promise((n,r)=>{g={payload:e,ctx:t,resolve:n,reject:r}})),S=(e,r,i)=>{b(),p=i,_=!0;try{return t(r,`throttle`,()=>n(e,r))}finally{_=!1}},C=()=>{d&&(h=o(w,e))},w=()=>{if(h=null,!d||m!==null||g)return;let t=Date.now(),n=Math.max(e-(t-(f??-1/0)),e-(t-p));n<=0?s():h=o(w,n)},T=e=>{m=null;let t=g;if(l&&t&&!t.ctx.signal.aborted){g=null;try{t.resolve(S(t.payload,t.ctx,e))}catch(e){t.reject(e)}}else b();w()},E=()=>{let t=Date.now();v(t)?T(t):m=o(E,Math.min(e-(t-(f??t)),e-(t-p)))},D=()=>{h!==null&&(a(h),h=null)},O=(e,t)=>{if(!l)y(t);else return x(e,t)},k=(e,t,n,r)=>{if(!r)y(t);else if(p=n,C(),!c)y(t);else return S(e,t,n)},A=(t,n,r,i)=>i&&m!==null?(a(m),m=o(E,e),S(t,n,r)):m===null&&(m=o(E,e),i&&(p=r,c))?S(t,n,r):O(t,n);return(e,t)=>{if(t.signal.aborted)return;let n=Date.now(),r=!_&&v(n);return f=n,D(),l?A(e,t,n,r):k(e,t,n,r)}};export{h as debounce,p as latest,v as leading,y as queue,x as throttle};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const e=()=>{},t=()=>e,n=()=>t;export{n as devPlugin};
|
package/dist/redux.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { k as EventMap, o as Bus, s as BusOptions } from "./action-
|
|
1
|
+
import { k as EventMap, o as Bus, s as BusOptions } from "./action-rqZEnRIp.js";
|
|
2
2
|
//#region src/store/redux/middleware.d.ts
|
|
3
3
|
/** What Redux passes through a middleware: an action is a plain object with a `type`. */
|
|
4
4
|
type ReduxAction = {
|
|
@@ -9,32 +9,6 @@ type NanoeffectsMiddlewareOptions = {
|
|
|
9
9
|
/** Return `false` for the actions that the bus should not get. Default: all of them. */
|
|
10
10
|
filter?: (action: ReduxAction) => boolean;
|
|
11
11
|
};
|
|
12
|
-
/**
|
|
13
|
-
* A Redux middleware that sends every action to the bus, after the reducers
|
|
14
|
-
* have handled it, so a handler that reads the store sees the new state. It
|
|
15
|
-
* does not depend on Redux: it only has the shape of a middleware. Values that
|
|
16
|
-
* are not plain actions (the functions of redux-thunk) go through untouched.
|
|
17
|
-
*
|
|
18
|
-
* The other way needs no adapter: give the store to the tasks with
|
|
19
|
-
* `createBus({ context: { store } })` and dispatch from a handler.
|
|
20
|
-
*
|
|
21
|
-
* Take care of loops: a handler must not dispatch the action it handles.
|
|
22
|
-
* Errors of handlers reach the caller of `dispatch`, as for `bus.emit`; set
|
|
23
|
-
* `onError` on the bus to isolate them.
|
|
24
|
-
*
|
|
25
|
-
* @example
|
|
26
|
-
* ```ts
|
|
27
|
-
* const store = configureStore({
|
|
28
|
-
* reducer,
|
|
29
|
-
* middleware: (getDefault) => getDefault().concat(nanoeffectsMiddleware(bus)),
|
|
30
|
-
* });
|
|
31
|
-
*
|
|
32
|
-
* bus.on(userRequested, latest(async (id, { store, signal }) => {
|
|
33
|
-
* store.dispatch(userLoaded(await fetchUser(id, { signal })));
|
|
34
|
-
* }));
|
|
35
|
-
* ```
|
|
36
|
-
*/
|
|
37
|
-
export declare const nanoeffectsMiddleware: <E extends EventMap>(bus: Bus<E>, options?: NanoeffectsMiddlewareOptions) => () => (next: (action: unknown) => unknown) => (action: unknown) => unknown;
|
|
38
12
|
//#endregion
|
|
39
13
|
//#region src/store/redux/effects.d.ts
|
|
40
14
|
/** What Redux gives a middleware: the parts of the store that it may use. */
|
|
@@ -89,4 +63,4 @@ export declare const createEffectsMiddleware: <E extends EventMap = EventMap>(op
|
|
|
89
63
|
middleware: (storeApi: ReduxStoreApi) => (next: (action: unknown) => unknown) => (action: unknown) => unknown;
|
|
90
64
|
};
|
|
91
65
|
//#endregion
|
|
92
|
-
export type { EffectsMiddlewareOptions,
|
|
66
|
+
export type { EffectsMiddlewareOptions, ReduxStoreApi };
|
package/dist/redux.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e}from"./onAbort-BgMfspK4.js";import{t}from"./bus-
|
|
1
|
+
import{n as e}from"./onAbort-BgMfspK4.js";import{t}from"./bus-CRnlwmQ4.js";const n=e=>typeof e==`object`&&!!e&&`type`in e,r=(e,t={})=>{let r=e.emit;return()=>e=>i=>{let a=e(i);return n(i)&&(t.filter?.(i)??!0)&&r(i),a}},i=(n={})=>{let{filter:i,context:a,onError:o,...s}=n,c,l=/* @__PURE__ */ new WeakMap,u=e=>({...a,store:c&&{getState:c.getState,dispatch:t=>{typeof t==`object`&&t&&l.set(t,e.type);let n=t;return c?.dispatch(n)}}}),d=t({...s,onError:o??((t,{type:n})=>{e(`handler of "${n}" failed`,t)}),context:u}),f=r(d,{filter:e=>l.get(e)!==e.type&&(i?.(e)??!0)});return{bus:d,middleware:e=>(c=e,f())}};export{i as createEffectsMiddleware};
|
package/dist/trace.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { E as Tracer, F as TraceEvent, I as TraceLogger, P as Trace } from "./action-
|
|
1
|
+
import { E as Tracer, F as TraceEvent, I as TraceLogger, P as Trace } from "./action-rqZEnRIp.js";
|
|
2
2
|
//#region src/trace/console.d.ts
|
|
3
3
|
type ConsoleLoggerOptions = {
|
|
4
4
|
/** Defaults to `globalThis.console`. */
|
|
@@ -77,6 +77,7 @@ type ReduxConnection = {
|
|
|
77
77
|
type ReduxExtension = {
|
|
78
78
|
connect: (options?: {
|
|
79
79
|
name?: string;
|
|
80
|
+
maxAge?: number;
|
|
80
81
|
}) => ReduxConnection;
|
|
81
82
|
};
|
|
82
83
|
type ReduxDevtoolsOptions = {
|
|
@@ -84,6 +85,20 @@ type ReduxDevtoolsOptions = {
|
|
|
84
85
|
name?: string;
|
|
85
86
|
/** Defaults to `globalThis.__REDUX_DEVTOOLS_EXTENSION__`. */
|
|
86
87
|
extension?: ReduxExtension;
|
|
88
|
+
/**
|
|
89
|
+
* Also send the start of every task as an action. Default `false`: a task
|
|
90
|
+
* is one action, sent when it ends, and the tasks that are running are in
|
|
91
|
+
* the state.
|
|
92
|
+
*/
|
|
93
|
+
starts?: boolean;
|
|
94
|
+
/**
|
|
95
|
+
* How deep in the tree of tasks to show: `0` is the handler tasks only, `1`
|
|
96
|
+
* also the effects they start (`retry`, `timeout`, ...), and so on. The
|
|
97
|
+
* attempts and the starters under them are hidden at the default, `1`.
|
|
98
|
+
*/
|
|
99
|
+
depth?: number;
|
|
100
|
+
/** The number of actions that DevTools keeps; its own default is 50. */
|
|
101
|
+
maxAge?: number;
|
|
87
102
|
};
|
|
88
103
|
type ReduxDevtoolsState = {
|
|
89
104
|
/** Tasks that started and have not settled yet, by trace id. */
|
|
@@ -93,9 +108,12 @@ type ReduxDevtoolsState = {
|
|
|
93
108
|
}>;
|
|
94
109
|
};
|
|
95
110
|
/**
|
|
96
|
-
* Trace logger that sends
|
|
97
|
-
* `type/effect/phase`, with the running tasks as state.
|
|
98
|
-
*
|
|
111
|
+
* Trace logger that sends the tasks to Redux DevTools as actions
|
|
112
|
+
* `type/effect/phase`, with the running tasks as state. By default it is quiet:
|
|
113
|
+
* a task is one action, when it ends, and only the handler tasks and the
|
|
114
|
+
* effects they start are shown (see `starts` and `depth` to show more).
|
|
115
|
+
* Read-only: there is no time travel. Does nothing when the extension is not
|
|
116
|
+
* installed.
|
|
99
117
|
*
|
|
100
118
|
* @example
|
|
101
119
|
* ```ts
|
package/dist/trace.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,t}from"./onAbort-BgMfspK4.js";import{n}from"./promise-CSLpzwSR.js";const r=(e={})=>{let t=e.console??globalThis.console,n=e.prefix??`[nanoeffects]`,r=/* @__PURE__ */ new Map;return({id:e,parent:i,type:a,effect:o,phase:s,payload:c,error:l})=>{r.has(e)||r.set(e,typeof i==`number`?(r.get(i)??0)+1:0);let u=` `.repeat(r.get(e)??0);s!==`start`&&r.delete(e);let d=`${n} ${u}${a} · ${o} ${s}`;s===`error`?t?.error(d,l):t?.debug(d,c)}},i=(e={})=>{let t=e.performance??globalThis.performance,n=/* @__PURE__ */ new Map;return({id:e,parent:r,type:i,effect:a,phase:o,error:s})=>{if(!t)return;if(o===`start`){n.set(e,t.now());return}let c=`${i} · ${a} (${o})`,l={id:e,parent:r,phase:o,...o===`error`&&{error:String(s)}},u=n.get(e);n.delete(e),typeof u==`number`?t.measure(c,{start:u,end:t.now(),detail:l}):t.mark(c,{detail:l})}},a=()=>{let e=[];return Object.assign(t=>{e.push(t)},{events:e,clear:()=>{e.length=0}})},o=()=>{},s=(e={})=>{let t=e.extension??globalThis.__REDUX_DEVTOOLS_EXTENSION__;if(!t)return o;let
|
|
1
|
+
import{n as e,t}from"./onAbort-BgMfspK4.js";import{n}from"./promise-CSLpzwSR.js";const r=(e={})=>{let t=e.console??globalThis.console,n=e.prefix??`[nanoeffects]`,r=/* @__PURE__ */ new Map;return({id:e,parent:i,type:a,effect:o,phase:s,payload:c,error:l})=>{r.has(e)||r.set(e,typeof i==`number`?(r.get(i)??0)+1:0);let u=` `.repeat(r.get(e)??0);s!==`start`&&r.delete(e);let d=`${n} ${u}${a} · ${o} ${s}`;s===`error`?t?.error(d,l):t?.debug(d,c)}},i=(e={})=>{let t=e.performance??globalThis.performance,n=/* @__PURE__ */ new Map;return({id:e,parent:r,type:i,effect:a,phase:o,error:s})=>{if(!t)return;if(o===`start`){n.set(e,t.now());return}let c=`${i} · ${a} (${o})`,l={id:e,parent:r,phase:o,...o===`error`&&{error:String(s)}},u=n.get(e);n.delete(e),typeof u==`number`?t.measure(c,{start:u,end:t.now(),detail:l}):t.mark(c,{detail:l})}},a=()=>{let e=[];return Object.assign(t=>{e.push(t)},{events:e,clear:()=>{e.length=0}})},o=()=>{},s=(e={})=>{let t=e.extension??globalThis.__REDUX_DEVTOOLS_EXTENSION__;if(!t)return o;let{starts:n=!1,depth:r=1,maxAge:i}=e,a=t.connect({name:e.name??`nanoeffects`,...i!==void 0&&{maxAge:i}}),s=/* @__PURE__ */ new Map,c=/* @__PURE__ */ new Map,l=()=>({running:Object.fromEntries(s)});return a.init(l()),({error:e,...t})=>{let i=(t.parent===void 0?-1:c.get(t.parent)??-1)+1,o=i<=r;t.phase===`start`?(c.set(t.id,i),o&&s.set(t.id,{type:t.type,effect:t.effect})):(c.delete(t.id),s.delete(t.id)),o&&(t.phase!==`start`||n)&&a.send({...t,type:`${t.type}/${t.effect}/${t.phase}`,event:t.type,...t.phase===`error`&&{error:e instanceof Error?e.message:e}},l())}},c=t=>{let n=typeof t==`function`?[t]:[...t??[]];return n.length===0?null:t=>{for(let r of n)try{r(t)}catch(t){e(`trace logger failed`,t)}}},l=()=>{},u=(e,r={})=>{let i=c(e),{filter:a,sample:o=1}=r,s=0,u=e=>typeof o==`function`?o({type:e.type,payload:e.payload}):Math.random()<o,d={task:(e,t)=>({id:++s,parent:t?.id,type:e.type,payload:e.payload,sampled:t?.sampled??u(e)}),report:(e,t,n,r)=>{if(!e.sampled)return;let o={id:e.id,type:e.type,effect:t,phase:n,payload:e.payload};typeof e.parent==`number`&&(o.parent=e.parent),n===`error`&&(o.error=r),(!a||a(o))&&i?.(o)},settler:(e,t)=>{if(!e.sampled)return l;let n=!1;return(r,i)=>{n||(n=!0,d.report(e,t,r,i))}},run:(e,r,i,a)=>{if(!e.sampled)return a();let o=d.settler(e,r);d.report(e,r,`start`),t({signal:i},()=>o(`cancel`));let s;try{s=a()}catch(e){throw o(`error`,e),e}return n(s)?Promise.resolve(s).then(e=>(o(`done`),e),e=>{throw o(`error`,e),e}):(o(`done`),s)}};return d};export{r as consoleLogger,a as createTraceRecorder,u as createTracer,i as performanceLogger,s as reduxDevtools};
|
package/docs/README.md
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
# Documentation
|
|
2
2
|
|
|
3
|
+
Start with the [Guide](guide.md): from a bare bus to modules, one step at a time. The pages below are the reference.
|
|
4
|
+
|
|
5
|
+
- [Guide](guide.md)
|
|
3
6
|
- [Policies](policies.md): `latest`, `leading`, `debounce`, `throttle`, `queue`, `key`
|
|
4
7
|
- [Effects and cancellation](effects.md): `retry`, `timeout`, `poll`, `take`, `all`, `allSettled`, `race`, `ctx.on`
|
|
5
8
|
- [Actions, commands, jobs and modules](actions.md)
|
|
@@ -8,5 +11,5 @@
|
|
|
8
11
|
- [Tracing](tracing.md): loggers, Redux DevTools, sampling, the `notrace` build
|
|
9
12
|
- [Redux, Zustand, MobX](stores.md)
|
|
10
13
|
- [Observable: events as streams](observable.md): `createObserve` for RxJS and friends
|
|
11
|
-
- [Hot reload](hmr.md)
|
|
14
|
+
- [Hot reload and dev diagnostics](hmr.md): modules replaced by name, `devPlugin`
|
|
12
15
|
- [Semantics](semantics.md)
|
package/docs/actions.md
CHANGED
|
@@ -18,8 +18,11 @@ const getUser = createCommand("user/get", (id: string, { signal }) => fetchUser(
|
|
|
18
18
|
// a contract without a handler: the code that sends mail is elsewhere
|
|
19
19
|
const sendMail = createCommand<Mail, void>("mail/send");
|
|
20
20
|
|
|
21
|
-
// a command whose outcome is sent on as
|
|
22
|
-
const loadUser = createJob("user/load", fetchUser, {
|
|
21
|
+
// a command whose outcome is sent on as actions: the command and its two actions together
|
|
22
|
+
const { command: loadUser, successAction, failAction } = createJob("user/load", fetchUser, {
|
|
23
|
+
success: userLoaded, // an action creator that exists: used and returned as it is
|
|
24
|
+
fail: "user/failed", // a string: the job makes the action creator
|
|
25
|
+
});
|
|
23
26
|
```
|
|
24
27
|
|
|
25
28
|
**Actions.** `createAction(type)` returns a creator, with no generics: it keeps the literal type, and the bus checks the payload against its event map (`bus.emit(userLoaded(5))` is an error when `"user/loaded"` is a `User`). Without an event map give the payload type, `createAction<User>("user/loaded")`. The creator: `userLoaded(user)` is `{ type, payload }`, `userLoaded.type` is the type, `userLoaded.match(action)` narrows an action. `createAction(type, prepare)` builds the payload from several arguments. A creator works as the event of its type: `bus.emit(userLoaded(user))`, `bus.on(userLoaded, fn)`.
|
|
@@ -31,30 +34,36 @@ const loadUser = createJob("user/load", fetchUser, { done: userLoaded, fail: loa
|
|
|
31
34
|
```ts
|
|
32
35
|
import { createCommands, bindHandler } from "nanoeffects/actions";
|
|
33
36
|
|
|
34
|
-
const
|
|
35
|
-
const
|
|
37
|
+
const bus = createBus<Events>();
|
|
38
|
+
const commands = createCommands(bus, [bindHandler(sendMail, smtpSend)]); // attached to the bus
|
|
36
39
|
|
|
37
40
|
const unbind = commands.handle(getUser, async () => fakeUser); // later, e.g. in a test
|
|
38
41
|
unbind(); // the command's own handler is back; the latest binding wins
|
|
39
42
|
```
|
|
40
43
|
|
|
41
|
-
A command with no handler anywhere throws `No handler for command "..."` from `emit`. The registry lives in `nanoeffects/actions`, so a bus without
|
|
44
|
+
A command with no handler anywhere throws `No handler for command "..."` from `emit`. The registry lives in `nanoeffects/actions`, so a bus without one carries none of this code; without it `emit(command, payload)` simply runs the command's own handler. `createCommands(bus)` sets the registry as `bus.commands`, and a second call on the same bus replaces it. There is no `commands` option in `createBus`; a custom runner is assigned, `bus.commands = { run }`.
|
|
45
|
+
|
|
46
|
+
**Jobs.** `createJob(type, handler, { success, fail })` makes a command that sends its outcome on as actions, for when nobody waits for the result, and returns `{ command, successAction, failAction }`. When the handler succeeds, `successAction(result)` is emitted on the bus, and when it fails, `failAction(error)`.
|
|
42
47
|
|
|
43
|
-
|
|
48
|
+
- `success` and `fail` are a string, from which the job makes an action creator with `createAction` (the payload is the result, or the error), or an action creator that exists already, which is used and returned as it is. A missing one is made with the type `<type>/success` or `<type>/fail`.
|
|
49
|
+
- `bus.emit(command, payload)` returns a promise of the result. An error of the handler always counts as handled: it goes to `failAction` and the promise resolves with `undefined`. For a result that must reject, use a command.
|
|
50
|
+
- The actions are emitted as the task that ran the job, also for a handler bound with `commands.handle`, and are not sent once the task is aborted. A missing handler is not an outcome: `emit` throws `No handler for command "..."`.
|
|
51
|
+
- Calling `command(payload)` directly runs only the handler.
|
|
44
52
|
|
|
45
53
|
## Modules
|
|
46
54
|
|
|
47
|
-
`
|
|
55
|
+
`bus.use(modulePlugin(modules))`, with `modulePlugin` from `nanoeffects/actions`, assembles an app from modules and returns `mount`, `unmount`, `isMounted`, `dispose` and `commands`, the registry of command handlers. A module is what a domain of the app needs: the commands it handles, the events it listens to, its sub-modules and its background tasks.
|
|
48
56
|
|
|
49
57
|
```ts
|
|
50
58
|
const userModule = createModule<Events>("user", (m) => {
|
|
51
|
-
m.handle(getUser, fetchUser);
|
|
59
|
+
m.handle(getUser, fetchUser); // a contract gets its handler here
|
|
60
|
+
m.use(saveUser, authModule); // a command that carries a handler, and a sub-module
|
|
52
61
|
m.on("login", (user, ctx) => ctx.emit("loaded", user));
|
|
53
62
|
m.spawn(async (_, ctx) => { /* background work, ends with the module */ });
|
|
54
63
|
});
|
|
55
64
|
|
|
56
65
|
const bus = createBus<Events>();
|
|
57
|
-
const app =
|
|
66
|
+
const app = bus.use(modulePlugin([userModule]));
|
|
58
67
|
|
|
59
68
|
const unmount = app.mount(orderModule); // later, e.g. after a lazy import
|
|
60
69
|
app.commands.handle(getUser, fakeUser); // in a test
|
|
@@ -63,6 +72,7 @@ app.dispose(); // unmounts every module
|
|
|
63
72
|
|
|
64
73
|
- **Unmounting undoes everything** the module did: its subscriptions, its bound commands, its sub-modules and its background tasks, which are aborted.
|
|
65
74
|
- **A module is known by its name.** Mounting a module whose name is taken replaces the mounted one. That is what hot reload needs: see [hmr.md](hmr.md).
|
|
66
|
-
- **The registry.** If
|
|
75
|
+
- **The registry.** If `createCommands(bus)` was called, that registry is used; otherwise the module plugin attaches its own. Either way it is `bus.commands` and `app.commands`, so the commands that modules bind are the ones the bus runs.
|
|
67
76
|
- A disposed app cannot mount modules.
|
|
68
|
-
- A module context is a task context plus `handle` (
|
|
77
|
+
- A module context is a task context plus `handle` (give a command a handler: for a contract, or to override), `use` (bring sub-modules and commands that carry a handler: `m.use(getUser, saveUser, subModule)`, in any order; the returned function undoes just that call) and `spawn` (a background task, aborted on unmount).
|
|
78
|
+
- A command that carries a handler keeps answering after its module is unmounted: the handler is its own, and `use` only brings the command and tracks it in the registry. Use `handle` for a handler that should live only as long as the module.
|
package/docs/context.md
CHANGED
|
@@ -13,4 +13,3 @@ The fields are in the context of handlers, `ctx.run`, listeners added with `ctx.
|
|
|
13
13
|
|
|
14
14
|
- The fields of the library (`signal`, `emit`, `run`, ...) win when the names are the same.
|
|
15
15
|
- `context` can also be a function, `(task) => fields`, called with `{ type, payload }` of each task, for fields that depend on the task.
|
|
16
|
-
- Several stores are fields of one object: `WithContext<{ stores: { user: UserStore; cart: CartStore } }>`.
|