nanoeffects 0.23.1 → 0.24.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/actions.d.ts +2 -2
- package/dist/delay-18LJ8jSk.js +1 -0
- package/dist/dev.d.ts +1 -1
- package/dist/effects.d.ts +18 -6
- package/dist/effects.js +1 -1
- package/dist/{module-D1VVKbE0.d.ts → module-ChMx7hHT.d.ts} +1 -1
- package/dist/notrace/actions.d.ts +1 -1
- package/dist/notrace/delay-Besb3X1O.js +1 -0
- package/dist/notrace/effects.d.ts +18 -6
- package/dist/notrace/effects.js +1 -1
- package/dist/notrace/{plugin-BEvYzo8Q.d.ts → plugin-jkWtYPT7.d.ts} +50 -3
- package/dist/notrace/policies.js +1 -1
- package/dist/{plugin-BZK83Z3N.d.ts → plugin-CGIdsEGF.d.ts} +50 -3
- package/dist/policies.js +1 -1
- package/dist/scope.d.ts +1 -1
- package/dist/{types-CBoV9m7W.d.ts → types-B0DMvfsU.d.ts} +1 -1
- package/docs/effects.md +61 -6
- package/docs/guide.md +13 -1
- package/docs/migrating-from-rxjs.md +4 -4
- package/llms-full.txt +78 -11
- package/package.json +2 -2
- package/dist/delay-mxZkTg17.js +0 -1
- package/dist/notrace/delay-CqKplsaY.js +0 -1
package/dist/actions.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { H as PayloadOf, T as EventKey, W as Task, c as WithScope, h as Bus, n as Free, o as Scope, r as FreeActionCreator, t as ActionCreator, z as EventMap } from "./action-creator-Bpa8BUS9.js";
|
|
2
|
-
import { r as Scoped, t as FieldsOfScope } from "./types-
|
|
3
|
-
import { a as createModule, c as CarryingCalls, d as commandsPlugin, f as createCommand, l as MadeCommand, n as ModuleApi, o as modulePlugin, r as ModuleContext, s as Binding, t as Module, u as bindHandler } from "./module-
|
|
2
|
+
import { r as Scoped, t as FieldsOfScope } from "./types-B0DMvfsU.js";
|
|
3
|
+
import { a as createModule, c as CarryingCalls, d as commandsPlugin, f as createCommand, l as MadeCommand, n as ModuleApi, o as modulePlugin, r as ModuleContext, s as Binding, t as Module, u as bindHandler } from "./module-ChMx7hHT.js";
|
|
4
4
|
import { t as OriginOptions } from "./origin-key-CxK0SkeG.js";
|
|
5
5
|
//#region src/actions/action.d.ts
|
|
6
6
|
type ScopedCreator<P, T extends string, F> = [P] extends [Free] ? FreeActionCreator<T, F> & WithScope<F> : ActionCreator<P, T, PayloadOf<P>, F> & WithScope<F>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{u as e}from"./context-UcmrAIhP.js";const t=e=>typeof e==`object`&&!!e,n=2**31-1,r=(e,t)=>{let r={id:null};if(t===1/0)return r;let i=t=>{r.id=setTimeout(()=>{t>n?i(t-n):(r.id=null,e())},Math.min(t,n))};return i(t>0?t:0),r},i=e=>{e.id!==null&&(clearTimeout(e.id),e.id=null)},a=(t,n)=>new Promise((a,o)=>{let s=r(()=>{c(),a()},typeof n==`function`?n():n),c=e(t,e=>{i(s),o(e)})});function o(e,n){return t(e)?a(e,n):t=>a(t,e)}export{t as i,i as n,r,o as t};
|
package/dist/dev.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { J as UnsubscribeCallback, h as Bus, z as EventMap } from "./action-creator-Bpa8BUS9.js";
|
|
2
|
-
import { i as WithApp, n as ModuleApi } from "./module-
|
|
2
|
+
import { i as WithApp, n as ModuleApi } from "./module-ChMx7hHT.js";
|
|
3
3
|
//#region src/dev/types.d.ts
|
|
4
4
|
/** The parts of what `modulePlugin` returned that the diagnostics report. */
|
|
5
5
|
type ReportedApp<E extends EventMap> = Pick<ModuleApi<E>, "mount" | "unmount" | "isMounted">;
|
package/dist/effects.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { P as WithSignal, W as Task, u as Effect, z as EventMap } from "./action-creator-Bpa8BUS9.js";
|
|
2
|
-
import { a as RaceStarter, c as all, d as Starter, f as
|
|
1
|
+
import { P as WithSignal, W as Task, b as Context, u as Effect, z as EventMap } from "./action-creator-Bpa8BUS9.js";
|
|
2
|
+
import { a as RaceStarter, c as all, d as Starter, f as StarterOf, i as take, l as ChildOf, n as effectsPlugin, o as race, p as delay, r as TakeOptions, s as allSettled, u as EffectContext } from "./plugin-CGIdsEGF.js";
|
|
3
3
|
//#region src/utils/onAbort.d.ts
|
|
4
4
|
export declare const onAbort: (ctx: {
|
|
5
5
|
signal?: AbortSignal | undefined;
|
|
@@ -68,6 +68,18 @@ type CancellableExecutor<T> = (handle: CancellableHandle<T>) => void;
|
|
|
68
68
|
*/
|
|
69
69
|
export declare const cancellable: <T = void>(ctx: WithSignal, executor: CancellableExecutor<T>) => Promise<T>;
|
|
70
70
|
//#endregion
|
|
71
|
+
//#region src/effects/starter-call.d.ts
|
|
72
|
+
/**
|
|
73
|
+
* What the Task of `retry`, `timeout` and `poll` is: a Task for every payload, and a starter of
|
|
74
|
+
* `race`, `all` and `allSettled` when its function accepts `undefined` as the payload (a group has
|
|
75
|
+
* none). The Task signature is last: TypeScript infers a handler from the last one.
|
|
76
|
+
*/
|
|
77
|
+
type Startable<P, E extends EventMap, R> = StarterPayload<P, E> extends true ? {
|
|
78
|
+
(child: Context<E>): R;
|
|
79
|
+
(payload: P, ctx: Context<E>): R;
|
|
80
|
+
} : Task<P, E, R>;
|
|
81
|
+
type StarterPayload<P, E extends EventMap> = undefined extends P ? true : Context<E> extends P ? true : false;
|
|
82
|
+
//#endregion
|
|
71
83
|
//#region src/effects/poll.d.ts
|
|
72
84
|
type PollOptions = {
|
|
73
85
|
/** Also call `fn` at once, not only after the first `ms`. Default `false`. */
|
|
@@ -105,7 +117,7 @@ type PollOptions = {
|
|
|
105
117
|
* ```
|
|
106
118
|
*/
|
|
107
119
|
type PollMs = number | ((call: number) => number);
|
|
108
|
-
export declare function poll<P, E extends EventMap, R>(ms: PollMs, task: Task<P, E, R>, options?: PollOptions):
|
|
120
|
+
export declare function poll<P, E extends EventMap, R>(ms: PollMs, task: Task<P, E, R>, options?: PollOptions): Startable<P, E, Promise<void>>;
|
|
109
121
|
export declare function poll(ctx: WithSignal, fn: (tick: number) => unknown, ms: PollMs, options?: PollOptions): Promise<void>;
|
|
110
122
|
//#endregion
|
|
111
123
|
//#region src/effects/retry.d.ts
|
|
@@ -143,7 +155,7 @@ type RetryOptions = {
|
|
|
143
155
|
* ```
|
|
144
156
|
*/
|
|
145
157
|
type RetryFn<T> = (attempt: number) => T | PromiseLike<T>;
|
|
146
|
-
export declare function retry<P, E extends EventMap, R>(task: Task<P, E, R>, options?: RetryOptions):
|
|
158
|
+
export declare function retry<P, E extends EventMap, R>(task: Task<P, E, R>, options?: RetryOptions): Startable<P, E, Promise<Awaited<R>>>;
|
|
147
159
|
export declare function retry<T>(ctx: {
|
|
148
160
|
signal?: AbortSignal;
|
|
149
161
|
}, fn: RetryFn<T>, options?: RetryOptions): Promise<T>;
|
|
@@ -170,9 +182,9 @@ export declare function retry<T>(ctx: {
|
|
|
170
182
|
* });
|
|
171
183
|
* ```
|
|
172
184
|
*/
|
|
173
|
-
export declare function timeout<P, E extends EventMap, R>(ms: number, task: Task<P, E, R>):
|
|
185
|
+
export declare function timeout<P, E extends EventMap, R>(ms: number, task: Task<P, E, R>): Startable<P, E, Promise<Awaited<R>>>;
|
|
174
186
|
export declare function timeout<C extends {
|
|
175
187
|
signal?: AbortSignal;
|
|
176
188
|
}, T>(ctx: C, ms: number, starter: Starter<T, ChildOf<C>>): Promise<T>;
|
|
177
189
|
//#endregion
|
|
178
|
-
export { type BackoffOptions, type CancellableExecutor, type CancellableHandle, type Effect, type EffectContext, type PollOptions, type RaceStarter, type RetryOptions, type TakeOptions, all, allSettled, delay, effectsPlugin, race, take };
|
|
190
|
+
export { type BackoffOptions, type CancellableExecutor, type CancellableHandle, type Effect, type EffectContext, type PollOptions, type RaceStarter, type RetryOptions, type StarterOf, type TakeOptions, all, allSettled, delay, effectsPlugin, race, take };
|
package/dist/effects.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{i as e,n as t,r as n,t as r}from"./delay-18LJ8jSk.js";import{d as i,i as a,o,s,t as c,u as l}from"./context-UcmrAIhP.js";const u=(e,t)=>t?.signal?new Promise((n,r)=>{let i=l(t,r);e.then(n,r).finally(i)}):e,d=async(e,t,n,r)=>{t?.signal?.throwIfAborted();let{ctx:i,unlink:o}=a(t??{}),d=c(i,e);s(i,e,`start`),l(i,()=>d(`cancel`));try{let e=await u(n(i),t);return d(`done`),r?.(!1),e}catch(e){throw d(`error`,e),r?.(!0),e}finally{o()}},f=async(e,t)=>{let{ctx:n,unlink:r}=a(e);try{return await o(n,`run`,()=>t(n))}finally{r()}},p=e=>e,m=(e,t)=>n=>e(t,p(n)),h=e=>Array.isArray(e)?Array(e.length):{},g=(e,t)=>{let n=Object.entries(t).map(([t,n])=>{let r=a(e),i=()=>n(r.ctx);return{key:t,task:new Promise(e=>e(o(r.ctx,`run`,i))).finally(r.unlink),cancel:r.ctx.abort}});return{tasks:n.map(({key:e,task:t})=>[e,t]),cancelAll:()=>{for(let e of n)e.cancel()}}},_=(t,n)=>{if(t.length===2)return n(...t);let[r]=t;if(e(Reflect.get(r,`signal`)))throw TypeError(`A group takes effects: call it as (effects), or as (ctx, effects); a context alone has none`);return e=>n(e,r)},v=(e,t,n,r,i)=>{let a=()=>{};return d(e,t,async e=>{let t=g(e,n);return a=t.cancelAll,r(t.tasks)},e=>{(e||i===`end`)&&a()})};function y(...e){return _(e,b)}const b=(e,t)=>v(`all`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>e)),r=h(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`),x=e=>e.then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}));function S(...e){return _(e,C)}const C=(e,t)=>v(`allSettled`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>x(e))),r=h(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`),w=e=>e>0?e:0,T=(e={})=>{let t=w(e.base??100),n=e.factor??2,r=w(e.max??1/0),i=e.jitter??!1;return e=>{let a=w(Math.min(r,t*n**(e-1)));return i?Math.random()*a||0:a}},E=(e,t)=>e.signal.aborted?Promise.reject(e.signal.reason):new Promise((n,r)=>{let a=[],o=`pending`,s=e=>{try{e()}catch(e){i(`cancel cleanup failed`,e)}},c=l(e,e=>{o=`cancelled`;for(let e of a.reverse())s(e);r(e)}),u=e=>(...t)=>{o===`pending`&&(o=`settled`,c(),a.length=0,e(...t))},d=e=>{o===`pending`?a.push(e):o===`cancelled`&&s(e)};try{t({resolve:u(n),reject:u(r),onCancel:d})}catch(e){u(r)(e)}}),D=Symbol(`nanoeffects.effects.effect`),O=e=>t=>{let n=t.addContext,r=Object.entries(e);return t.addContext=e=>{n?.(e);for(let[t,n]of r){let r=Reflect.get(e,t);if(r===void 0||r[D]===n){let r=(...t)=>n(e,...t);r[D]=n,Reflect.set(e,t,r)}}},t},k=()=>/* @__PURE__ */ TypeError(`A Task is called as (payload, ctx), or as (ctx) when a group starts it; the single argument is not a context`),A=t=>{if(e(t)&&`signal`in t)return t;throw k()},j=(e,t,n)=>t===void 0?n(A(e),void 0):n(t,e),M=(e,r,i,a)=>{if(e.signal.aborted)return Promise.resolve();let o=a.leading??!1,s=a.waitForFn??!1;return d(`poll`,e,e=>new Promise((a,c)=>{let u=0,d=null,p=()=>{d!==null&&(t(d),d=null)},m=e=>{try{d=n(h,typeof i==`function`?i(e):i)}catch(e){p(),c(e)}},h=()=>{d=null,s||m(u+1),g()},g=()=>{let t=u++;f(e,e=>r(e,t)).then(()=>{s&&!e.signal.aborted&&m(u)},e=>{p(),c(e)})};l(e,p),o?(g(),s||m(u)):m(0)})).catch(t=>{if(!e.signal.aborted)throw t})};function N(e,t,n,r={}){if(typeof e!=`object`){let r=t,i=n??{},a=(t,n)=>M(t,m(r,n),e,i);return(e,t)=>j(e,t,a)}let i=t;return M(e,(e,t)=>i(t),n,r)}function P(...e){return _(e,F)}const F=(e,t)=>{let n=h(t);return Object.keys(t).length===0?Promise.resolve(n):v(`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`)},I=(e,t,n)=>typeof e==`function`?e(t,n):e,L=e=>({times:e.times??3,delay:e.delay??0,shouldRetry:e.shouldRetry??(()=>!0)}),R=(e,t,n)=>d(`retry`,e,async e=>{let{times:i,delay:a,shouldRetry:o}=L(n);for(let n=1;;n++)try{return await f(e,e=>t(e,n))}catch(t){if(e.signal.throwIfAborted(),!(n<i)||!o(t,n))throw t;let s=I(a,n,t);s>0&&await r(e,s)}});function z(e,t,n={}){if(typeof e==`function`){let n=e,r=t??{},i=(e,t)=>R(e,m(n,t),r);return(e,t)=>j(e,t,i)}let r=t;return R(e,(e,t)=>r(t),n)}const B=(e,t,n={})=>d(`take`,e,r=>new Promise((i,a)=>{let{predicate:o}=n,s=[],c=()=>{for(let e of s)e()},u=e=>{c(),a(e)},d=t;s.push(e.on(d,e=>{(!o||o(e))&&(c(),i(e))})),s.push(l(r,u)),s.push(l({signal:n.signal},u))}));function V(t,n,r){if(e(t))return B(t,n,r);let i=n;return e=>B(e,t,i)}const H=(e,r,i)=>d(`timeout`,e,async e=>{let s=a(e),c=n(()=>s.ctx.abort(new DOMException(`Timed out after ${r}ms`,`TimeoutError`)),r);try{return await u(Promise.resolve(o(s.ctx,`run`,()=>i(s.ctx))),s.ctx)}finally{t(c),s.unlink()}});function U(e,t,n){if(typeof e==`number`){let n=t,r=(t,r)=>H(t,e,m(n,r));return(e,t)=>j(e,t,r)}return H(e,t,n)}export{y as all,S as allSettled,T as backoff,E as cancellable,r as delay,O as effectsPlugin,l as onAbort,N as poll,P as race,z as retry,V as take,U as timeout};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { H as PayloadOf, J as UnsubscribeCallback, W as Task, _ as Command, b as Context, c as WithScope, h as Bus, o as Scope, v as CommandCall, y as Commands, z as EventMap } from "./action-creator-Bpa8BUS9.js";
|
|
2
|
-
import { n as ScopeSlots, r as Scoped, t as FieldsOfScope } from "./types-
|
|
2
|
+
import { n as ScopeSlots, r as Scoped, t as FieldsOfScope } from "./types-B0DMvfsU.js";
|
|
3
3
|
//#region src/actions/command.d.ts
|
|
4
4
|
/** What `createCommand` returns: a command that also tells whether an action is of its type. */
|
|
5
5
|
type MadeCommand<P, R, T extends string> = Command<P, R> & {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { C as EventKey, F as EventMap, L as PayloadOf, R as Task, _ as Commands, a as Scope, g as CommandCall, h as Command, n as Free, o as WithFields, p as Bus, r as FreeActionCreator, s as WithScope, t as ActionCreator, u as Effects, v as Context, z as UnsubscribeCallback } from "./action-creator-D2CotugT.js";
|
|
2
|
-
import { t as BoundOf } from "./plugin-
|
|
2
|
+
import { t as BoundOf } from "./plugin-jkWtYPT7.js";
|
|
3
3
|
import { t as OriginOptions } from "./origin-key-CxK0SkeG.js";
|
|
4
4
|
//#region src/scope/types.d.ts
|
|
5
5
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as e}from"./context-_HWcdjZf.js";const t=e=>typeof e==`object`&&!!e,n=2**31-1,r=(e,t)=>{let r={id:null};if(t===1/0)return r;let i=t=>{r.id=setTimeout(()=>{t>n?i(t-n):(r.id=null,e())},Math.min(t,n))};return i(t>0?t:0),r},i=e=>{e.id!==null&&(clearTimeout(e.id),e.id=null)},a=(t,n)=>new Promise((a,o)=>{let s=r(()=>{c(),a()},typeof n==`function`?n():n),c=e(t,e=>{i(s),o(e)})});function o(e,n){return t(e)?a(e,n):t=>a(t,e)}export{t as i,i as n,r,o as t};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { F as EventMap, M as WithSignal, R as Task, l as Effect } from "./action-creator-D2CotugT.js";
|
|
2
|
-
import { a as RaceStarter, c as all, d as Starter, f as
|
|
1
|
+
import { F as EventMap, M as WithSignal, R as Task, l as Effect, v as Context } from "./action-creator-D2CotugT.js";
|
|
2
|
+
import { a as RaceStarter, c as all, d as Starter, f as StarterOf, i as take, l as ChildOf, n as effectsPlugin, o as race, p as delay, r as TakeOptions, s as allSettled, u as EffectContext } from "./plugin-jkWtYPT7.js";
|
|
3
3
|
//#region src/utils/onAbort.d.ts
|
|
4
4
|
export declare const onAbort: (ctx: {
|
|
5
5
|
signal?: AbortSignal | undefined;
|
|
@@ -68,6 +68,18 @@ type CancellableExecutor<T> = (handle: CancellableHandle<T>) => void;
|
|
|
68
68
|
*/
|
|
69
69
|
export declare const cancellable: <T = void>(ctx: WithSignal, executor: CancellableExecutor<T>) => Promise<T>;
|
|
70
70
|
//#endregion
|
|
71
|
+
//#region src/effects/starter-call.d.ts
|
|
72
|
+
/**
|
|
73
|
+
* What the Task of `retry`, `timeout` and `poll` is: a Task for every payload, and a starter of
|
|
74
|
+
* `race`, `all` and `allSettled` when its function accepts `undefined` as the payload (a group has
|
|
75
|
+
* none). The Task signature is last: TypeScript infers a handler from the last one.
|
|
76
|
+
*/
|
|
77
|
+
type Startable<P, E extends EventMap, R> = StarterPayload<P, E> extends true ? {
|
|
78
|
+
(child: Context<E>): R;
|
|
79
|
+
(payload: P, ctx: Context<E>): R;
|
|
80
|
+
} : Task<P, E, R>;
|
|
81
|
+
type StarterPayload<P, E extends EventMap> = undefined extends P ? true : Context<E> extends P ? true : false;
|
|
82
|
+
//#endregion
|
|
71
83
|
//#region src/effects/poll.d.ts
|
|
72
84
|
type PollOptions = {
|
|
73
85
|
/** Also call `fn` at once, not only after the first `ms`. Default `false`. */
|
|
@@ -105,7 +117,7 @@ type PollOptions = {
|
|
|
105
117
|
* ```
|
|
106
118
|
*/
|
|
107
119
|
type PollMs = number | ((call: number) => number);
|
|
108
|
-
export declare function poll<P, E extends EventMap, R>(ms: PollMs, task: Task<P, E, R>, options?: PollOptions):
|
|
120
|
+
export declare function poll<P, E extends EventMap, R>(ms: PollMs, task: Task<P, E, R>, options?: PollOptions): Startable<P, E, Promise<void>>;
|
|
109
121
|
export declare function poll(ctx: WithSignal, fn: (tick: number) => unknown, ms: PollMs, options?: PollOptions): Promise<void>;
|
|
110
122
|
//#endregion
|
|
111
123
|
//#region src/effects/retry.d.ts
|
|
@@ -143,7 +155,7 @@ type RetryOptions = {
|
|
|
143
155
|
* ```
|
|
144
156
|
*/
|
|
145
157
|
type RetryFn<T> = (attempt: number) => T | PromiseLike<T>;
|
|
146
|
-
export declare function retry<P, E extends EventMap, R>(task: Task<P, E, R>, options?: RetryOptions):
|
|
158
|
+
export declare function retry<P, E extends EventMap, R>(task: Task<P, E, R>, options?: RetryOptions): Startable<P, E, Promise<Awaited<R>>>;
|
|
147
159
|
export declare function retry<T>(ctx: {
|
|
148
160
|
signal?: AbortSignal;
|
|
149
161
|
}, fn: RetryFn<T>, options?: RetryOptions): Promise<T>;
|
|
@@ -170,9 +182,9 @@ export declare function retry<T>(ctx: {
|
|
|
170
182
|
* });
|
|
171
183
|
* ```
|
|
172
184
|
*/
|
|
173
|
-
export declare function timeout<P, E extends EventMap, R>(ms: number, task: Task<P, E, R>):
|
|
185
|
+
export declare function timeout<P, E extends EventMap, R>(ms: number, task: Task<P, E, R>): Startable<P, E, Promise<Awaited<R>>>;
|
|
174
186
|
export declare function timeout<C extends {
|
|
175
187
|
signal?: AbortSignal;
|
|
176
188
|
}, T>(ctx: C, ms: number, starter: Starter<T, ChildOf<C>>): Promise<T>;
|
|
177
189
|
//#endregion
|
|
178
|
-
export { type BackoffOptions, type CancellableExecutor, type CancellableHandle, type Effect, type EffectContext, type PollOptions, type RaceStarter, type RetryOptions, type TakeOptions, all, allSettled, delay, effectsPlugin, race, take };
|
|
190
|
+
export { type BackoffOptions, type CancellableExecutor, type CancellableHandle, type Effect, type EffectContext, type PollOptions, type RaceStarter, type RetryOptions, type StarterOf, type TakeOptions, all, allSettled, delay, effectsPlugin, race, take };
|
package/dist/notrace/effects.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{i as e,n as t,r as n,t as r}from"./delay-Besb3X1O.js";import{a as i,c as a,i as o,l as s,o as c,t as l}from"./context-_HWcdjZf.js";const u=(e,t)=>t?.signal?new Promise((n,r)=>{let i=a(t,r);e.then(n,r).finally(i)}):e,d=async(e,t,n,r)=>{t?.signal?.throwIfAborted();let{ctx:i,unlink:s}=o(t??{}),d=l(i,e);c(i,e,`start`),a(i,()=>d(`cancel`));try{let e=await u(n(i),t);return d(`done`),r?.(!1),e}catch(e){throw d(`error`,e),r?.(!0),e}finally{s()}},f=async(e,t)=>{let{ctx:n,unlink:r}=o(e);try{return await i(n,`run`,()=>t(n))}finally{r()}},p=e=>e,m=(e,t)=>n=>e(t,p(n)),h=e=>Array.isArray(e)?Array(e.length):{},g=(e,t)=>{let n=Object.entries(t).map(([t,n])=>{let r=o(e),a=()=>n(r.ctx);return{key:t,task:new Promise(e=>e(i(r.ctx,`run`,a))).finally(r.unlink),cancel:r.ctx.abort}});return{tasks:n.map(({key:e,task:t})=>[e,t]),cancelAll:()=>{for(let e of n)e.cancel()}}},_=(t,n)=>{if(t.length===2)return n(...t);let[r]=t;if(e(Reflect.get(r,`signal`)))throw TypeError(`A group takes effects: call it as (effects), or as (ctx, effects); a context alone has none`);return e=>n(e,r)},v=(e,t,n,r,i)=>{let a=()=>{};return d(e,t,async e=>{let t=g(e,n);return a=t.cancelAll,r(t.tasks)},e=>{(e||i===`end`)&&a()})};function y(...e){return _(e,b)}const b=(e,t)=>v(`all`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>e)),r=h(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`),x=e=>e.then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}));function S(...e){return _(e,C)}const C=(e,t)=>v(`allSettled`,e,t,async e=>{let n=await Promise.all(e.map(([,e])=>x(e))),r=h(t);for(let[t,[i]]of e.entries())r[i]=n[t];return r},`failure`),w=e=>e>0?e:0,T=(e={})=>{let t=w(e.base??100),n=e.factor??2,r=w(e.max??1/0),i=e.jitter??!1;return e=>{let a=w(Math.min(r,t*n**(e-1)));return i?Math.random()*a||0:a}},E=(e,t)=>e.signal.aborted?Promise.reject(e.signal.reason):new Promise((n,r)=>{let i=[],o=`pending`,c=e=>{try{e()}catch(e){s(`cancel cleanup failed`,e)}},l=a(e,e=>{o=`cancelled`;for(let e of i.reverse())c(e);r(e)}),u=e=>(...t)=>{o===`pending`&&(o=`settled`,l(),i.length=0,e(...t))},d=e=>{o===`pending`?i.push(e):o===`cancelled`&&c(e)};try{t({resolve:u(n),reject:u(r),onCancel:d})}catch(e){u(r)(e)}}),D=Symbol(`nanoeffects.effects.effect`),O=e=>t=>{let n=t.addContext,r=Object.entries(e);return t.addContext=e=>{n?.(e);for(let[t,n]of r){let r=Reflect.get(e,t);if(r===void 0||r[D]===n){let r=(...t)=>n(e,...t);r[D]=n,Reflect.set(e,t,r)}}},t},k=()=>/* @__PURE__ */ TypeError(`A Task is called as (payload, ctx), or as (ctx) when a group starts it; the single argument is not a context`),A=t=>{if(e(t)&&`signal`in t)return t;throw k()},j=(e,t,n)=>t===void 0?n(A(e),void 0):n(t,e),M=(e,r,i,o)=>{if(e.signal.aborted)return Promise.resolve();let s=o.leading??!1,c=o.waitForFn??!1;return d(`poll`,e,e=>new Promise((o,l)=>{let u=0,d=null,p=()=>{d!==null&&(t(d),d=null)},m=e=>{try{d=n(h,typeof i==`function`?i(e):i)}catch(e){p(),l(e)}},h=()=>{d=null,c||m(u+1),g()},g=()=>{let t=u++;f(e,e=>r(e,t)).then(()=>{c&&!e.signal.aborted&&m(u)},e=>{p(),l(e)})};a(e,p),s?(g(),c||m(u)):m(0)})).catch(t=>{if(!e.signal.aborted)throw t})};function N(e,t,n,r={}){if(typeof e!=`object`){let r=t,i=n??{},a=(t,n)=>M(t,m(r,n),e,i);return(e,t)=>j(e,t,a)}let i=t;return M(e,(e,t)=>i(t),n,r)}function P(...e){return _(e,F)}const F=(e,t)=>{let n=h(t);return Object.keys(t).length===0?Promise.resolve(n):v(`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`)},I=(e,t,n)=>typeof e==`function`?e(t,n):e,L=e=>({times:e.times??3,delay:e.delay??0,shouldRetry:e.shouldRetry??(()=>!0)}),R=(e,t,n)=>d(`retry`,e,async e=>{let{times:i,delay:a,shouldRetry:o}=L(n);for(let n=1;;n++)try{return await f(e,e=>t(e,n))}catch(t){if(e.signal.throwIfAborted(),!(n<i)||!o(t,n))throw t;let s=I(a,n,t);s>0&&await r(e,s)}});function z(e,t,n={}){if(typeof e==`function`){let n=e,r=t??{},i=(e,t)=>R(e,m(n,t),r);return(e,t)=>j(e,t,i)}let r=t;return R(e,(e,t)=>r(t),n)}const B=(e,t,n={})=>d(`take`,e,r=>new Promise((i,o)=>{let{predicate:s}=n,c=[],l=()=>{for(let e of c)e()},u=e=>{l(),o(e)},d=t;c.push(e.on(d,e=>{(!s||s(e))&&(l(),i(e))})),c.push(a(r,u)),c.push(a({signal:n.signal},u))}));function V(t,n,r){if(e(t))return B(t,n,r);let i=n;return e=>B(e,t,i)}const H=(e,r,a)=>d(`timeout`,e,async e=>{let s=o(e),c=n(()=>s.ctx.abort(new DOMException(`Timed out after ${r}ms`,`TimeoutError`)),r);try{return await u(Promise.resolve(i(s.ctx,`run`,()=>a(s.ctx))),s.ctx)}finally{t(c),s.unlink()}});function U(e,t,n){if(typeof e==`number`){let n=t,r=(t,r)=>H(t,e,m(n,r));return(e,t)=>j(e,t,r)}return H(e,t,n)}export{y as all,S as allSettled,T as backoff,E as cancellable,r as delay,O as effectsPlugin,a as onAbort,N as poll,P as race,z as retry,V as take,U as timeout};
|
|
@@ -7,11 +7,17 @@ import { F as EventMap, I as Keys, c as BoundForm, j as WithContext, p as Bus, r
|
|
|
7
7
|
type NoClash<Fields extends object, E extends EventMap> = [keyof Fields & keyof ContextOf<E>] extends [never] ? unknown : never;
|
|
8
8
|
//#endregion
|
|
9
9
|
//#region src/utils/delay.d.ts
|
|
10
|
+
type Milliseconds = number | (() => number);
|
|
10
11
|
/**
|
|
11
12
|
* Resolves after `ms`, or rejects early if `ctx.signal` aborts. `ms` can be a
|
|
12
13
|
* function that returns the number of ms, called once when the delay starts:
|
|
13
14
|
* handy for a random pause (jitter).
|
|
14
15
|
*
|
|
16
|
+
* Without `ctx`, `delay(ms)` returns a starter for `race`, `all` and
|
|
17
|
+
* `allSettled`: they call it with the context of its own child task, and it
|
|
18
|
+
* waits then. It starts no timer before that, and one starter can be used in
|
|
19
|
+
* several groups. Do not `await` it on its own: it is a function, not a promise.
|
|
20
|
+
*
|
|
15
21
|
* @example
|
|
16
22
|
* ```ts
|
|
17
23
|
* await delay({}, 500);
|
|
@@ -24,11 +30,20 @@ type NoClash<Fields extends object, E extends EventMap> = [keyof Fields & keyof
|
|
|
24
30
|
* await delay(ctx, 1000);
|
|
25
31
|
* await load();
|
|
26
32
|
* });
|
|
33
|
+
*
|
|
34
|
+
* // as a starter: the loser of the race is cancelled
|
|
35
|
+
* const result = await race(ctx, {
|
|
36
|
+
* waited: delay(1000),
|
|
37
|
+
* cancelled: take(cancel),
|
|
38
|
+
* });
|
|
27
39
|
* ```
|
|
28
40
|
*/
|
|
29
|
-
declare
|
|
41
|
+
declare function delay(ms: Milliseconds): (child: {
|
|
42
|
+
signal?: AbortSignal | undefined;
|
|
43
|
+
}) => Promise<void>;
|
|
44
|
+
declare function delay(ctx: {
|
|
30
45
|
signal?: AbortSignal | undefined;
|
|
31
|
-
}, ms:
|
|
46
|
+
}, ms: Milliseconds): Promise<void>;
|
|
32
47
|
//#endregion
|
|
33
48
|
//#region src/effects/run.d.ts
|
|
34
49
|
/** What a starter gets when the effect was called with `{}` or a bare `{ signal }`. */
|
|
@@ -43,6 +58,20 @@ type EffectContext = {
|
|
|
43
58
|
*/
|
|
44
59
|
type ChildOf<C> = C extends Context<infer E> ? Context<E> : EffectContext;
|
|
45
60
|
type Starter<T, Child = EffectContext> = (child: Child) => T | PromiseLike<T>;
|
|
61
|
+
/**
|
|
62
|
+
* A starter of a group on a bus with the events `E`, with the result `R`. A starter written in a
|
|
63
|
+
* group needs no type: the group gives it. Use this for one kept in a variable, where nothing
|
|
64
|
+
* tells the checker which bus it is for.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const load: StarterOf<Events> = all({ user: retry(() => loadUser(1)) });
|
|
69
|
+
* const user: StarterOf<Events, User> = retry(() => loadUser(1));
|
|
70
|
+
*
|
|
71
|
+
* bus.on("open", async (_, ctx) => race(ctx, { load, user }));
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
type StarterOf$1<E extends EventMap, R = unknown> = Starter<R, Context<E>>;
|
|
46
75
|
//#endregion
|
|
47
76
|
//#region src/effects/all.d.ts
|
|
48
77
|
/**
|
|
@@ -66,6 +95,8 @@ declare function all<C extends {
|
|
|
66
95
|
declare function all<C extends {
|
|
67
96
|
signal?: AbortSignal;
|
|
68
97
|
}, const T extends readonly Starter<unknown, ChildOf<C>>[]>(ctx: C, effects: T): Promise<{ -readonly [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
|
|
98
|
+
declare function all<Child, T extends Record<string, Starter<unknown, Child>>>(effects: T): (child: Child) => Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
|
|
99
|
+
declare function all<Child, const T extends readonly Starter<unknown, Child>[]>(effects: T): (child: Child) => Promise<{ -readonly [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
|
|
69
100
|
//#endregion
|
|
70
101
|
//#region src/effects/allSettled.d.ts
|
|
71
102
|
/**
|
|
@@ -92,6 +123,8 @@ declare function allSettled<C extends {
|
|
|
92
123
|
declare function allSettled<C extends {
|
|
93
124
|
signal?: AbortSignal;
|
|
94
125
|
}, const T extends readonly Starter<unknown, ChildOf<C>>[]>(ctx: C, effects: T): Promise<{ -readonly [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
|
|
126
|
+
declare function allSettled<Child, T extends Record<string, Starter<unknown, Child>>>(effects: T): (child: Child) => Promise<{ [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
|
|
127
|
+
declare function allSettled<Child, const T extends readonly Starter<unknown, Child>[]>(effects: T): (child: Child) => Promise<{ -readonly [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
|
|
95
128
|
//#endregion
|
|
96
129
|
//#region src/effects/race.d.ts
|
|
97
130
|
type RaceStarter<T, Child = EffectContext> = Starter<T, Child>;
|
|
@@ -118,6 +151,8 @@ declare function race<C extends {
|
|
|
118
151
|
declare function race<C extends {
|
|
119
152
|
signal?: AbortSignal;
|
|
120
153
|
}, const T extends readonly RaceStarter<unknown, ChildOf<C>>[]>(ctx: C, effects: T): Promise<{ -readonly [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
|
|
154
|
+
declare function race<Child, T extends Record<string, RaceStarter<unknown, Child>>>(effects: T): (child: Child) => Promise<{ [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
|
|
155
|
+
declare function race<Child, const T extends readonly RaceStarter<unknown, Child>[]>(effects: T): (child: Child) => Promise<{ -readonly [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
|
|
121
156
|
//#endregion
|
|
122
157
|
//#region src/effects/take.d.ts
|
|
123
158
|
type TakeOptions<P> = {
|
|
@@ -169,6 +204,18 @@ declare function take<E extends EventMap, P, T extends P>(ctx: Context<E>, creat
|
|
|
169
204
|
predicate: (payload: P) => payload is T;
|
|
170
205
|
}): Promise<T>;
|
|
171
206
|
declare function take<E extends EventMap, P>(ctx: Context<E>, creator: ActionCreator<P>, options?: TakeOptions<P>): Promise<P>;
|
|
207
|
+
declare function take<E extends EventMap, K extends Keys<E>, T extends E[K]>(event: K, options: TakeOptions<E[K]> & {
|
|
208
|
+
predicate: (payload: E[K]) => payload is T;
|
|
209
|
+
}): (child: Context<E>) => Promise<T>;
|
|
210
|
+
declare function take<E extends EventMap, K extends Keys<E>>(event: K, options?: TakeOptions<E[K]>): (child: Context<E>) => Promise<E[K]>;
|
|
211
|
+
declare function take<E extends EventMap, K extends Keys<E>, T extends E[K]>(creator: FreeActionCreator<K>, options: TakeOptions<E[K]> & {
|
|
212
|
+
predicate: (payload: E[K]) => payload is T;
|
|
213
|
+
}): (child: Context<E>) => Promise<T>;
|
|
214
|
+
declare function take<E extends EventMap, K extends Keys<E>>(creator: FreeActionCreator<K>, options?: TakeOptions<E[K]>): (child: Context<E>) => Promise<E[K]>;
|
|
215
|
+
declare function take<E extends EventMap, P, T extends P>(creator: ActionCreator<P>, options: TakeOptions<P> & {
|
|
216
|
+
predicate: (payload: P) => payload is T;
|
|
217
|
+
}): (child: Context<E>) => Promise<T>;
|
|
218
|
+
declare function take<E extends EventMap, P>(creator: ActionCreator<P>, options?: TakeOptions<P>): (child: Context<E>) => Promise<P>;
|
|
172
219
|
//#endregion
|
|
173
220
|
//#region src/effects/plugin.d.ts
|
|
174
221
|
/** The effects that `effectsPlugin` can put on `ctx`. */
|
|
@@ -233,4 +280,4 @@ type StarterOf<H extends Helpers, E extends EventMap> = Context<E> & BoundOf<H,
|
|
|
233
280
|
*/
|
|
234
281
|
declare const effectsPlugin: <H extends Helpers>(helpers: H) => <E extends EventMap>(bus: Bus<E> & NoClash<BoundOf<H, E>, E>) => Bus<E & WithContext<BoundOf<H, E>>>;
|
|
235
282
|
//#endregion
|
|
236
|
-
export { RaceStarter as a, all as c, Starter as d,
|
|
283
|
+
export { RaceStarter as a, all as c, Starter as d, StarterOf$1 as f, take as i, ChildOf as l, effectsPlugin as n, race as o, delay as p, TakeOptions as r, allSettled as s, BoundOf as t, EffectContext as u };
|
package/dist/notrace/policies.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{n as e,r as t,t as n}from"./delay-Besb3X1O.js";import{a as r,c as i,i as a,n as o,o as s,t as c}from"./context-_HWcdjZf.js";import{n as l,t as u}from"./promise-CSLpzwSR.js";import{n as d,t as f}from"./lifecycle-key-8iX8RUVD.js";const p=e=>Reflect.get(e,f),m=e=>{p(e)?.start()},h=(e,t,n)=>(m(e),r(e,t,n)),g=(e,t)=>{s(e,t,`drop`),p(e)?.drop()},_=(e,t)=>{p(e)?.done(t)},v=(e,t,n)=>{let r=p(e);t?r?.cancel(n):r?.drop()},y=e=>(Reflect.set(e,d,!0),e),b=()=>{},x=(e,t,n)=>typeof e==`function`?n(e,t??{}):t=>n(t,e??{}),S=(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)}},C=(e,t)=>y(e?S(e,t):t(b));function w(e,t){return x(e,t,T)}const T=(e,t)=>C(t.key,t=>E(`latest`,(t,n,r)=>(r(),e(t,n)),t)),E=(e,t,n=b)=>{let r=null;return(o,u)=>{if(r?.abort(),u.signal.aborted)return;let{ctx:d,unlink:f}=a(u);r=d;let p=c(d,e),h=!1,g=()=>{d.signal.aborted||(h=!0,m(d),s(d,e,`start`))};i(d,e=>{v(d,h,e),p(h?`cancel`:`drop`)});let _=()=>{f(),r===d&&(r=null,n())},y=e=>{if(!d.signal.aborted)return p(h?`done`:`drop`),e};try{let e=t(o,d,g);return l(e)?Promise.resolve(e).then(y,e=>{if(!d.signal.aborted)throw p(`error`,e),e}).finally(_):(_(),y(e))}catch(e){if(_(),d.signal.aborted)return;throw p(`error`,e),e}}};function D(e,t,n){return x(t,n,(t,n)=>O(e,t,n))}const O=(e,t,n)=>C(n.key,r=>A(e,t,n,r)),k=(n,r,i,a)=>{let o=a!==b,s=null,c=null;return(l,u)=>{if(u.signal.aborted)return;let d=Date.now(),f=s===null||d-s>=n||d-s<0;return s=d,c!==null&&e(c),c=o?t(a,n):null,i&&f?Promise.resolve(h(u,`debounce`,()=>r(l,u))):(g(u,`debounce`),Promise.resolve(void 0))}},A=(e,t,r,a)=>{let o=r.leading??!1,s=r.trailing??!0;if(!s)return k(e,t,o,a);let c=!1,l=0,u=E(`debounce`,([r,a],o,u)=>{let d=l;return i(o,()=>{l===d&&(c=!1)}),n(o,e).then(()=>{if(c=!1,s&&!a)return u(),t(r,o)})},a);return(e,n)=>{if(n.signal.aborted)return;let r=o&&!c;c=!0,l++;let i=u([e,r],n);return r?Promise.resolve(h(n,`debounce`,()=>t(e,n))):i}};function j(e,t){return x(e,t,M)}const M=(e,t)=>C(t.key,t=>{let n=null;return(r,a)=>{if(a.signal.aborted)return;if(n){g(a,`leading`);return}let o={};n=o;let s=()=>{c(),n===o&&(n=null,t())},c=i(a,s);try{return u(h(a,`leading`,()=>e(r,a)),s)}catch(e){throw s(),e}}});function N(e,t){return x(e,t,P)}const P=(e,t)=>C(t.key,n=>F(e,t,n)),F=(e,t,n)=>{let r=t.concurrency??1,a=t.limit??1/0,o=[],s=0,c=()=>{for(;s<r;){let e=o.shift();if(!e)return;e.start()}};return(l,u)=>new Promise((d,f)=>{if(u.signal.aborted){d(void 0);return}let p=b,m=()=>{p(),g(u,`queue`),d(void 0)},v=()=>{if(p(),u.signal.aborted){m();return}s++;let t=!0,r=()=>{c(),s===0&&o.length===0&&n()},a=(e=!1)=>{t&&(t=!1,s--,e?queueMicrotask(r):r())},g=i(u,()=>{a(!0),d(void 0)}),v;try{v=Promise.resolve(h(u,`queue`,()=>e(l,u)))}catch(e){v=Promise.reject(e)}let y=()=>{g(),a()};v.then(e=>{_(u,{value:e}),y(),d(u.signal.aborted?void 0:e)},e=>{_(u,{error:e}),y(),u.signal.aborted?d(void 0):f(e)})};if(s<r){v();return}if(o.length>=a){if(t.overflow!==`drop-old`||a<=0){m();return}o.shift()?.drop()}let y={start:v,drop:m};o.push(y),p=i(u,()=>{let e=o.indexOf(y);e>=0&&o.splice(e,1),m()})})};function I(e,t,n){return x(t,n,(t,n)=>L(e,t,n))}const L=(e,t,n)=>C(n.key,r=>R(e,t,n,r)),R=(n,r,i,a)=>{let o=i.leading??!0,s=i.trailing??!0,c=a!==b,l=null,u=0,d=null,f=null,p=null,m=!1,_=e=>l===null||e-l>=n||e-l<0||e-u>=n,v=e=>g(e,`throttle`),y=()=>{let e=p;p=null,e&&(v(e.ctx),e.resolve())},x=(e,t)=>(y(),new Promise((n,r)=>{p={payload:e,ctx:t,resolve:n,reject:r}})),S=(e,t,n)=>{y(),u=n,m=!0;try{return h(t,`throttle`,()=>r(e,t))}finally{m=!1}},C=()=>{c&&(f=t(w,n))},w=()=>{if(f=null,!c||d!==null||p)return;let e=Date.now(),r=Math.max(n-(e-(l??-1/0)),n-(e-u));r<=0?a():f=t(w,r)},T=e=>{d=null;let t=p;if(s&&t&&!t.ctx.signal.aborted){p=null;try{t.resolve(S(t.payload,t.ctx,e))}catch(e){t.reject(e)}}else y();w()},E=()=>{let e=Date.now();_(e)?T(e):d=t(E,Math.min(n-(e-(l??e)),n-(e-u)))},D=()=>{f!==null&&(e(f),f=null)},O=(e,t)=>{if(!s)v(t);else return x(e,t)},k=(e,t,n,r)=>{if(!r)v(t);else if(u=n,C(),!o)v(t);else return S(e,t,n)},A=(r,i,a,s)=>s&&d!==null?(e(d),d=t(E,n),S(r,i,a)):d===null&&(d=t(E,n),s&&(u=a,o))?S(r,i,a):O(r,i);return(e,t)=>{if(t.signal.aborted)return;let n=Date.now(),r=!m&&_(n);return l=n,D(),s?A(e,t,n,r):k(e,t,n,r)}},z=Reflect.get(Symbol,`dispose`),B=e=>{let t=new AbortController,n=async(...n)=>{let r=n[0],{ctx:i,unlink:a}=o({event:{type:`withPolicy`,payload:r},parent:{signal:t.signal}});try{return await e(r,i)}finally{a()}},r=e=>{t.abort(e),t=new AbortController},i=Object.assign(n,{cancel:r});return z&&Reflect.set(i,z,()=>r()),i};export{D as debounce,w as latest,j as leading,N as queue,I as throttle,B as withPolicy};
|
|
@@ -1,11 +1,17 @@
|
|
|
1
1
|
import { B as Keys, N as WithContext, b as Context, d as Effects, h as Bus, l as BoundForm, r as FreeActionCreator, t as ActionCreator, z as EventMap } from "./action-creator-Bpa8BUS9.js";
|
|
2
2
|
import { n as NoClash } from "./context-types-BKIH5a8s.js";
|
|
3
3
|
//#region src/utils/delay.d.ts
|
|
4
|
+
type Milliseconds = number | (() => number);
|
|
4
5
|
/**
|
|
5
6
|
* Resolves after `ms`, or rejects early if `ctx.signal` aborts. `ms` can be a
|
|
6
7
|
* function that returns the number of ms, called once when the delay starts:
|
|
7
8
|
* handy for a random pause (jitter).
|
|
8
9
|
*
|
|
10
|
+
* Without `ctx`, `delay(ms)` returns a starter for `race`, `all` and
|
|
11
|
+
* `allSettled`: they call it with the context of its own child task, and it
|
|
12
|
+
* waits then. It starts no timer before that, and one starter can be used in
|
|
13
|
+
* several groups. Do not `await` it on its own: it is a function, not a promise.
|
|
14
|
+
*
|
|
9
15
|
* @example
|
|
10
16
|
* ```ts
|
|
11
17
|
* await delay({}, 500);
|
|
@@ -18,11 +24,20 @@ import { n as NoClash } from "./context-types-BKIH5a8s.js";
|
|
|
18
24
|
* await delay(ctx, 1000);
|
|
19
25
|
* await load();
|
|
20
26
|
* });
|
|
27
|
+
*
|
|
28
|
+
* // as a starter: the loser of the race is cancelled
|
|
29
|
+
* const result = await race(ctx, {
|
|
30
|
+
* waited: delay(1000),
|
|
31
|
+
* cancelled: take(cancel),
|
|
32
|
+
* });
|
|
21
33
|
* ```
|
|
22
34
|
*/
|
|
23
|
-
declare
|
|
35
|
+
declare function delay(ms: Milliseconds): (child: {
|
|
36
|
+
signal?: AbortSignal | undefined;
|
|
37
|
+
}) => Promise<void>;
|
|
38
|
+
declare function delay(ctx: {
|
|
24
39
|
signal?: AbortSignal | undefined;
|
|
25
|
-
}, ms:
|
|
40
|
+
}, ms: Milliseconds): Promise<void>;
|
|
26
41
|
//#endregion
|
|
27
42
|
//#region src/effects/run.d.ts
|
|
28
43
|
/** What a starter gets when the effect was called with `{}` or a bare `{ signal }`. */
|
|
@@ -37,6 +52,20 @@ type EffectContext = {
|
|
|
37
52
|
*/
|
|
38
53
|
type ChildOf<C> = C extends Context<infer E> ? Context<E> : EffectContext;
|
|
39
54
|
type Starter<T, Child = EffectContext> = (child: Child) => T | PromiseLike<T>;
|
|
55
|
+
/**
|
|
56
|
+
* A starter of a group on a bus with the events `E`, with the result `R`. A starter written in a
|
|
57
|
+
* group needs no type: the group gives it. Use this for one kept in a variable, where nothing
|
|
58
|
+
* tells the checker which bus it is for.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```ts
|
|
62
|
+
* const load: StarterOf<Events> = all({ user: retry(() => loadUser(1)) });
|
|
63
|
+
* const user: StarterOf<Events, User> = retry(() => loadUser(1));
|
|
64
|
+
*
|
|
65
|
+
* bus.on("open", async (_, ctx) => race(ctx, { load, user }));
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
type StarterOf$1<E extends EventMap, R = unknown> = Starter<R, Context<E>>;
|
|
40
69
|
//#endregion
|
|
41
70
|
//#region src/effects/all.d.ts
|
|
42
71
|
/**
|
|
@@ -60,6 +89,8 @@ declare function all<C extends {
|
|
|
60
89
|
declare function all<C extends {
|
|
61
90
|
signal?: AbortSignal;
|
|
62
91
|
}, const T extends readonly Starter<unknown, ChildOf<C>>[]>(ctx: C, effects: T): Promise<{ -readonly [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
|
|
92
|
+
declare function all<Child, T extends Record<string, Starter<unknown, Child>>>(effects: T): (child: Child) => Promise<{ [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
|
|
93
|
+
declare function all<Child, const T extends readonly Starter<unknown, Child>[]>(effects: T): (child: Child) => Promise<{ -readonly [K in keyof T]: Awaited<ReturnType<T[K]>>; }>;
|
|
63
94
|
//#endregion
|
|
64
95
|
//#region src/effects/allSettled.d.ts
|
|
65
96
|
/**
|
|
@@ -86,6 +117,8 @@ declare function allSettled<C extends {
|
|
|
86
117
|
declare function allSettled<C extends {
|
|
87
118
|
signal?: AbortSignal;
|
|
88
119
|
}, const T extends readonly Starter<unknown, ChildOf<C>>[]>(ctx: C, effects: T): Promise<{ -readonly [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
|
|
120
|
+
declare function allSettled<Child, T extends Record<string, Starter<unknown, Child>>>(effects: T): (child: Child) => Promise<{ [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
|
|
121
|
+
declare function allSettled<Child, const T extends readonly Starter<unknown, Child>[]>(effects: T): (child: Child) => Promise<{ -readonly [K in keyof T]: PromiseSettledResult<Awaited<ReturnType<T[K]>>>; }>;
|
|
89
122
|
//#endregion
|
|
90
123
|
//#region src/effects/race.d.ts
|
|
91
124
|
type RaceStarter<T, Child = EffectContext> = Starter<T, Child>;
|
|
@@ -112,6 +145,8 @@ declare function race<C extends {
|
|
|
112
145
|
declare function race<C extends {
|
|
113
146
|
signal?: AbortSignal;
|
|
114
147
|
}, const T extends readonly RaceStarter<unknown, ChildOf<C>>[]>(ctx: C, effects: T): Promise<{ -readonly [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
|
|
148
|
+
declare function race<Child, T extends Record<string, RaceStarter<unknown, Child>>>(effects: T): (child: Child) => Promise<{ [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
|
|
149
|
+
declare function race<Child, const T extends readonly RaceStarter<unknown, Child>[]>(effects: T): (child: Child) => Promise<{ -readonly [K in keyof T]?: Awaited<ReturnType<T[K]>>; }>;
|
|
115
150
|
//#endregion
|
|
116
151
|
//#region src/effects/take.d.ts
|
|
117
152
|
type TakeOptions<P> = {
|
|
@@ -163,6 +198,18 @@ declare function take<E extends EventMap, P, T extends P>(ctx: Context<E>, creat
|
|
|
163
198
|
predicate: (payload: P) => payload is T;
|
|
164
199
|
}): Promise<T>;
|
|
165
200
|
declare function take<E extends EventMap, P>(ctx: Context<E>, creator: ActionCreator<P>, options?: TakeOptions<P>): Promise<P>;
|
|
201
|
+
declare function take<E extends EventMap, K extends Keys<E>, T extends E[K]>(event: K, options: TakeOptions<E[K]> & {
|
|
202
|
+
predicate: (payload: E[K]) => payload is T;
|
|
203
|
+
}): (child: Context<E>) => Promise<T>;
|
|
204
|
+
declare function take<E extends EventMap, K extends Keys<E>>(event: K, options?: TakeOptions<E[K]>): (child: Context<E>) => Promise<E[K]>;
|
|
205
|
+
declare function take<E extends EventMap, K extends Keys<E>, T extends E[K]>(creator: FreeActionCreator<K>, options: TakeOptions<E[K]> & {
|
|
206
|
+
predicate: (payload: E[K]) => payload is T;
|
|
207
|
+
}): (child: Context<E>) => Promise<T>;
|
|
208
|
+
declare function take<E extends EventMap, K extends Keys<E>>(creator: FreeActionCreator<K>, options?: TakeOptions<E[K]>): (child: Context<E>) => Promise<E[K]>;
|
|
209
|
+
declare function take<E extends EventMap, P, T extends P>(creator: ActionCreator<P>, options: TakeOptions<P> & {
|
|
210
|
+
predicate: (payload: P) => payload is T;
|
|
211
|
+
}): (child: Context<E>) => Promise<T>;
|
|
212
|
+
declare function take<E extends EventMap, P>(creator: ActionCreator<P>, options?: TakeOptions<P>): (child: Context<E>) => Promise<P>;
|
|
166
213
|
//#endregion
|
|
167
214
|
//#region src/effects/plugin.d.ts
|
|
168
215
|
/** The effects that `effectsPlugin` can put on `ctx`. */
|
|
@@ -227,4 +274,4 @@ type StarterOf<H extends Helpers, E extends EventMap> = Context<E> & BoundOf<H,
|
|
|
227
274
|
*/
|
|
228
275
|
declare const effectsPlugin: <H extends Helpers>(helpers: H) => <E extends EventMap>(bus: Bus<E> & NoClash<BoundOf<H, E>, E>) => Bus<E & WithContext<BoundOf<H, E>>>;
|
|
229
276
|
//#endregion
|
|
230
|
-
export { RaceStarter as a, all as c, Starter as d,
|
|
277
|
+
export { RaceStarter as a, all as c, Starter as d, StarterOf$1 as f, take as i, ChildOf as l, effectsPlugin as n, race as o, delay as p, TakeOptions as r, allSettled as s, BoundOf as t, EffectContext as u };
|
package/dist/policies.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{
|
|
1
|
+
import{n as e,r as t,t as n}from"./delay-18LJ8jSk.js";import{i as r,o as i,s as a,t as o,u as s}from"./context-UcmrAIhP.js";import{n as c,t as l}from"./promise-CSLpzwSR.js";import{n as u,t as d}from"./lifecycle-key-8iX8RUVD.js";import{t as f}from"./with-policy-D-SQRkPh.js";const p=e=>Reflect.get(e,d),m=e=>{p(e)?.start()},h=(e,t,n)=>(m(e),i(e,t,n)),g=(e,t)=>{a(e,t,`drop`),p(e)?.drop()},_=(e,t)=>{p(e)?.done(t)},v=(e,t,n)=>{let r=p(e);t?r?.cancel(n):r?.drop()},y=e=>(Reflect.set(e,u,!0),e),b=()=>{},x=(e,t,n)=>typeof e==`function`?n(e,t??{}):t=>n(t,e??{}),S=(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)}},C=(e,t)=>y(e?S(e,t):t(b));function w(e,t){return x(e,t,T)}const T=(e,t)=>C(t.key,t=>E(`latest`,(t,n,r)=>(r(),e(t,n)),t)),E=(e,t,n=b)=>{let i=null;return(l,u)=>{if(i?.abort(),u.signal.aborted)return;let{ctx:d,unlink:f}=r(u);i=d;let p=o(d,e),h=!1,g=()=>{d.signal.aborted||(h=!0,m(d),a(d,e,`start`))};s(d,e=>{v(d,h,e),p(h?`cancel`:`drop`)});let _=()=>{f(),i===d&&(i=null,n())},y=e=>{if(!d.signal.aborted)return p(h?`done`:`drop`),e};try{let e=t(l,d,g);return c(e)?Promise.resolve(e).then(y,e=>{if(!d.signal.aborted)throw p(`error`,e),e}).finally(_):(_(),y(e))}catch(e){if(_(),d.signal.aborted)return;throw p(`error`,e),e}}};function D(e,t,n){return x(t,n,(t,n)=>O(e,t,n))}const O=(e,t,n)=>C(n.key,r=>A(e,t,n,r)),k=(n,r,i,a)=>{let o=a!==b,s=null,c=null;return(l,u)=>{if(u.signal.aborted)return;let d=Date.now(),f=s===null||d-s>=n||d-s<0;return s=d,c!==null&&e(c),c=o?t(a,n):null,i&&f?Promise.resolve(h(u,`debounce`,()=>r(l,u))):(g(u,`debounce`),Promise.resolve(void 0))}},A=(e,t,r,i)=>{let a=r.leading??!1,o=r.trailing??!0;if(!o)return k(e,t,a,i);let c=!1,l=0,u=E(`debounce`,([r,i],a,u)=>{let d=l;return s(a,()=>{l===d&&(c=!1)}),n(a,e).then(()=>{if(c=!1,o&&!i)return u(),t(r,a)})},i);return(e,n)=>{if(n.signal.aborted)return;let r=a&&!c;c=!0,l++;let i=u([e,r],n);return r?Promise.resolve(h(n,`debounce`,()=>t(e,n))):i}};function j(e,t){return x(e,t,M)}const M=(e,t)=>C(t.key,t=>{let n=null;return(r,i)=>{if(i.signal.aborted)return;if(n){g(i,`leading`);return}let a={};n=a;let o=()=>{c(),n===a&&(n=null,t())},c=s(i,o);try{return l(h(i,`leading`,()=>e(r,i)),o)}catch(e){throw o(),e}}});function N(e,t){return x(e,t,P)}const P=(e,t)=>C(t.key,n=>F(e,t,n)),F=(e,t,n)=>{let r=t.concurrency??1,i=t.limit??1/0,a=[],o=0,c=()=>{for(;o<r;){let e=a.shift();if(!e)return;e.start()}};return(l,u)=>new Promise((d,f)=>{if(u.signal.aborted){d(void 0);return}let p=b,m=()=>{p(),g(u,`queue`),d(void 0)},v=()=>{if(p(),u.signal.aborted){m();return}o++;let t=!0,r=()=>{c(),o===0&&a.length===0&&n()},i=(e=!1)=>{t&&(t=!1,o--,e?queueMicrotask(r):r())},g=s(u,()=>{i(!0),d(void 0)}),v;try{v=Promise.resolve(h(u,`queue`,()=>e(l,u)))}catch(e){v=Promise.reject(e)}let y=()=>{g(),i()};v.then(e=>{_(u,{value:e}),y(),d(u.signal.aborted?void 0:e)},e=>{_(u,{error:e}),y(),u.signal.aborted?d(void 0):f(e)})};if(o<r){v();return}if(a.length>=i){if(t.overflow!==`drop-old`||i<=0){m();return}a.shift()?.drop()}let y={start:v,drop:m};a.push(y),p=s(u,()=>{let e=a.indexOf(y);e>=0&&a.splice(e,1),m()})})};function I(e,t,n){return x(t,n,(t,n)=>L(e,t,n))}const L=(e,t,n)=>C(n.key,r=>R(e,t,n,r)),R=(n,r,i,a)=>{let o=i.leading??!0,s=i.trailing??!0,c=a!==b,l=null,u=0,d=null,f=null,p=null,m=!1,_=e=>l===null||e-l>=n||e-l<0||e-u>=n,v=e=>g(e,`throttle`),y=()=>{let e=p;p=null,e&&(v(e.ctx),e.resolve())},x=(e,t)=>(y(),new Promise((n,r)=>{p={payload:e,ctx:t,resolve:n,reject:r}})),S=(e,t,n)=>{y(),u=n,m=!0;try{return h(t,`throttle`,()=>r(e,t))}finally{m=!1}},C=()=>{c&&(f=t(w,n))},w=()=>{if(f=null,!c||d!==null||p)return;let e=Date.now(),r=Math.max(n-(e-(l??-1/0)),n-(e-u));r<=0?a():f=t(w,r)},T=e=>{d=null;let t=p;if(s&&t&&!t.ctx.signal.aborted){p=null;try{t.resolve(S(t.payload,t.ctx,e))}catch(e){t.reject(e)}}else y();w()},E=()=>{let e=Date.now();_(e)?T(e):d=t(E,Math.min(n-(e-(l??e)),n-(e-u)))},D=()=>{f!==null&&(e(f),f=null)},O=(e,t)=>{if(!s)v(t);else return x(e,t)},k=(e,t,n,r)=>{if(!r)v(t);else if(u=n,C(),!o)v(t);else return S(e,t,n)},A=(r,i,a,s)=>s&&d!==null?(e(d),d=t(E,n),S(r,i,a)):d===null&&(d=t(E,n),s&&(u=a,o))?S(r,i,a):O(r,i);return(e,t)=>{if(t.signal.aborted)return;let n=Date.now(),r=!m&&_(n);return l=n,D(),s?A(e,t,n,r):k(e,t,n,r)}};export{D as debounce,w as latest,j as leading,N as queue,I as throttle,f as withPolicy};
|
package/dist/scope.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { P as WithSignal, a as EmitScope, d as Effects, f as Signaled, h as Bus, o as Scope, u as Effect, z as EventMap } from "./action-creator-Bpa8BUS9.js";
|
|
2
|
-
import { n as ScopeSlots, r as Scoped } from "./types-
|
|
2
|
+
import { n as ScopeSlots, r as Scoped } from "./types-B0DMvfsU.js";
|
|
3
3
|
//#region src/scope/effect.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* Marks a function whose first parameter is `{ signal }` as an effect, so that
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { d as Effects, o as Scope, s as WithFields, z as EventMap } from "./action-creator-Bpa8BUS9.js";
|
|
2
|
-
import { t as BoundOf } from "./plugin-
|
|
2
|
+
import { t as BoundOf } from "./plugin-CGIdsEGF.js";
|
|
3
3
|
//#region src/scope/types.d.ts
|
|
4
4
|
/**
|
|
5
5
|
* The slots `scopePlugin` fills for `modulePlugin`. They are not on `Bus`: a bus
|
package/docs/effects.md
CHANGED
|
@@ -264,8 +264,10 @@ bus.on("login", async (user, ctx) => {
|
|
|
264
264
|
console.log(stopped);
|
|
265
265
|
|
|
266
266
|
// wait for a matching event, but not longer than 5 s
|
|
267
|
-
const id = await timeout(
|
|
268
|
-
|
|
267
|
+
const id = await timeout(
|
|
268
|
+
ctx,
|
|
269
|
+
5000,
|
|
270
|
+
take("saved", { predicate: (savedId) => savedId === draft.id }), // take without ctx: a starter
|
|
269
271
|
);
|
|
270
272
|
});
|
|
271
273
|
```
|
|
@@ -273,7 +275,7 @@ bus.on("login", async (user, ctx) => {
|
|
|
273
275
|
- Sees only events emitted after the call, takes one, and unsubscribes.
|
|
274
276
|
- With an action creator the result has the payload type of the creator. A creator made without a payload type (`createAction("saved")`) takes it from the event map of the bus.
|
|
275
277
|
- `options.predicate` skips payloads it rejects. In TypeScript, a type guard (`(payload): payload is Admin`) narrows the type of the result.
|
|
276
|
-
- `options.signal` stops the wait.
|
|
278
|
+
- `options.signal` stops the wait. Inside `race`, `all` or `timeout` you do not need it: the group already stops the starter, so write `take("saved")` without options.
|
|
277
279
|
- On abort of the task or of `options.signal`, unsubscribes and rejects with the abort reason.
|
|
278
280
|
|
|
279
281
|
## Run several starters together
|
|
@@ -311,8 +313,8 @@ const bus = createBus();
|
|
|
311
313
|
bus.on("save", async (draft, ctx) => {
|
|
312
314
|
// race — the first starter to finish wins, the other is cancelled
|
|
313
315
|
const result = await race(ctx, {
|
|
314
|
-
waited: (
|
|
315
|
-
cancelled: (
|
|
316
|
+
waited: delay(1000), // delay without ctx — a starter: race gives it its own child
|
|
317
|
+
cancelled: take("cancel"), // take without ctx — the same, waits for the next "cancel"
|
|
316
318
|
});
|
|
317
319
|
|
|
318
320
|
if ("waited" in result) {
|
|
@@ -321,12 +323,65 @@ bus.on("save", async (draft, ctx) => {
|
|
|
321
323
|
});
|
|
322
324
|
```
|
|
323
325
|
|
|
326
|
+
**`delay` and `take` without `ctx` are ready-made starters.** In a group, `delay(1000)` and `take("cancel")` do what `(child) => delay(child, 1000)` and `(child) => take(child, "cancel")` do. The group calls them with the child, so the wait stops with the group. Use this form inside `race`, `all`, `allSettled` and `timeout`; use `delay(ctx, 1000)` in plain handler code. A starter waits only when a group calls it: do not `await delay(1000)` on its own, it is a function, not a promise. Write `take("cancel")` in the group, as above; a starter stored in a variable outside it does not know the events of your bus, and you name them yourself in TypeScript (`const cancelled: StarterOf<Events> = take("cancel")`; `StarterOf` is exported by `nanoeffects/effects`).
|
|
327
|
+
|
|
328
|
+
The wrapper form of `retry`, `timeout` and `poll` is a starter too: a group calls it with the child, and the function you wrap gets `undefined` as its payload and the child as its context. Write the data it needs into a closure:
|
|
329
|
+
|
|
330
|
+
```js
|
|
331
|
+
import { createBus } from "nanoeffects";
|
|
332
|
+
import { delay, race, retry } from "nanoeffects/effects";
|
|
333
|
+
|
|
334
|
+
const bus = createBus();
|
|
335
|
+
|
|
336
|
+
bus.on("open", async (id, ctx) => {
|
|
337
|
+
const result = await race(ctx, {
|
|
338
|
+
// retry without ctx — a starter: up to 3 attempts, each with the signal of the child
|
|
339
|
+
user: retry((_, { signal }) => fetchUser(id, { signal }), { times: 3 }),
|
|
340
|
+
// delay without ctx — the loser is cancelled when the other one finishes
|
|
341
|
+
waited: delay(5000),
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
if ("user" in result) {
|
|
345
|
+
render(result.user);
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
The same call with a payload and a context, `(payload, ctx)`, is the Task that `bus.on` and `ctx.run` use, and it does not change.
|
|
351
|
+
|
|
352
|
+
**`all`, `allSettled` and `race` without `ctx` are starters too**, so a group nests in another group with no wrapper. Load two things, but give up after five seconds:
|
|
353
|
+
|
|
354
|
+
```js
|
|
355
|
+
import { createBus } from "nanoeffects";
|
|
356
|
+
import { all, delay, race, retry } from "nanoeffects/effects";
|
|
357
|
+
|
|
358
|
+
const bus = createBus();
|
|
359
|
+
|
|
360
|
+
bus.on("open", async (id, ctx) => {
|
|
361
|
+
const result = await race(ctx, {
|
|
362
|
+
// all without ctx — a starter: loads both, each with up to 3 attempts
|
|
363
|
+
loaded: all({
|
|
364
|
+
user: retry((_, { signal }) => fetchUser(id, { signal }), { times: 3 }),
|
|
365
|
+
posts: retry((_, { signal }) => fetchPosts(id, { signal }), { times: 3 }),
|
|
366
|
+
}),
|
|
367
|
+
// delay without ctx — when it wins, the whole `all` above is cancelled
|
|
368
|
+
waited: delay(5000),
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
if ("loaded" in result) {
|
|
372
|
+
render(result.loaded.user, result.loaded.posts);
|
|
373
|
+
}
|
|
374
|
+
});
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
One argument is the short form and two arguments are the form with `ctx`: `all(effects)` returns a starter, `all(ctx, effects)` runs the group. The inner group stops with the outer one and cancels its own starters. Passing only a context, `all(ctx)`, is a mistake and throws a `TypeError` at once. A group starter written in a group needs no type. One kept in a variable outside a group does not know its bus: in TypeScript, annotate it with `StarterOf<Events>`, or `StarterOf<Events, Result>` when you need its value.
|
|
378
|
+
|
|
324
379
|
**A starter gets the context of its own child task.** Pass `child` as the first argument to any effect, as a handler passes `ctx`: when the race ends, `child` is aborted and stops exactly this effect. The outer `ctx` is only for `race` itself. Your own API takes the signal in its options: `({ signal }) => fetchUser(id, { signal })`. The same holds for `all`, `allSettled` and `timeout`.
|
|
325
380
|
|
|
326
381
|
If `ctx` is `{}` or a bare `{ signal }` (outside a task), `child` has only `signal` and `abort`, so it fits `delay` and `poll` but not `take`, which needs a bus.
|
|
327
382
|
|
|
328
383
|
## Pass `ctx` outside a task
|
|
329
384
|
|
|
330
|
-
Effects that wait inside a body take `ctx` first: `delay`, `all`, `allSettled`, `race`, `cancellable`, `onAbort`, `take`, and the `ctx` forms of `retry` / `timeout` / `poll`. Outside a task, pass `{}` or any object with a `signal`.
|
|
385
|
+
Effects that wait inside a body take `ctx` first: `delay`, `all`, `allSettled`, `race`, `cancellable`, `onAbort`, `take`, and the `ctx` forms of `retry` / `timeout` / `poll`. Outside a task, pass `{}` or any object with a `signal`. The one exception is `delay(ms)` and `take(event)` as starters of a group, which take no `ctx` (see above).
|
|
331
386
|
|
|
332
387
|
For `fetch` and other APIs that take a signal, pass `ctx.signal`. A timeout without `race`: `AbortSignal.any([ctx.signal, AbortSignal.timeout(5000)])`.
|
package/docs/guide.md
CHANGED
|
@@ -267,7 +267,7 @@ For one call in the middle of a body: `await retry(ctx, () => api.search(q, { si
|
|
|
267
267
|
|
|
268
268
|
```js
|
|
269
269
|
import { createBus } from "nanoeffects";
|
|
270
|
-
import { all, take } from "nanoeffects/effects";
|
|
270
|
+
import { all, delay, race, take } from "nanoeffects/effects";
|
|
271
271
|
|
|
272
272
|
const bus = createBus();
|
|
273
273
|
|
|
@@ -285,6 +285,18 @@ bus.on("typed", async (query, ctx) => {
|
|
|
285
285
|
const position = await take(ctx, "scroll");
|
|
286
286
|
ctx.emit("scrolled", { query, position });
|
|
287
287
|
});
|
|
288
|
+
|
|
289
|
+
// race — the first to finish wins, the other is cancelled
|
|
290
|
+
bus.on("save", async (draft, ctx) => {
|
|
291
|
+
const result = await race(ctx, {
|
|
292
|
+
cancelled: take("cancel"), // take without ctx — waits for the next "cancel"
|
|
293
|
+
waited: delay(1000), // delay without ctx — waits one second
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
if ("waited" in result) {
|
|
297
|
+
ctx.emit("saved", draft);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
288
300
|
```
|
|
289
301
|
|
|
290
302
|
More in [Effects](effects.md).
|
|
@@ -121,10 +121,10 @@ bus.on("watch", async (_, ctx) => {
|
|
|
121
121
|
};
|
|
122
122
|
|
|
123
123
|
await race(ctx, {
|
|
124
|
-
// poll: a check every 5 s; waitForFn: the next pause starts after the check ends
|
|
125
|
-
polling:
|
|
126
|
-
// take: resolves at the next "leave", and race stops the polling
|
|
127
|
-
leave:
|
|
124
|
+
// poll without ctx: a check every 5 s; waitForFn: the next pause starts after the check ends
|
|
125
|
+
polling: poll(5000, checkStatus, { waitForFn: true }),
|
|
126
|
+
// take without ctx: resolves at the next "leave", and race stops the polling
|
|
127
|
+
leave: take("leave"),
|
|
128
128
|
});
|
|
129
129
|
});
|
|
130
130
|
|
package/llms-full.txt
CHANGED
|
@@ -284,7 +284,7 @@ For one call in the middle of a body: `await retry(ctx, () => api.search(q, { si
|
|
|
284
284
|
|
|
285
285
|
```js
|
|
286
286
|
import { createBus } from "nanoeffects";
|
|
287
|
-
import { all, take } from "nanoeffects/effects";
|
|
287
|
+
import { all, delay, race, take } from "nanoeffects/effects";
|
|
288
288
|
|
|
289
289
|
const bus = createBus();
|
|
290
290
|
|
|
@@ -302,6 +302,18 @@ bus.on("typed", async (query, ctx) => {
|
|
|
302
302
|
const position = await take(ctx, "scroll");
|
|
303
303
|
ctx.emit("scrolled", { query, position });
|
|
304
304
|
});
|
|
305
|
+
|
|
306
|
+
// race — the first to finish wins, the other is cancelled
|
|
307
|
+
bus.on("save", async (draft, ctx) => {
|
|
308
|
+
const result = await race(ctx, {
|
|
309
|
+
cancelled: take("cancel"), // take without ctx — waits for the next "cancel"
|
|
310
|
+
waited: delay(1000), // delay without ctx — waits one second
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
if ("waited" in result) {
|
|
314
|
+
ctx.emit("saved", draft);
|
|
315
|
+
}
|
|
316
|
+
});
|
|
305
317
|
```
|
|
306
318
|
|
|
307
319
|
More in [Effects](effects.md).
|
|
@@ -1848,8 +1860,10 @@ bus.on("login", async (user, ctx) => {
|
|
|
1848
1860
|
console.log(stopped);
|
|
1849
1861
|
|
|
1850
1862
|
// wait for a matching event, but not longer than 5 s
|
|
1851
|
-
const id = await timeout(
|
|
1852
|
-
|
|
1863
|
+
const id = await timeout(
|
|
1864
|
+
ctx,
|
|
1865
|
+
5000,
|
|
1866
|
+
take("saved", { predicate: (savedId) => savedId === draft.id }), // take without ctx: a starter
|
|
1853
1867
|
);
|
|
1854
1868
|
});
|
|
1855
1869
|
```
|
|
@@ -1857,7 +1871,7 @@ bus.on("login", async (user, ctx) => {
|
|
|
1857
1871
|
- Sees only events emitted after the call, takes one, and unsubscribes.
|
|
1858
1872
|
- With an action creator the result has the payload type of the creator. A creator made without a payload type (`createAction("saved")`) takes it from the event map of the bus.
|
|
1859
1873
|
- `options.predicate` skips payloads it rejects. In TypeScript, a type guard (`(payload): payload is Admin`) narrows the type of the result.
|
|
1860
|
-
- `options.signal` stops the wait.
|
|
1874
|
+
- `options.signal` stops the wait. Inside `race`, `all` or `timeout` you do not need it: the group already stops the starter, so write `take("saved")` without options.
|
|
1861
1875
|
- On abort of the task or of `options.signal`, unsubscribes and rejects with the abort reason.
|
|
1862
1876
|
|
|
1863
1877
|
## Run several starters together
|
|
@@ -1895,8 +1909,8 @@ const bus = createBus();
|
|
|
1895
1909
|
bus.on("save", async (draft, ctx) => {
|
|
1896
1910
|
// race — the first starter to finish wins, the other is cancelled
|
|
1897
1911
|
const result = await race(ctx, {
|
|
1898
|
-
waited: (
|
|
1899
|
-
cancelled: (
|
|
1912
|
+
waited: delay(1000), // delay without ctx — a starter: race gives it its own child
|
|
1913
|
+
cancelled: take("cancel"), // take without ctx — the same, waits for the next "cancel"
|
|
1900
1914
|
});
|
|
1901
1915
|
|
|
1902
1916
|
if ("waited" in result) {
|
|
@@ -1905,13 +1919,66 @@ bus.on("save", async (draft, ctx) => {
|
|
|
1905
1919
|
});
|
|
1906
1920
|
```
|
|
1907
1921
|
|
|
1922
|
+
**`delay` and `take` without `ctx` are ready-made starters.** In a group, `delay(1000)` and `take("cancel")` do what `(child) => delay(child, 1000)` and `(child) => take(child, "cancel")` do. The group calls them with the child, so the wait stops with the group. Use this form inside `race`, `all`, `allSettled` and `timeout`; use `delay(ctx, 1000)` in plain handler code. A starter waits only when a group calls it: do not `await delay(1000)` on its own, it is a function, not a promise. Write `take("cancel")` in the group, as above; a starter stored in a variable outside it does not know the events of your bus, and you name them yourself in TypeScript (`const cancelled: StarterOf<Events> = take("cancel")`; `StarterOf` is exported by `nanoeffects/effects`).
|
|
1923
|
+
|
|
1924
|
+
The wrapper form of `retry`, `timeout` and `poll` is a starter too: a group calls it with the child, and the function you wrap gets `undefined` as its payload and the child as its context. Write the data it needs into a closure:
|
|
1925
|
+
|
|
1926
|
+
```js
|
|
1927
|
+
import { createBus } from "nanoeffects";
|
|
1928
|
+
import { delay, race, retry } from "nanoeffects/effects";
|
|
1929
|
+
|
|
1930
|
+
const bus = createBus();
|
|
1931
|
+
|
|
1932
|
+
bus.on("open", async (id, ctx) => {
|
|
1933
|
+
const result = await race(ctx, {
|
|
1934
|
+
// retry without ctx — a starter: up to 3 attempts, each with the signal of the child
|
|
1935
|
+
user: retry((_, { signal }) => fetchUser(id, { signal }), { times: 3 }),
|
|
1936
|
+
// delay without ctx — the loser is cancelled when the other one finishes
|
|
1937
|
+
waited: delay(5000),
|
|
1938
|
+
});
|
|
1939
|
+
|
|
1940
|
+
if ("user" in result) {
|
|
1941
|
+
render(result.user);
|
|
1942
|
+
}
|
|
1943
|
+
});
|
|
1944
|
+
```
|
|
1945
|
+
|
|
1946
|
+
The same call with a payload and a context, `(payload, ctx)`, is the Task that `bus.on` and `ctx.run` use, and it does not change.
|
|
1947
|
+
|
|
1948
|
+
**`all`, `allSettled` and `race` without `ctx` are starters too**, so a group nests in another group with no wrapper. Load two things, but give up after five seconds:
|
|
1949
|
+
|
|
1950
|
+
```js
|
|
1951
|
+
import { createBus } from "nanoeffects";
|
|
1952
|
+
import { all, delay, race, retry } from "nanoeffects/effects";
|
|
1953
|
+
|
|
1954
|
+
const bus = createBus();
|
|
1955
|
+
|
|
1956
|
+
bus.on("open", async (id, ctx) => {
|
|
1957
|
+
const result = await race(ctx, {
|
|
1958
|
+
// all without ctx — a starter: loads both, each with up to 3 attempts
|
|
1959
|
+
loaded: all({
|
|
1960
|
+
user: retry((_, { signal }) => fetchUser(id, { signal }), { times: 3 }),
|
|
1961
|
+
posts: retry((_, { signal }) => fetchPosts(id, { signal }), { times: 3 }),
|
|
1962
|
+
}),
|
|
1963
|
+
// delay without ctx — when it wins, the whole `all` above is cancelled
|
|
1964
|
+
waited: delay(5000),
|
|
1965
|
+
});
|
|
1966
|
+
|
|
1967
|
+
if ("loaded" in result) {
|
|
1968
|
+
render(result.loaded.user, result.loaded.posts);
|
|
1969
|
+
}
|
|
1970
|
+
});
|
|
1971
|
+
```
|
|
1972
|
+
|
|
1973
|
+
One argument is the short form and two arguments are the form with `ctx`: `all(effects)` returns a starter, `all(ctx, effects)` runs the group. The inner group stops with the outer one and cancels its own starters. Passing only a context, `all(ctx)`, is a mistake and throws a `TypeError` at once. A group starter written in a group needs no type. One kept in a variable outside a group does not know its bus: in TypeScript, annotate it with `StarterOf<Events>`, or `StarterOf<Events, Result>` when you need its value.
|
|
1974
|
+
|
|
1908
1975
|
**A starter gets the context of its own child task.** Pass `child` as the first argument to any effect, as a handler passes `ctx`: when the race ends, `child` is aborted and stops exactly this effect. The outer `ctx` is only for `race` itself. Your own API takes the signal in its options: `({ signal }) => fetchUser(id, { signal })`. The same holds for `all`, `allSettled` and `timeout`.
|
|
1909
1976
|
|
|
1910
1977
|
If `ctx` is `{}` or a bare `{ signal }` (outside a task), `child` has only `signal` and `abort`, so it fits `delay` and `poll` but not `take`, which needs a bus.
|
|
1911
1978
|
|
|
1912
1979
|
## Pass `ctx` outside a task
|
|
1913
1980
|
|
|
1914
|
-
Effects that wait inside a body take `ctx` first: `delay`, `all`, `allSettled`, `race`, `cancellable`, `onAbort`, `take`, and the `ctx` forms of `retry` / `timeout` / `poll`. Outside a task, pass `{}` or any object with a `signal`.
|
|
1981
|
+
Effects that wait inside a body take `ctx` first: `delay`, `all`, `allSettled`, `race`, `cancellable`, `onAbort`, `take`, and the `ctx` forms of `retry` / `timeout` / `poll`. Outside a task, pass `{}` or any object with a `signal`. The one exception is `delay(ms)` and `take(event)` as starters of a group, which take no `ctx` (see above).
|
|
1915
1982
|
|
|
1916
1983
|
For `fetch` and other APIs that take a signal, pass `ctx.signal`. A timeout without `race`: `AbortSignal.any([ctx.signal, AbortSignal.timeout(5000)])`.
|
|
1917
1984
|
|
|
@@ -5599,10 +5666,10 @@ bus.on("watch", async (_, ctx) => {
|
|
|
5599
5666
|
};
|
|
5600
5667
|
|
|
5601
5668
|
await race(ctx, {
|
|
5602
|
-
// poll: a check every 5 s; waitForFn: the next pause starts after the check ends
|
|
5603
|
-
polling:
|
|
5604
|
-
// take: resolves at the next "leave", and race stops the polling
|
|
5605
|
-
leave:
|
|
5669
|
+
// poll without ctx: a check every 5 s; waitForFn: the next pause starts after the check ends
|
|
5670
|
+
polling: poll(5000, checkStatus, { waitForFn: true }),
|
|
5671
|
+
// take without ctx: resolves at the next "leave", and race stops the polling
|
|
5672
|
+
leave: take("leave"),
|
|
5606
5673
|
});
|
|
5607
5674
|
});
|
|
5608
5675
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nanoeffects",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.24.0",
|
|
4
4
|
"description": "Cancel stale async work and fix race conditions in event handlers: a typed event bus where every handler is a task with an AbortSignal, plus latest, debounce, throttle, queue, retry, timeout and poll. About 1.4 kB gzip.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"event-bus",
|
|
@@ -220,7 +220,7 @@
|
|
|
220
220
|
{
|
|
221
221
|
"name": "effects (all)",
|
|
222
222
|
"path": "dist/effects.js",
|
|
223
|
-
"limit": "2.
|
|
223
|
+
"limit": "2.8 kB"
|
|
224
224
|
},
|
|
225
225
|
{
|
|
226
226
|
"name": "actions (all)",
|
package/dist/delay-mxZkTg17.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{u as e}from"./context-UcmrAIhP.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 +0,0 @@
|
|
|
1
|
-
import{c as e}from"./context-_HWcdjZf.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};
|