nanoeffects 0.12.0 → 0.13.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/trace.d.ts CHANGED
@@ -120,6 +120,12 @@ type PolicyStage = {
120
120
  * (`["cancel", "drop"]`), or a function of the stage.
121
121
  */
122
122
  type PolicyStages = boolean | readonly Phase[] | ((stage: PolicyStage) => boolean);
123
+ /**
124
+ * Which actions carry the payload of the event: `"all"` of them, the
125
+ * `"essential"` ones (the emits, and the stages that end a call without a result:
126
+ * `cancel`, `drop`, `error`), or `"none"`.
127
+ */
128
+ type PayloadMode = "all" | "essential" | "none";
123
129
  type ReduxDevtoolsOptions = {
124
130
  /** Instance name in the Redux DevTools picker. */
125
131
  name?: string;
@@ -144,6 +150,14 @@ type ReduxDevtoolsOptions = {
144
150
  * The handler tasks themselves are chosen by `policies`.
145
151
  */
146
152
  depth?: number;
153
+ /**
154
+ * Which actions carry the payload of their event. Default `"essential"`: the
155
+ * emits, and the `cancel`, `drop` and `error` of a task, where the payload is
156
+ * the only way to tell which call it was; `start` and `done` repeat the emit
157
+ * and have none. `"all"` puts it in every action, `"none"` in no action, for
158
+ * size or for data that must not reach the extension.
159
+ */
160
+ payload?: PayloadMode;
147
161
  /** The number of actions that DevTools keeps; its own default is 50. */
148
162
  maxAge?: number;
149
163
  };
@@ -210,4 +224,4 @@ type TracerOptions = {
210
224
  */
211
225
  export declare const createTracer: <E = Record<string, unknown>>(trace: Trace<E>, options?: TracerOptions) => Tracer;
212
226
  //#endregion
213
- export type { ConsoleLoggerOptions, PerformanceLoggerOptions, Recorder, ReduxDevtoolsOptions, ReduxDevtoolsState, ReduxExtension, TracerOptions };
227
+ export type { ConsoleLoggerOptions, PayloadMode, PerformanceLoggerOptions, PolicyStage, PolicyStages, Recorder, ReduxDevtoolsOptions, ReduxDevtoolsState, ReduxExtension, TracerOptions };
package/dist/trace.js CHANGED
@@ -1 +1 @@
1
- import{a as e,c as t,d as n,n as r,o as i,r as a,s as o,u as s}from"./context-CJGW6OWj.js";import{n as c}from"./promise-CSLpzwSR.js";import{t as l}from"./origin-key-BbWN3gmN.js";import{t as u}from"./scope-key-B7l7mUS5.js";const d=(e={})=>{let t=e.console??globalThis.console,n=e.prefix??`[nanoeffects]`,r=/* @__PURE__ */ new Map;return({id:e,parentId:i,type:a,effect:o,phase:s,payload:c,error:l,traceGroupId:u})=>{r.has(e)||r.set(e,typeof i==`number`?(r.get(i)??0)+1:0);let d=` `.repeat(r.get(e)??0);s!==`start`&&r.delete(e);let f=u===void 0?``:` [${u}]`,p=`${n}${f} ${d}${a} · ${o} ${s}`;s===`error`?t?.error(p,l):t?.debug(p,c)}},f=(e={})=>{let t=e.performance??globalThis.performance,n=/* @__PURE__ */ new Map;return({id:e,parentId:r,rootId:i,traceGroupId:a,type:o,effect:s,phase:c,error:l})=>{if(!t)return;if(c===`start`){n.set(e,t.now());return}let u=`${o} · ${s} (${c})`,d={id:e,parentId:r,...i!==void 0&&{rootId:i},...a!==void 0&&{traceGroupId:a},phase:c,...c===`error`&&{error:String(l)}},f=n.get(e);n.delete(e),typeof f==`number`?t.measure(u,{start:f,end:t.now(),detail:d}):t.mark(u,{detail:d})}};let p;const m=()=>p,h=(e,t)=>{let n=p;p=e;try{return t()}finally{p=n}},g=(e,t,n={})=>{let{trace:i}=e;if(!i){e.emit(t);return}let{traceId:a,traceGroupId:s}=n,{ctx:c,unlink:l}=r({event:{type:a??t.type,payload:t,...s===void 0?{}:{traceGroupId:s}},bus:{emit:e.emit,on:e.on,off:e.off,ctx:e.ctx,addContext:e.addContext},tracer:i});o(c,`run`,`start`);try{c.emit(t),o(c,`run`,`done`)}catch(e){throw o(c,`run`,`error`,e),e}finally{l()}},_=e=>typeof e==`string`?e:Reflect.get(Object(e),`type`),v=(e,t)=>typeof e==`object`?Reflect.get(Object(e),`payload`):t[0],y=()=>n=>{if(!(t&&n.trace))return n;let{trace:r}=n,o=(e,t)=>{let n=r.task({type:_(e),payload:v(e,t)},a());r.report(n,`emit`,`done`)},s=n.emit;n.emit=(e,...t)=>h(e,()=>(o(e,t),s(e,...t))),Reflect.set(n,l,(e,t)=>{g(n,e,t)});let c=/* @__PURE__ */ new WeakMap,u=(e,t,n)=>{let r=c.get(t)??/* @__PURE__ */ new Map,i=_(e);r.set(i,[...r.get(i)??[],n]),c.set(t,r)},d=(e,t)=>(c.get(t)?.get(_(e)))?.pop(),f=(t,n)=>(r,a)=>(e(a,n),i(a,`run`,()=>t(r,a))),p=(e,t)=>(n,r,i)=>{let a=Reflect.get(Object(i),`traceId`);if(typeof a!=`string`)return e(n,r);let o=t?(e,t)=>(d(n,r),f(r,a)(e,t)):f(r,a);u(n,r,o);let s=e(n,o);return()=>{s()}},m=n.off,y=(e,t)=>{t===void 0?m(e):m(e,d(e,t)??t)},b=n.on,x=n.once;return n.on=p(b,!1),n.once=p(x,!0),n.off=y,n},b=()=>{let e=[];return Object.assign(t=>{e.push(t)},{events:e,clear:()=>{e.length=0}})},x=()=>{},S=()=>!1,C=()=>!0,w=e=>{if(typeof e==`function`)return e;if(Array.isArray(e)){let t=new Set(e);return({phase:e})=>t.has(e)}return e?C:S},T=(e={})=>{let t=e.extension??globalThis.__REDUX_DEVTOOLS_EXTENSION__;if(!t)return x;let{starts:n=!1,depth:r=0,maxAge:i}=e,a=w(e.policies),o=t.connect({name:e.name??`nanoeffects`,...i!==void 0&&{maxAge:i}}),s=/* @__PURE__ */ new Map,c=/* @__PURE__ */ new Map,l=()=>({running:Object.fromEntries(s)});o.init(l());let u=(e,t,n)=>n===0?a({effect:e,phase:t}):n<=r,d=(e,t)=>{e.phase===`start`?(c.set(e.id,t),u(e.effect,`start`,t)&&s.set(e.id,{type:e.type,effect:e.effect,...e.traceGroupId!==void 0&&{traceGroupId:e.traceGroupId}})):(c.delete(e.id),s.delete(e.id))},f=!1,p=!1,m=(e,t)=>{f||p||t!==0||e===`start`||(p=!0,globalThis.console?.warn(`[nanoeffects] reduxDevtools got a task but no emit event: add bus.use(tracePlugin()) to see the emits.`))},h=(e,t)=>{o.send({...e,type:`${e.type}/${e.effect}/${e.phase}`,event:e.type,...e.phase===`error`&&{error:t instanceof Error?t.message:t}},l())};return({error:e,...t})=>{if(t.effect===`emit`){f=!0,o.send({...t,event:t.type},l());return}let r=(t.parentId===void 0?-1:c.get(t.parentId)??-1)+1;d(t,r),m(t.phase,r),(t.phase===`error`&&r===0||u(t.effect,t.phase,r))&&(t.phase!==`start`||n)&&h(t,e)}},E=e=>{let t=typeof e==`function`?[e]:[...e??[]];return t.length===0?null:e=>{for(let r of t)try{r(e)}catch(e){n(`trace logger failed`,e)}}},D=()=>{},O=e=>{if(typeof e.traceGroupId==`string`)return e.traceGroupId;let t=m();if(typeof t!=`object`&&typeof t!=`function`||t===null)return;let n=Reflect.get(t,u),r=typeof n==`object`&&n?Reflect.get(n,`traceGroupId`):void 0;return typeof r==`string`?r:void 0},k=(e,t={})=>{let n=E(e),{filter:r,sample:i=1}=t,a=0,o=e=>typeof i==`function`?i({type:e.type,payload:e.payload}):Math.random()<i,l={task:(e,t)=>({id:++a,root:t?.root??a,parent:t?.id,type:e.type,payload:e.payload,sampled:t?.sampled??o(e),group:O(e)??t?.group}),rename:(e,t)=>{e.type=t},report:(e,t,i,a)=>{if(!e.sampled)return;let o={id:e.id,type:e.type,effect:t,phase:i,payload:e.payload};typeof e.parent==`number`&&(o.parentId=e.parent),e.root!==e.id&&(o.rootId=e.root),e.group!==void 0&&(o.traceGroupId=e.group),i===`error`&&(o.error=a),(!r||r(o))&&n?.(o)},settler:(e,t)=>{if(!e.sampled)return D;let n=!1;return(r,i)=>{n||(n=!0,l.report(e,t,r,i))}},run:(e,t,n,r)=>{if(!e.sampled)return r();let i=l.settler(e,t);l.report(e,t,`start`),s({signal:n},()=>i(`cancel`));let a;try{a=r()}catch(e){throw i(`error`,e),e}return c(a)?Promise.resolve(a).then(e=>(i(`done`),e),e=>{throw i(`error`,e),e}):(i(`done`),a)}};return l};export{d as consoleLogger,b as createTraceRecorder,k as createTracer,f as performanceLogger,T as reduxDevtools,y as tracePlugin};
1
+ import{a as e,c as t,d as n,n as r,o as i,r as a,s as o,u as s}from"./context-CJGW6OWj.js";import{n as c}from"./promise-CSLpzwSR.js";import{t as l}from"./origin-key-BbWN3gmN.js";import{t as u}from"./scope-key-B7l7mUS5.js";const d=(e={})=>{let t=e.console??globalThis.console,n=e.prefix??`[nanoeffects]`,r=/* @__PURE__ */ new Map;return({id:e,parentId:i,type:a,effect:o,phase:s,payload:c,error:l,traceGroupId:u})=>{r.has(e)||r.set(e,typeof i==`number`?(r.get(i)??0)+1:0);let d=` `.repeat(r.get(e)??0);s!==`start`&&r.delete(e);let f=u===void 0?``:` [${u}]`,p=`${n}${f} ${d}${a} · ${o} ${s}`;s===`error`?t?.error(p,l):t?.debug(p,c)}},f=(e={})=>{let t=e.performance??globalThis.performance,n=/* @__PURE__ */ new Map;return({id:e,parentId:r,rootId:i,traceGroupId:a,type:o,effect:s,phase:c,error:l})=>{if(!t)return;if(c===`start`){n.set(e,t.now());return}let u=`${o} · ${s} (${c})`,d={id:e,parentId:r,...i!==void 0&&{rootId:i},...a!==void 0&&{traceGroupId:a},phase:c,...c===`error`&&{error:String(l)}},f=n.get(e);n.delete(e),typeof f==`number`?t.measure(u,{start:f,end:t.now(),detail:d}):t.mark(u,{detail:d})}};let p;const m=()=>p,h=(e,t)=>{let n=p;p=e;try{return t()}finally{p=n}},g=(e,t,n={})=>{let{trace:i}=e;if(!i){e.emit(t);return}let{traceId:a,traceGroupId:s}=n,{ctx:c,unlink:l}=r({event:{type:a??t.type,payload:t,...s===void 0?{}:{traceGroupId:s}},bus:{emit:e.emit,on:e.on,off:e.off,ctx:e.ctx,addContext:e.addContext},tracer:i});o(c,`run`,`start`);try{c.emit(t),o(c,`run`,`done`)}catch(e){throw o(c,`run`,`error`,e),e}finally{l()}},_=e=>typeof e==`string`?e:Reflect.get(Object(e),`type`),v=(e,t)=>typeof e==`object`?Reflect.get(Object(e),`payload`):t[0],y=()=>n=>{if(!(t&&n.trace))return n;let{trace:r}=n,o=(e,t)=>{let n=r.task({type:_(e),payload:v(e,t)},a());r.report(n,`emit`,`done`)},s=n.emit;n.emit=(e,...t)=>h(e,()=>(o(e,t),s(e,...t))),Reflect.set(n,l,(e,t)=>{g(n,e,t)});let c=/* @__PURE__ */ new WeakMap,u=(e,t,n)=>{let r=c.get(t)??/* @__PURE__ */ new Map,i=_(e);r.set(i,[...r.get(i)??[],n]),c.set(t,r)},d=(e,t)=>(c.get(t)?.get(_(e)))?.pop(),f=(t,n)=>(r,a)=>(e(a,n),i(a,`run`,()=>t(r,a))),p=(e,t)=>(n,r,i)=>{let a=Reflect.get(Object(i),`traceId`);if(typeof a!=`string`)return e(n,r);let o=t?(e,t)=>(d(n,r),f(r,a)(e,t)):f(r,a);u(n,r,o);let s=e(n,o);return()=>{s()}},m=n.off,y=(e,t)=>{t===void 0?m(e):m(e,d(e,t)??t)},b=n.on,x=n.once;return n.on=p(b,!1),n.once=p(x,!0),n.off=y,n},b=()=>{let e=[];return Object.assign(t=>{e.push(t)},{events:e,clear:()=>{e.length=0}})},x=()=>{},S=/* @__PURE__ */ new Set([`cancel`,`drop`,`error`]),C=()=>!1,w=()=>!0,T=e=>{if(typeof e==`function`)return e;if(Array.isArray(e)){let t=new Set(e);return({phase:e})=>t.has(e)}return e?w:C},E=(e={})=>{let t=e.extension??globalThis.__REDUX_DEVTOOLS_EXTENSION__;if(!t)return x;let{starts:n=!1,depth:r=0,maxAge:i}=e,a=T(e.policies),o=e.payload??`essential`,s=t.connect({name:e.name??`nanoeffects`,...i!==void 0&&{maxAge:i}}),c=/* @__PURE__ */ new Map,l=/* @__PURE__ */ new Map,u=()=>({running:Object.fromEntries(c)});s.init(u());let d=(e,t,n)=>n===0?a({effect:e,phase:t}):n<=r,f=(e,t)=>{e.phase===`start`?(l.set(e.id,t),d(e.effect,`start`,t)&&c.set(e.id,{type:e.type,effect:e.effect,...e.traceGroupId!==void 0&&{traceGroupId:e.traceGroupId}})):(l.delete(e.id),c.delete(e.id))},p=!1,m=!1,h=(e,t)=>{p||m||t!==0||e===`start`||(m=!0,globalThis.console?.warn(`[nanoeffects] reduxDevtools got a task but no emit event: add bus.use(tracePlugin()) to see the emits.`))},g=e=>{let{payload:t,...n}=e;return o===`all`||o===`essential`&&(e.effect===`emit`||S.has(e.phase))?{...n,payload:t}:n},_=(e,t)=>{s.send({...g(e),type:`${e.type}/${e.effect}/${e.phase}`,event:e.type,...e.phase===`error`&&{error:t instanceof Error?t.message:t}},u())};return({error:e,...t})=>{if(t.effect===`emit`){p=!0,s.send({...g(t),event:t.type},u());return}let r=(t.parentId===void 0?-1:l.get(t.parentId)??-1)+1;f(t,r),h(t.phase,r),(t.phase===`error`&&r===0||d(t.effect,t.phase,r))&&(t.phase!==`start`||n)&&_(t,e)}},D=e=>{let t=typeof e==`function`?[e]:[...e??[]];return t.length===0?null:e=>{for(let r of t)try{r(e)}catch(e){n(`trace logger failed`,e)}}},O=()=>{},k=e=>{if(typeof e.traceGroupId==`string`)return e.traceGroupId;let t=m();if(typeof t!=`object`&&typeof t!=`function`||t===null)return;let n=Reflect.get(t,u),r=typeof n==`object`&&n?Reflect.get(n,`traceGroupId`):void 0;return typeof r==`string`?r:void 0},A=(e,t={})=>{let n=D(e),{filter:r,sample:i=1}=t,a=0,o=e=>typeof i==`function`?i({type:e.type,payload:e.payload}):Math.random()<i,l={task:(e,t)=>({id:++a,root:t?.root??a,parent:t?.id,type:e.type,payload:e.payload,sampled:t?.sampled??o(e),group:k(e)??t?.group}),rename:(e,t)=>{e.type=t},report:(e,t,i,a)=>{if(!e.sampled)return;let o={id:e.id,type:e.type,effect:t,phase:i,payload:e.payload};typeof e.parent==`number`&&(o.parentId=e.parent),e.root!==e.id&&(o.rootId=e.root),e.group!==void 0&&(o.traceGroupId=e.group),i===`error`&&(o.error=a),(!r||r(o))&&n?.(o)},settler:(e,t)=>{if(!e.sampled)return O;let n=!1;return(r,i)=>{n||(n=!0,l.report(e,t,r,i))}},run:(e,t,n,r)=>{if(!e.sampled)return r();let i=l.settler(e,t);l.report(e,t,`start`),s({signal:n},()=>i(`cancel`));let a;try{a=r()}catch(e){throw i(`error`,e),e}return c(a)?Promise.resolve(a).then(e=>(i(`done`),e),e=>{throw i(`error`,e),e}):(i(`done`),a)}};return l};export{d as consoleLogger,b as createTraceRecorder,A as createTracer,f as performanceLogger,E as reduxDevtools,y as tracePlugin};
package/docs/tracing.md CHANGED
@@ -246,6 +246,10 @@ Turn on more when you need it:
246
246
  - `policies` — the stages of the handler tasks, as `event/policy/phase`. `true` shows every phase, a list shows those phases, a function gets `{ effect, phase }`.
247
247
  - `starts: true` — also send the start of each shown task. Running tasks are in the state `{ running }`.
248
248
  - `depth: 1` — also the effects a handler starts (`retry`, `timeout`); `depth: Infinity` — everything below.
249
+ - `payload` — which actions carry the payload of their event:
250
+ - `"essential"` (default) — the emit actions, and the `cancel`, `drop` and `error` of a task, where the payload is the only way to tell which call it was. `start` and `done` repeat the emit and have none, so a large payload is sent once.
251
+ - `"all"` — every action, as in 0.12.
252
+ - `"none"` — no action. Use it for a payload that is large, or holds data that must not reach the browser extension (tokens, personal data). You can then no longer tell which call a policy stopped.
249
253
  - `maxAge: 200` — how many actions DevTools keeps (its default is 50).
250
254
 
251
255
  ```js
@@ -273,7 +277,10 @@ reduxDevtools({
273
277
  });
274
278
 
275
279
  // the old log: every stage, and the effects below the handlers
276
- reduxDevtools({ name: "app", policies: true, depth: 1 });
280
+ reduxDevtools({ name: "app", policies: true, depth: 1, payload: "all" });
281
+
282
+ // keep the payloads out of the extension
283
+ reduxDevtools({ name: "app", payload: "none" });
277
284
  ```
278
285
 
279
286
  With two quick `search` emits and a `latest` handler, the default list is `search`, `search`. With `policies: true` it adds the `latest` stages of each call, for example `search/latest/cancel` for the first one.
package/llms-full.txt CHANGED
@@ -4786,6 +4786,10 @@ Turn on more when you need it:
4786
4786
  - `policies` — the stages of the handler tasks, as `event/policy/phase`. `true` shows every phase, a list shows those phases, a function gets `{ effect, phase }`.
4787
4787
  - `starts: true` — also send the start of each shown task. Running tasks are in the state `{ running }`.
4788
4788
  - `depth: 1` — also the effects a handler starts (`retry`, `timeout`); `depth: Infinity` — everything below.
4789
+ - `payload` — which actions carry the payload of their event:
4790
+ - `"essential"` (default) — the emit actions, and the `cancel`, `drop` and `error` of a task, where the payload is the only way to tell which call it was. `start` and `done` repeat the emit and have none, so a large payload is sent once.
4791
+ - `"all"` — every action, as in 0.12.
4792
+ - `"none"` — no action. Use it for a payload that is large, or holds data that must not reach the browser extension (tokens, personal data). You can then no longer tell which call a policy stopped.
4789
4793
  - `maxAge: 200` — how many actions DevTools keeps (its default is 50).
4790
4794
 
4791
4795
  ```js
@@ -4813,7 +4817,10 @@ reduxDevtools({
4813
4817
  });
4814
4818
 
4815
4819
  // the old log: every stage, and the effects below the handlers
4816
- reduxDevtools({ name: "app", policies: true, depth: 1 });
4820
+ reduxDevtools({ name: "app", policies: true, depth: 1, payload: "all" });
4821
+
4822
+ // keep the payloads out of the extension
4823
+ reduxDevtools({ name: "app", payload: "none" });
4817
4824
  ```
4818
4825
 
4819
4826
  With two quick `search` emits and a `latest` handler, the default list is `search`, `search`. With `policies: true` it adds the `latest` stages of each call, for example `search/latest/cancel` for the first one.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nanoeffects",
3
- "version": "0.12.0",
3
+ "version": "0.13.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",
@@ -165,6 +165,7 @@
165
165
  "lefthook": "2.2.1",
166
166
  "lodash": "4.17.21",
167
167
  "mobx": "^7.0.6",
168
+ "playwright-core": "1.64.1",
168
169
  "publint": "^0.3.25",
169
170
  "react": "^19.3.1",
170
171
  "react-dom": "^19.3.1",