nanoeffects 0.31.2 → 0.33.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.
Files changed (66) hide show
  1. package/dist/{action-creator-6rlBTmH9.d.ts → action-creator-DprJV-pN.d.ts} +6 -2
  2. package/dist/actions.d.ts +3 -3
  3. package/dist/actions.js +1 -1
  4. package/dist/{bus-DFlmNJ6h.js → bus-Cmk4U1hQ.js} +1 -1
  5. package/dist/caller-DULg_ZYV.js +1 -0
  6. package/dist/context-Dp_QRXzb.js +1 -0
  7. package/dist/{context-types-DKNc5mkS.d.ts → context-types-BiTMp_lW.d.ts} +1 -1
  8. package/dist/context.d.ts +2 -2
  9. package/dist/dev.d.ts +2 -2
  10. package/dist/dev.js +2 -2
  11. package/dist/effects.d.ts +2 -2
  12. package/dist/effects.js +1 -1
  13. package/dist/guard.d.ts +1 -1
  14. package/dist/index.d.ts +1 -1
  15. package/dist/index.js +1 -1
  16. package/dist/match.d.ts +1 -1
  17. package/dist/match.js +1 -1
  18. package/dist/{module-G39MaVOt.d.ts → module-DPKjzfRk.d.ts} +2 -2
  19. package/dist/notrace/{action-creator-BrMSO3RP.d.ts → action-creator-BWd9FWt6.d.ts} +2 -2
  20. package/dist/notrace/actions.d.ts +2 -2
  21. package/dist/notrace/actions.js +1 -1
  22. package/dist/notrace/effects.d.ts +2 -2
  23. package/dist/notrace/index.d.ts +1 -1
  24. package/dist/notrace/{plugin-7GUL2EW5.d.ts → plugin-DmAYT3Xk.d.ts} +1 -1
  25. package/dist/notrace/policies.d.ts +1 -1
  26. package/dist/notrace/redux.d.ts +1 -1
  27. package/dist/observable.d.ts +1 -1
  28. package/dist/oop.d.ts +1 -1
  29. package/dist/oop.js +1 -1
  30. package/dist/{plugin-BWNP23hr.d.ts → plugin-2d3uuW7o.d.ts} +2 -2
  31. package/dist/policies.d.ts +2 -2
  32. package/dist/policies.js +1 -1
  33. package/dist/react.d.ts +2 -2
  34. package/dist/react.js +1 -1
  35. package/dist/redux.d.ts +1 -1
  36. package/dist/scope.d.ts +2 -2
  37. package/dist/signal.d.ts +2 -2
  38. package/dist/signal.js +1 -1
  39. package/dist/svelte.d.ts +1 -1
  40. package/dist/testing.d.ts +80 -0
  41. package/dist/testing.js +1 -0
  42. package/dist/trace.d.ts +227 -44
  43. package/dist/trace.js +3 -3
  44. package/dist/tracer-v7m-Qah_.js +2 -0
  45. package/dist/{types-N_cdRr1r.d.ts → types-DxPZDzZG.d.ts} +2 -2
  46. package/dist/vue.d.ts +1 -1
  47. package/dist/{with-policy-CeM1rtES.js → with-policy-BmL0eRU3.js} +1 -1
  48. package/dist/{with-policy-CthiBp_z.d.ts → with-policy-Y12d-yx6.d.ts} +1 -1
  49. package/docs/debugging-cases.md +122 -0
  50. package/docs/debugging-loops.md +79 -0
  51. package/docs/migrating-from-rxjs.md +1 -1
  52. package/docs/package.md +2 -1
  53. package/docs/recipes.md +35 -0
  54. package/docs/ru/debugging-cases.md +122 -0
  55. package/docs/ru/debugging-loops.md +79 -0
  56. package/docs/ru/migrating-from-rxjs.md +1 -1
  57. package/docs/ru/package.md +2 -1
  58. package/docs/ru/recipes.md +35 -0
  59. package/docs/ru/testing.md +92 -0
  60. package/docs/ru/tracing.md +189 -3
  61. package/docs/testing.md +92 -0
  62. package/docs/tracing.md +189 -3
  63. package/llms-full.txt +528 -5
  64. package/llms.txt +4 -2
  65. package/package.json +12 -3
  66. package/dist/context-B5Z2RpJt.js +0 -1
@@ -0,0 +1,80 @@
1
+ import { H as EventMap, v as Bus, y as BusOptions } from "./action-creator-DprJV-pN.js";
2
+ //#region src/testing/clock.d.ts
3
+ /** What the runner needs from time: move it forward, and read it. */
4
+ type Clock = {
5
+ /** Moves time forward by `ms` and lets the timers and the promises of that time run. */
6
+ advance(ms: number): void | Promise<void>;
7
+ /** The time now, in milliseconds. */
8
+ now(): number;
9
+ };
10
+ /** The part of `vi` (Vitest) and `jest` (Jest) that `fakeTimersClock` uses. */
11
+ type FakeTimers = {
12
+ advanceTimersByTimeAsync(ms: number): Promise<unknown>;
13
+ };
14
+ /**
15
+ * A clock over fake timers. The test turns them on itself (`vi.useFakeTimers()`), and leaves `Date`
16
+ * faked, which is the default, because the clock reads `Date.now()`.
17
+ *
18
+ * @example
19
+ * ```ts
20
+ * import { vi } from "vitest";
21
+ * import { fakeTimersClock } from "nanoeffects/testing";
22
+ *
23
+ * vi.useFakeTimers();
24
+ * const clock = fakeTimersClock(vi);
25
+ * ```
26
+ */
27
+ export declare const fakeTimersClock: (timers: FakeTimers) => Clock;
28
+ //#endregion
29
+ //#region src/testing/runner.d.ts
30
+ type MarbleOptions<E extends EventMap> = Omit<BusOptions<E>, "trace"> & {
31
+ /** Moves time and tells it. `fakeTimersClock(vi)` is one. */
32
+ clock: Clock;
33
+ /** The length of a frame in milliseconds. Default 10. */
34
+ frame?: number;
35
+ };
36
+ /** What to emit for one event: a diagram, and the value of each character (the character itself by default). */
37
+ type EmitMarble = {
38
+ marble: string;
39
+ values?: Record<string, unknown>;
40
+ };
41
+ type RunOptions = {
42
+ /** Event name → what to emit. */
43
+ emits?: Record<string, EmitMarble>;
44
+ /** How many frames to run. Default: the length of the longest diagram of `emits`. */
45
+ frames?: number;
46
+ };
47
+ type MarbleResult = {
48
+ /** The number of frames that were run. */
49
+ frames: number;
50
+ /** The phases of every traced task as diagrams, by `type:effect`. */
51
+ rows(): Record<string, string>;
52
+ /**
53
+ * Throws when a row differs, with both diagrams. A key with `:` is one row (`search:run`), a key
54
+ * without it is the effect (`latest`) and must match one row. Returns the result.
55
+ */
56
+ expect(expected: Record<string, string>): MarbleResult;
57
+ };
58
+ /**
59
+ * A bus that records its trace, and a `run` that moves time frame by frame, emits what the
60
+ * diagrams say at the start of each frame, and gives the phases of the tasks back as diagrams.
61
+ * Register the listeners on `bus`, then `run`. It needs a tracer, so there is no `notrace` build.
62
+ *
63
+ * @example
64
+ * ```ts
65
+ * const marbles = createMarbleBus({ clock: fakeTimersClock(vi) });
66
+ * marbles.bus.on("search/changed", latest(search), { traceId: "search" });
67
+ *
68
+ * const result = await marbles.run({
69
+ * emits: { "search/changed": { marble: "a-b---", values: { a: "x", b: "xy" } } },
70
+ * frames: 12,
71
+ * });
72
+ * result.expect({ latest: "s-c-d-" });
73
+ * ```
74
+ */
75
+ export declare const createMarbleBus: <E extends EventMap = EventMap>(options: MarbleOptions<E>) => {
76
+ bus: Bus<E>;
77
+ run: ({ emits, frames }?: RunOptions) => Promise<MarbleResult>;
78
+ };
79
+ //#endregion
80
+ export type { Clock, EmitMarble, FakeTimers, MarbleOptions, MarbleResult, RunOptions };
@@ -0,0 +1 @@
1
+ import{t as e}from"./bus-Cmk4U1hQ.js";import{n as t,t as n}from"./tracer-v7m-Qah_.js";const r=e=>({advance:t=>e.advanceTimersByTimeAsync(t).then(()=>{}),now:()=>Date.now()}),i={start:`s`,done:`d`,error:`e`,cancel:`c`,drop:`x`},a=new Set(Object.values(i)),o=e=>i[e],s=(e,t,n)=>{throw Error(`marble "${e}": ${n} at position ${t}`)},c=(e,t,n)=>{for(let r=0;r<n.length;r+=1){let i=n.charAt(r);(/\s/.test(i)||i===`|`)&&s(e,t+r,`"${i.trim()||`space`}" is not part of a diagram`)}},l=(e,t)=>{let n=e.indexOf(`)`,t);n<0&&s(e,t,`a group that is not closed with ")"`);let r=e.slice(t+1,n);r===``&&s(e,t,`an empty group`);let i=r.indexOf(`(`);i>=0&&s(e,t+1+i,`a group inside a group`);let a=r.indexOf(`-`);return a>=0&&s(e,t+1+a,`"-" inside a group`),c(e,t+1,r),{frame:[...r],next:n+1}},u=(e,t)=>{let n=e.charAt(t);return n===`(`?l(e,t):(n===`)`&&s(e,t,`")" without "("`),c(e,t,n),{frame:n===`-`?[]:[n],next:t+1})},d=e=>{let t=[],n=0;for(;n<e.length;){let{frame:r,next:i}=u(e,n);t.push(r),n=i}return t},f=e=>{let t=d(e),n=0;for(let r of t){for(let t of r)a.has(t)||s(e,n,`"${t}" is not a phase (s d e c x)`);n+=r.length||1}return t},p=(e,t)=>{let n=``;for(let r=0;r<t;r+=1){let t=e[r]??[];t.length===0?n+=`-`:t.length===1?n+=t[0]:n+=`(${t.join(``)})`}return n},m=(e,t)=>e&&Object.hasOwn(e,t)?e[t]:t,h=(e,t,n,r,i)=>{let a=Array.from({length:i},()=>[]);for(let o of e){let e=Math.floor((o.at-n)/r);o.key===t&&e>=0&&e<i&&a[e]?.push(o.letter)}return a},g=(e,t)=>t.includes(`:`)?e.includes(t)?[t]:[]:e.filter(e=>e.endsWith(`:${t}`)),_=(e,t,n)=>`marble row "${e}" differs\n expected ${t}\n received ${n}`,v=(e,t,n,r)=>{let i=[...new Set(e.map(e=>e.key))],a=()=>Object.fromEntries(i.map(i=>[i,p(h(e,i,t,n,r),r)])),o={frames:r,rows:a,expect:e=>{let t=a();for(let[n,a]of Object.entries(e)){let e=g(i,n),[o]=e;if(o===void 0)throw Error(`marble row "${n}" matches no task; rows: ${i.join(`, `)||`none`}`);if(e.length>1)throw Error(`marble row "${n}" matches more than one task (${e.join(`, `)}): give the full key`);let s=p(f(a),r);if(s!==t[o])throw Error(_(o,s,t[o]??``))}return o}};return o},y=r=>{let{clock:i,frame:a=10,...s}=r,c=[],l=e=>{e.effect!==`emit`&&c.push({key:`${e.type}:${e.effect}`,letter:o(e.phase),at:i.now()})},u=e({...s,trace:n(l)});return u.use(t()),{bus:u,run:async({emits:e={},frames:t}={})=>{let n=Object.entries(e).map(([e,t])=>({event:e,frames:d(t.marble),values:t.values})),r=t??Math.max(0,...n.map(e=>e.frames.length));c.length=0;let o=i.now();for(let e=0;e<r;e+=1){for(let t of n)for(let n of t.frames[e]??[])Reflect.apply(u.emit,u,[t.event,m(t.values,n)]);await i.advance(a)}return v(c,o,a,r)}}};export{y as createMarbleBus,r as fakeTimersClock};
package/dist/trace.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { B as Tracer, H as EventMap, J as TaskInfo, K as Phase, V as EffectName, X as TraceEvent, Y as Trace, Z as TraceLogger, v as Bus } from "./action-creator-6rlBTmH9.js";
1
+ import { B as Tracer, H as EventMap, J as TaskInfo, K as Phase, V as EffectName, X as TraceEvent, Y as Trace, Z as TraceLogger, v as Bus } from "./action-creator-DprJV-pN.js";
2
2
  //#region src/graph/serialize.d.ts
3
3
  type JsonValue = null | boolean | number | string | JsonValue[] | {
4
4
  [key: string]: JsonValue;
@@ -136,12 +136,151 @@ type GraphLogger = TraceLogger & {
136
136
  */
137
137
  export declare const graphLogger: (options?: GraphLoggerOptions) => GraphLogger;
138
138
  //#endregion
139
+ //#region src/graph/merge.d.ts
140
+ /**
141
+ * Joins the graphs of several runs (tests, e2e, a manual session) into one, so a
142
+ * listener or an edge that no single run reached can still be seen by another.
143
+ * Counts add up, nodes and edges are the union, and a cycle found twice is one
144
+ * cycle. The snapshots you pass are not changed.
145
+ *
146
+ * @example
147
+ * ```ts
148
+ * import { mergeGraphs } from "nanoeffects/trace";
149
+ *
150
+ * // each run wrote `graph.toJSON()` to a file
151
+ * const all = mergeGraphs(unitRun, e2eRun);
152
+ * ```
153
+ */
154
+ export declare const mergeGraphs: (...snapshots: GraphSnapshot[]) => GraphSnapshot;
155
+ //#endregion
156
+ //#region src/graph/orphans.d.ts
157
+ /**
158
+ * A listener that the graph never saw run. `unemitted`: the graph has no node for
159
+ * the event, so nobody emitted it. `unrun`: the event was emitted, this listener
160
+ * did not run.
161
+ */
162
+ type Orphan = {
163
+ event: string;
164
+ listener: string;
165
+ kind: "unemitted" | "unrun";
166
+ };
167
+ /**
168
+ * Compares the listeners a bus has with the graph of what ran, and lists the
169
+ * listeners the graph never saw. Pass `describeBus(bus)` (with or without `source`) and
170
+ * `graph.toJSON()`, or the result of `mergeGraphs` for wider coverage. A listener
171
+ * is a node of the graph once it has run, by its `traceId` or function name;
172
+ * anonymous listeners have no node and are left out. One run shows many false
173
+ * orphans: read the list as a hint, not as a failure.
174
+ *
175
+ * @example
176
+ * ```ts
177
+ * import { describeBus, findOrphans } from "nanoeffects/trace";
178
+ *
179
+ * const described = describeBus(bus);
180
+ * const orphans = findOrphans(described, graph.toJSON());
181
+ * // [{ event: "cart/cleared", listener: "reset", kind: "unemitted" }]
182
+ * ```
183
+ */
184
+ export declare const findOrphans: (described: Readonly<Record<string, readonly string[]>>, snapshot: GraphSnapshot) => Orphan[];
185
+ //#endregion
186
+ //#region src/trace/task-index.d.ts
187
+ /** What the `task` hook told about one task, also a task that reports no event. */
188
+ type KnownTask = {
189
+ type: string;
190
+ parentId?: number;
191
+ source?: string;
192
+ traceGroupId?: string;
193
+ };
194
+ //#endregion
195
+ //#region src/trace/recorder.d.ts
196
+ type Recorder<E = Record<string, unknown>> = TraceLogger<E> & {
197
+ /**
198
+ * The events received so far, oldest first. Without a `capacity` it is one
199
+ * live array; with one, each read is a new array that is a snapshot.
200
+ */
201
+ readonly events: TraceEvent<E>[];
202
+ /**
203
+ * The tasks the tracer told about, by `id`, also the ones that report no event (a plain
204
+ * listener). `chainOf` reads them to keep a path whole. Cut by `capacity` like `events`.
205
+ */
206
+ readonly tasks: ReadonlyMap<number, KnownTask>;
207
+ clear: () => void;
208
+ /**
209
+ * The events as plain data that `JSON.stringify` takes: the payload and the error are made safe, so a
210
+ * circular object, an `Error`, a `Map` or a class instance cannot break it. `JSON.stringify(recorder)` uses it.
211
+ */
212
+ toJSON: () => JsonValue[];
213
+ };
214
+ /**
215
+ * Trace logger that keeps events in memory. With no option it keeps all of
216
+ * them, for tests. With `capacity` it keeps the last events, to send when
217
+ * something goes wrong.
218
+ *
219
+ * `payload` and `error` are kept as they are, and can hold private data: cut
220
+ * what you send. An event has no time, and a `parentId` can name an event that
221
+ * was pushed out: read it as a root.
222
+ *
223
+ * @example
224
+ * ```ts
225
+ * const recorder = createTraceRecorder<Events>();
226
+ * const bus = createBus<Events>({ trace: createTracer(recorder) });
227
+ *
228
+ * bus.emit("search", "re");
229
+ * bus.emit("search", "redux");
230
+ * recorder.events.map((e) => e.phase); // ["start", "cancel", "start", "done"]
231
+ *
232
+ * const lastEvents = createTraceRecorder<Events>({ capacity: 500 });
233
+ * ```
234
+ */
235
+ export declare const createTraceRecorder: <E = Record<string, unknown>>(
236
+ /** `capacity`: keep the last N events (a ring buffer); not a positive integer, or left out: keep all. */
237
+ options?: {
238
+ capacity?: number;
239
+ }) => Recorder<E>;
240
+ //#endregion
241
+ //#region src/trace/chain.d.ts
242
+ /** One task on the way from the root to the task you asked about. */
243
+ type ChainStep = {
244
+ id: number;
245
+ type: string;
246
+ /** Absent for a task that reported no event (a plain listener). */
247
+ effect?: EffectName;
248
+ /** The latest phase of the task; absent when it reported no event. */
249
+ phase?: Phase;
250
+ source?: string;
251
+ traceGroupId?: string;
252
+ };
253
+ type ChainSource<E> = readonly TraceEvent<E>[] | Pick<Recorder<E>, "events" | "tasks">;
254
+ /**
255
+ * The causal path of a task: the tasks that led to it, from the root, ending
256
+ * with the task itself. Use it to answer "what started the task that failed".
257
+ *
258
+ * Give it a recorder to keep the listeners that report no event in the path;
259
+ * a plain list of events (a snapshot, a file read back) shows only the tasks
260
+ * that have events.
261
+ *
262
+ * A parent that is not known (pushed out by a `capacity`) ends the path:
263
+ * it starts at the oldest task that is known. An unknown `id` gives `[]`.
264
+ *
265
+ * @example
266
+ * ```ts
267
+ * const failed = recorder.events.find((event) => event.phase === "error");
268
+ * const path = chainOf(recorder, failed.id);
269
+ * path.map((step) => step.type).join(" → "); // "queryChanged → searchLoaded"
270
+ * ```
271
+ */
272
+ export declare const chainOf: <E = Record<string, unknown>>(source: ChainSource<E>, id: number) => ChainStep[];
273
+ //#endregion
139
274
  //#region src/trace/console.d.ts
140
275
  type ConsoleLoggerOptions = {
141
276
  /** Defaults to `globalThis.console`. */
142
277
  console?: Pick<Console, "debug" | "error">;
143
278
  /** Prepended to every line. */
144
279
  prefix?: string;
280
+ /** Append where the listener was registered, to the lines of events that have it. Default `false`. */
281
+ source?: boolean;
282
+ /** Append the path from the root, with the listeners that report nothing, to the line of an `error`. Default `false`. */
283
+ chain?: boolean;
145
284
  };
146
285
  /**
147
286
  * Trace logger that prints one line per phase, indented by task depth.
@@ -156,6 +295,32 @@ type ConsoleLoggerOptions = {
156
295
  */
157
296
  export declare const consoleLogger: (options?: ConsoleLoggerOptions) => TraceLogger;
158
297
  //#endregion
298
+ //#region src/trace/describe.d.ts
299
+ type DescribeBusOptions = {
300
+ /** Add where each listener was registered, for the ones `tracePlugin({ source: true })` recorded. Default `false`. */
301
+ source?: boolean;
302
+ };
303
+ /**
304
+ * The listeners that each event has right now, by name and in the order they were
305
+ * added: the `traceId` of a listener, else its function name, else `"<anonymous>"`.
306
+ * Reads what `tracePlugin` keeps, so it returns `{}` on a bus without the plugin or
307
+ * a tracer, and in the `notrace` build. It changes nothing on the bus. With `{ source: true }`
308
+ * each name is followed by `(file:line:column)` of its registration, when it was recorded.
309
+ *
310
+ * @example
311
+ * ```ts
312
+ * import { createBus } from "nanoeffects";
313
+ * import { consoleLogger, createTracer, describeBus, tracePlugin } from "nanoeffects/trace";
314
+ *
315
+ * const trace = createTracer(consoleLogger());
316
+ * const bus = createBus({ trace }).use(tracePlugin());
317
+ * bus.on("name/changed", function saveName() {});
318
+ *
319
+ * describeBus(bus); // { "name/changed": ["saveName"] }
320
+ * ```
321
+ */
322
+ export declare const describeBus: <E extends EventMap>(bus: Bus<E>, options?: DescribeBusOptions) => Record<string, string[]>;
323
+ //#endregion
159
324
  //#region src/trace/performance.d.ts
160
325
  /** The part of the User Timing API the logger uses. */
161
326
  type PerformanceLike = {
@@ -186,6 +351,14 @@ type PerformanceLoggerOptions = {
186
351
  export declare const performanceLogger: (options?: PerformanceLoggerOptions) => TraceLogger;
187
352
  //#endregion
188
353
  //#region src/trace/plugin.d.ts
354
+ type TracePluginOptions = {
355
+ /**
356
+ * Record where each `bus.on` and `bus.once` was called (`file:line:column`) and put it on the
357
+ * events of the listener. Reads one stack at registration, never on emit. An anonymous listener
358
+ * is reported too, under the type of its event. Default `false`.
359
+ */
360
+ source?: boolean;
361
+ };
189
362
  /**
190
363
  * Names and groups what the trace shows, on a bus that has a tracer:
191
364
  *
@@ -213,48 +386,7 @@ export declare const performanceLogger: (options?: PerformanceLoggerOptions) =>
213
386
  * bus.on("name/changed", saveName, { traceId: "saveNotifier" });
214
387
  * ```
215
388
  */
216
- export declare const tracePlugin: () => <E extends EventMap>(bus: Bus<E>) => Bus<E>;
217
- //#endregion
218
- //#region src/trace/recorder.d.ts
219
- type Recorder<E = Record<string, unknown>> = TraceLogger<E> & {
220
- /**
221
- * The events received so far, oldest first. Without a `capacity` it is one
222
- * live array; with one, each read is a new array that is a snapshot.
223
- */
224
- readonly events: TraceEvent<E>[];
225
- clear: () => void;
226
- /**
227
- * The events as plain data that `JSON.stringify` takes: the payload and the error are made safe, so a
228
- * circular object, an `Error`, a `Map` or a class instance cannot break it. `JSON.stringify(recorder)` uses it.
229
- */
230
- toJSON: () => JsonValue[];
231
- };
232
- /**
233
- * Trace logger that keeps events in memory. With no option it keeps all of
234
- * them, for tests. With `capacity` it keeps the last events, to send when
235
- * something goes wrong.
236
- *
237
- * `payload` and `error` are kept as they are, and can hold private data: cut
238
- * what you send. An event has no time, and a `parentId` can name an event that
239
- * was pushed out: read it as a root.
240
- *
241
- * @example
242
- * ```ts
243
- * const recorder = createTraceRecorder<Events>();
244
- * const bus = createBus<Events>({ trace: createTracer(recorder) });
245
- *
246
- * bus.emit("search", "re");
247
- * bus.emit("search", "redux");
248
- * recorder.events.map((e) => e.phase); // ["start", "cancel", "start", "done"]
249
- *
250
- * const lastEvents = createTraceRecorder<Events>({ capacity: 500 });
251
- * ```
252
- */
253
- export declare const createTraceRecorder: <E = Record<string, unknown>>(
254
- /** `capacity`: keep the last N events (a ring buffer); not a positive integer, or left out: keep all. */
255
- options?: {
256
- capacity?: number;
257
- }) => Recorder<E>;
389
+ export declare const tracePlugin: (options?: TracePluginOptions) => <E extends EventMap>(bus: Bus<E>) => Bus<E>;
258
390
  //#endregion
259
391
  //#region src/trace/redux.d.ts
260
392
  type ReduxConnection = {
@@ -353,6 +485,57 @@ type ReduxDevtoolsState = {
353
485
  */
354
486
  export declare const reduxDevtools: (options?: ReduxDevtoolsOptions) => TraceLogger;
355
487
  //#endregion
488
+ //#region src/trace/timing.d.ts
489
+ /** One task of the trace with the time it took, or the time since it started. */
490
+ type TimedTask = {
491
+ id: number;
492
+ type: string;
493
+ effect: EffectName;
494
+ parentId?: number;
495
+ rootId?: number;
496
+ source?: string;
497
+ /** Milliseconds from `start` to the closing phase, or to now for an open task. */
498
+ ms: number;
499
+ };
500
+ /** A task that closed: how it ended and how long it took. */
501
+ type ClosedTask = TimedTask & {
502
+ phase: Exclude<Phase, "start">;
503
+ };
504
+ type TimingLoggerOptions = {
505
+ /** The clock, in ms. Default `performance.now`, or `Date.now` where there is none. */
506
+ now?: () => number;
507
+ /** Keep only the last N closed tasks in `durations`. `pending()` is never cut. Not a positive integer, or left out: keep all. */
508
+ capacity?: number;
509
+ };
510
+ type TimingLogger = TraceLogger & {
511
+ /** The tasks that closed, oldest closed first. One live array. */
512
+ readonly durations: ClosedTask[];
513
+ /** The tasks that started and have not closed, oldest started first, with the time since `start`. */
514
+ pending: () => TimedTask[];
515
+ clear: () => void;
516
+ };
517
+ /**
518
+ * Trace logger that measures time. It stamps each event when it gets it,
519
+ * pairs `start` with the first `done`, `error`, `cancel` or `drop` of the same
520
+ * task and effect, and keeps the result. Use it to find a slow handler, to see
521
+ * how long a request lived before `cancel`, or to check that a test left
522
+ * no task open.
523
+ *
524
+ * The logger sees what the tracer lets through: a task whose `start` was
525
+ * filtered or not sampled never pairs, and its closing event is ignored.
526
+ *
527
+ * @example
528
+ * ```ts
529
+ * const timing = timingLogger();
530
+ * const bus = createBus<Events>({ trace: createTracer(timing) });
531
+ *
532
+ * bus.emit("search", "redux");
533
+ * timing.pending(); // [{ id: 1, type: "search", effect: "latest", ms: 0 }]
534
+ * timing.durations; // after it ends: [{ ..., phase: "done", ms: 120 }]
535
+ * ```
536
+ */
537
+ export declare const timingLogger: (options?: TimingLoggerOptions) => TimingLogger;
538
+ //#endregion
356
539
  //#region src/trace/tracer.d.ts
357
540
  type TracerOptions = {
358
541
  /** Drops the events it returns `false` for, before any logger sees them. */
@@ -388,4 +571,4 @@ type TracerOptions = {
388
571
  */
389
572
  export declare const createTracer: <E = Record<string, unknown>>(trace: Trace<E>, options?: TracerOptions) => Tracer;
390
573
  //#endregion
391
- export type { ConsoleLoggerOptions, EffectName, ExportOptions, Finding, GraphLogger, GraphLoggerOptions, GraphSnapshot, JsonOptions, JsonValue, PayloadMode, PerformanceLoggerOptions, Phase, PolicyStage, PolicyStages, Recorder, ReduxDevtoolsOptions, ReduxDevtoolsState, ReduxExtension, SerializeOptions, TaskInfo, Trace, TraceEvent, TraceLogger, Tracer, TracerOptions };
574
+ export type { ChainStep, ClosedTask, ConsoleLoggerOptions, DescribeBusOptions, EffectName, ExportOptions, Finding, GraphLogger, GraphLoggerOptions, GraphSnapshot, JsonOptions, JsonValue, Orphan, PayloadMode, PerformanceLoggerOptions, Phase, PolicyStage, PolicyStages, Recorder, ReduxDevtoolsOptions, ReduxDevtoolsState, ReduxExtension, SerializeOptions, TaskInfo, TimedTask, TimingLogger, TimingLoggerOptions, Trace, TraceEvent, TraceLogger, TracePluginOptions, Tracer, TracerOptions };
package/dist/trace.js CHANGED
@@ -1,3 +1,3 @@
1
- import{n as e,t}from"./onAbort-BgMfspK4.js";import{a as n,c as r,n as i,o as a,r as o,s}from"./context-B5Z2RpJt.js";import{n as c}from"./promise-CSLpzwSR.js";import{t as l}from"./origin-key-BbWN3gmN.js";import{n as u}from"./site-DLvUoXs3.js";import{t as d}from"./scope-key-B7l7mUS5.js";const f=e=>{let t=/* @__PURE__ */ new Map;for(let{from:n,to:r}of e){let e=t.get(n)??[];e.push(r),t.set(n,e),t.has(r)||t.set(r,[])}let n=/* @__PURE__ */ new Map,r=/* @__PURE__ */ new Map,i=/* @__PURE__ */ new Set,a=[],o=[],s=0,c=(e,t)=>{n.set(e,s),r.set(e,s),s+=1,a.push(e),i.add(e),t.push({name:e,next:0})},l=e=>{let n=[],r;do{if(r=a.pop(),r===void 0)break;i.delete(r),n.push(r)}while(r!==e);let[s]=n,c=n.length===1&&s!==void 0&&t.get(s)?.includes(s);(n.length>1||c)&&o.push(n.reverse())},u=(e,t)=>{r.set(e,Math.min(r.get(e)??t,t))},d=(e,r)=>{let a=t.get(r.name)?.[r.next];return a!==void 0&&(r.next+=1,n.has(a)?i.has(a)&&u(r.name,n.get(a)??0):c(a,e),!0)},f=(e,t)=>{e.pop();let i=e.at(-1);i&&u(i.name,r.get(t.name)??0),r.get(t.name)===n.get(t.name)&&l(t.name)},p=e=>{let t=[];c(e,t);for(let e=t.at(-1);e;e=t.at(-1))d(t,e)||f(t,e)};for(let e of t.keys())n.has(e)||p(e);return o},p=(e,t)=>{if(t===`prefix`){let t=e.indexOf(`/`);return t>0?e.slice(0,t):void 0}return t?.(e)},m=e=>e.replaceAll(`"`,`#quot;`).replaceAll(`<`,`#lt;`).replaceAll(`>`,`#gt;`).replaceAll(/\r?\n/g,` `),h=e=>e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`).replaceAll(/\r?\n/g,`\\n`),g=e=>new Map(e.nodes.map((e,t)=>[e.name,`n${t}`])),_=(e,t)=>{let n=/* @__PURE__ */ new Map;for(let{name:r}of e.nodes){let e=p(r,t);e!==void 0&&n.set(e,[...n.get(e)??[],r])}return n},v=(e,t={})=>{let n=g(e),r=[`flowchart LR`],i=/* @__PURE__ */ new Set;for(let[a,o]of _(e,t.group)){r.push(` subgraph g_${r.length}["${m(a)}"]`);for(let e of o)i.add(e),r.push(` ${n.get(e)}["${m(e)}"]`);r.push(` end`)}for(let{name:t}of e.nodes)i.has(t)||r.push(` ${n.get(t)}["${m(t)}"]`);let a=[];for(let[t,i]of e.edges.entries())r.push(` ${n.get(i.from)} -->|x${i.count}| ${n.get(i.to)}`),i.inCycle&&a.push(t);return a.length>0&&r.push(` linkStyle ${a.join(`,`)} stroke:red,stroke-width:2px`),r.join(`
2
- `)},y=(e,t={})=>{let n=g(e),r=[`digraph events {`];e.name!==void 0&&r.push(` label="${h(e.name)}";`);let i=/* @__PURE__ */ new Set;for(let[a,o]of _(e,t.group)){r.push(` subgraph "cluster_${h(a)}" {`,` label="${h(a)}";`);for(let e of o)i.add(e),r.push(` ${n.get(e)} [label="${h(e)}"];`);r.push(` }`)}for(let{name:t}of e.nodes)i.has(t)||r.push(` ${n.get(t)} [label="${h(t)}"];`);for(let t of e.edges){let e=t.inCycle?`, color=red, penwidth=2`:``;r.push(` ${n.get(t.from)} -> ${n.get(t.to)} [label="x${t.count}"${e}];`)}return r.push(`}`),r.join(`
3
- `)},b=e=>e.kind===`storm`?"an emit from a component or a timer repeats: stop it with `equals` of useEmitter, debounce, or a guard":e.kind===`runaway`?`one chain started a huge number of tasks: look for event names that are made from a counter or an id`:e.path.length<=2?`a handler emits its own event: emit a different event for the result`:`handlers feed each other: break the loop with a condition, or emit a different event for the result`,x=(e,t)=>{let n=t===void 0?`[nanoeffects]`:`[nanoeffects ${t}]`,r=e.traceGroupId===void 0?``:` (flow ${e.traceGroupId})`,i=e.kind===`cycle`?`cycle: ${e.path.join(` → `)} (repeated ${e.repeats} times, started at ${e.root})`:`${e.kind}: ${e.path.join(` → `)} (${e.repeats} in a row, started at ${e.root})`,a=[...new Set(e.path)].flatMap(e=>{let t=u(e);return t===void 0?[]:[`${e} at ${t}`]});return`${n} ${i}${r}${a.length>0?`\n ${a.join(`; `)}`:``}\n ${b(e)}`},S=(e,t)=>{if(!e)return;let n=e.connect({name:t});n.init({findings:0});let r=0;return e=>{r+=1,n.send({type:`cycle/detected`,kind:e.kind,path:e.path,repeats:e.repeats,root:e.root},{findings:r})}},C=2e3,w=e=>{let t=Object.getPrototypeOf(e),n=t===null?void 0:Reflect.get(t,`constructor`),r=typeof n==`function`?n.name:``;return typeof r==`string`&&r!==``?r:`Object`},T=e=>{let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype},E=e=>typeof Reflect.get(e,`nodeType`)==`number`&&typeof Reflect.get(e,`nodeName`)==`string`,D=e=>e.length>C?`${e.slice(0,C)}…`:e,O=e=>{switch(typeof e){case`string`:return D(e);case`boolean`:return e;case`number`:return Number.isFinite(e)?e:String(e);case`bigint`:return`${e}n`;case`symbol`:return String(e);case`function`:return`[Function ${e.name||`anonymous`}]`;default:return e===null?null:void 0}},k=e=>{if(e instanceof WeakMap)return`[WeakMap]`;if(e instanceof WeakSet)return`[WeakSet]`;if(e instanceof Promise)return`[Promise]`;if(E(e))return`[DOM ${String(Reflect.get(e,`nodeName`))}]`;if(e instanceof Date)return Number.isNaN(e.getTime())?`[Invalid Date]`:e.toISOString()},A=(e,t,n)=>{if(t.budget<=0)return`[Cut]`;--t.budget;let r=O(e);return r===void 0?typeof e!=`object`||!e?`[undefined]`:j(e,t,n):r},j=(e,t,n)=>{try{let r=k(e);return r===void 0?t.path.has(e)?`[Circular]`:n>=t.maxDepth?Array.isArray(e)?`[Array]`:`[${w(e)}]`:M(e,t,n):r}catch{return`[Unserializable]`}},M=(e,t,n)=>{t.path.add(e);try{return N(e,t,n)}finally{t.path.delete(e)}},N=(e,t,n)=>e instanceof Error?P(e,t,n):Array.isArray(e)?F(e,t,n):e instanceof Map?{$map:F([...e.entries()],t,n)}:e instanceof Set?{$set:F([...e.values()],t,n)}:ArrayBuffer.isView(e)?{$class:w(e),length:Number(Reflect.get(e,`length`))}:I(e,t,n,T(e)?void 0:w(e)),P=(e,t,n)=>{let r={name:D(e.name),message:D(e.message)};return typeof e.stack==`string`&&(r.stack=D(e.stack)),`cause`in e&&(r.cause=A(e.cause,t,n+1)),r},F=(e,t,n)=>{let r=[];for(let[i,a]of e.entries()){if(t.budget<=0){r.push(`[${e.length-i} more]`);break}r.push(A(a,t,n+1))}return r},I=(e,t,n,r)=>{let i={};r!==void 0&&(i.$class=r);for(let r of Object.keys(e)){let a=Object.getOwnPropertyDescriptor(e,r);a&&(i[r]=`value`in a?A(a.value,t,n+1):`[Getter]`)}return i},L=(e,t={})=>{let n={maxDepth:t.maxDepth??6,budget:t.maxSize??1e3,path:/* @__PURE__ */ new Set};try{return A(e,n,0)}catch{return`[Unserializable]`}},R=(e,t)=>`${e}\u0000${t}`,z=e=>{if(typeof e==`function`)return e;let t=new Set(e);return e=>t.has(e)},B=e=>e.event===void 0?[e.node]:[e.event,e.node],V=e=>{let t=e.slice(0,-1),n=t.reduce((e,n,r)=>n<(t[e]??n)?r:e,0);return[...t.slice(n),...t.slice(0,n)].join(`\0`)},H=(e,t)=>{let{node:n}=t,r=[],i=e;for(;i&&i.node!==n;)r.push(i),i=i.parent;let a=r.reverse();return{path:[n,...a.flatMap(B),...B(t)],names:[n,...a.map(e=>e.node),n]}},U=(e={})=>{let t=e.repeats??3,n=e.maxSteps??5e3,r=e.storm===!1?void 0:e.storm??{count:100,perMs:1e3},i=z(e.ignore),a=e.now??(()=>globalThis.performance.now()),o=e.console??globalThis.console,s=/* @__PURE__ */ new Map,c=/* @__PURE__ */ new Map,l=/* @__PURE__ */ new Map,d=/* @__PURE__ */ new WeakMap,p=/* @__PURE__ */ new Map,m=/* @__PURE__ */ new Set,h=!1,g=!1,_,b,C=!1,w=!1,T=e=>{let t=s.get(e)??{count:0};t.count+=1,s.set(e,t)},E=(e,t)=>{let n=R(e,t),r=c.get(n)??{from:e,to:t,count:0,inCycle:!1};r.count+=1,c.set(n,r)},D=t=>{if(e.devtools&&!C){C=!0;let t=e.extension??globalThis.__REDUX_DEVTOOLS_EXTENSION__;b=S(t,e.name??`nanoeffects graph`)}b?.(t),e.onCycle?e.onCycle(t):o?.warn(x(t,e.name))},O=(e,t)=>{let n=l.get(e);if(n){n.turns+=1;return}let r=t();if(l.set(e,r),!w){w=!0;try{D(r)}catch(e){globalThis.console?.error(`[nanoeffects] graph logger report failed`,e)}finally{w=!1}}},k=(e,t)=>{let n=new Map(e.counts);n.set(t,(n.get(t)??0)+1),e.counts=n},A=(e,n)=>{let r=e.counts.get(e.node)??0;if(r<t||i(e.node))return;let{path:a,names:o}=H(e.parent,e);O(`cycle:${V(o)}`,()=>{let t={kind:`cycle`,path:a,repeats:r,turns:1,root:e.root.name,source:`chain`};return n.traceGroupId!==void 0&&(t.traceGroupId=n.traceGroupId),t})},j=e=>{e.root.steps+=1,!(e.root.steps<=n||e.root.flagged)&&(e.root.flagged=!0,O(`runaway:${e.root.name}`,()=>({kind:`runaway`,path:[e.root.name],repeats:e.root.steps,turns:1,root:e.root.name,source:`chain`})))},M=e=>{if(!r||i(e))return;let t=a(),n=(p.get(e)??[]).filter(e=>t-e<r.perMs);n.push(t),p.set(e,n),n.length<r.count?m.delete(e):m.has(e)||(m.add(e),O(`storm:${e}:${t}`,()=>({kind:`storm`,path:[e],repeats:n.length,turns:1,root:e,source:`chain`})))},N=(e,t)=>{let n=_;return n!==void 0&&n.parent===e&&n.type===t},P=(e,t,n)=>({node:e.type,parent:t,counts:t?.counts??/* @__PURE__ */ new Map,root:t?.root??{name:e.type,steps:0,flagged:!1},inner:n}),F=()=>{g||(g=!0,queueMicrotask(()=>{h||o?.warn(`[nanoeffects] graphLogger got tasks but no emit event: add bus.use(tracePlugin()) for a finer graph.`)}))},I=(e,t,n,r)=>{k(t,e.type),(e.leaf===!0||r||!h)&&(T(e.type),n?E(n.node,e.type):M(e.type)),e.leaf||i(e.type)||(j(t),A(t,e))},B=e=>{let t=e.parent?d.get(e.parent):void 0;e.leaf?(h=!0,_={parent:t,type:e.type}):F();let n=e.emitted===!1,r=!e.leaf&&h&&!n&&!N(t,e.type),i=r&&!t,a=P(e,t,n||r&&!i);d.set(e.ref,a),a.inner||I(e,a,t,i)},U=(e,t)=>{let n=new Map(e.counts),r=e.node;n.set(r,Math.max(0,(n.get(r)??1)-1)),n.set(t.type,(n.get(t.type)??0)+1),e.counts=n,e.node=t.type,e.event=t.event,T(t.type),t.event!==void 0&&E(t.event,t.type),e.inner||A(e,t)},W=e=>{let t=d.get(e.ref);t?U(t,e):B(e)},G=e=>{if(e.phase!==`done`&&e.phase!==`error`)return;let t=s.get(e.type);t&&(t.last=e.phase===`error`?{payload:e.payload,error:e.error}:{payload:e.payload})},K=()=>{let t=J(),n=/* @__PURE__ */ new Set;for(let e of t)q(e,n);let r={nodes:[...s].map(([e,t])=>{let n=u(e);return n===void 0?{name:e,count:t.count}:{name:e,count:t.count,site:n}}),edges:[...c.values()].map(e=>({...e,inCycle:n.has(R(e.from,e.to))})),cycles:t};return e.name!==void 0&&(r.name=e.name),r},q=(e,t)=>{if(e.source===`chain`){for(let[n,r]of e.path.entries()){let i=e.path[n+1];i!==void 0&&t.add(R(r,i))}return}let n=new Set(e.path);for(let e of c.values())n.has(e.from)&&n.has(e.to)&&t.add(R(e.from,e.to))},J=()=>{let e=[...l.values()].filter(e=>e.kind===`cycle`),t=new Set(e.flatMap(e=>e.path)),n=[],r=[...c.values()].filter(e=>!(i(e.from)||i(e.to)));for(let e of f(r))e.every(e=>t.has(e))||n.push({kind:`cycle`,path:e,repeats:e.length,turns:0,root:e[0]??``,source:`graph`});return[...l.values(),...n.filter(t=>!e.some(e=>e.path.join()===t.path.join()))]};return Object.assign(G,{task:W,cycles:()=>J(),toMermaid:e=>v(K(),e),toDot:e=>y(K(),e),toJSON:(e={})=>{let t=K();if(!e.payload)return t;for(let e of t.nodes){let t=s.get(e.name)?.last;t&&(e.last={payload:L(t.payload),...t.error!==void 0&&{error:L(t.error)}})}return t},clear:()=>{s=/* @__PURE__ */ new Map,c=/* @__PURE__ */ new Map,l=/* @__PURE__ */ new Map,d=/* @__PURE__ */ new WeakMap,p=/* @__PURE__ */ new Map,m=/* @__PURE__ */ new Set,_=void 0}})},W=(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)}},G=e=>{if(e instanceof Error)return`${e.name}: ${e.message}`;let t=L(e);return typeof t==`string`?t:JSON.stringify(t)},K=(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:G(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 q;const J=()=>q,Y=(e,t)=>{let n=q;q=e;try{return t()}finally{q=n}},X=(e,t,n={})=>{let{trace:r}=e;if(!r){e.emit(t);return}let{traceId:a,traceGroupId:o}=n,{ctx:c,unlink:l}=i({event:{type:a??t.type,payload:t,...o===void 0?{}:{traceGroupId:o}},bus:{emit:e.emit,on:e.on,off:e.off,ctx:e.ctx,addContext:e.addContext},tracer:r});s(c,`run`,`start`);try{c.emit(t),s(c,`run`,`done`)}catch(e){throw s(c,`run`,`error`,e),e}finally{l()}},Z=e=>typeof e==`string`?e:Reflect.get(Object(e),`type`),Q=(e,t)=>typeof e==`object`?Reflect.get(Object(e),`payload`):t[0],$=()=>e=>{if(!(r&&e.trace))return e;let{trace:t}=e,i=(e,n)=>{let r=t.task({type:Z(e),payload:Q(e,n),leaf:!0},o());t.report(r,`emit`,`done`)},s=e.emit;e.emit=(e,...t)=>Y(e,()=>(i(e,t),s(e,...t))),Reflect.set(e,l,(t,n)=>{X(e,t,n)});let c=/* @__PURE__ */ new WeakMap,u=(e,t,n)=>{let r=c.get(t)??/* @__PURE__ */ new Map,i=Z(e);r.set(i,[...r.get(i)??[],n]),c.set(t,r)},d=(e,t)=>(c.get(t)?.get(Z(e)))?.pop(),f=(e,t)=>(r,i)=>(n(i,t),a(i,`run`,()=>e(r,i))),p=(e,t)=>(n,r,i)=>{let a=Reflect.get(Object(i),`traceId`);if(typeof a!=`string`)return e(n,r,i);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,i);return()=>{s()}},m=e.off,h=(e,t)=>{t===void 0?m(e):m(e,d(e,t)??t)},g=e.on,_=e.once;return e.on=p(g,!1),e.once=p(_,!0),e.off=h,e},ee=e=>{let t=e?.capacity??0,n=Number.isInteger(t)&&t>0?t:0,r=[],i=0,a=e=>{n===0?r.push(e):(r[i%n]=e,i+=1)},o=()=>{r.length=0,i=0},s=()=>{let e=Math.min(i,n),t=i>n?i%n:0,a=[];for(let i=0;i<e;i+=1){let e=r[(t+i)%n];e&&a.push(e)}return a},c=Object.assign(a,{clear:o,events:r,toJSON:()=>(n>0?s():r).map(e=>L(e))});return n>0&&Object.defineProperty(c,"events",{get:s}),c},te=()=>{},ne=/* @__PURE__ */ new Set([`cancel`,`drop`,`error`]),re=()=>!1,ie=()=>!0,ae=e=>{if(typeof e==`function`)return e;if(Array.isArray(e)){let t=new Set(e);return({phase:e})=>t.has(e)}return e?ie:re},oe=(e={})=>{let t=e.extension??globalThis.__REDUX_DEVTOOLS_EXTENSION__;if(!t)return te;let{starts:n=!1,depth:r=0,maxAge:i}=e,a=ae(e.policies),o=e.payload??`essential`,s=e.serialize===!1?e=>e:e.serialize??(e=>L(e)),c=t.connect({name:e.name??`nanoeffects`,...i!==void 0&&{maxAge:i}}),l=/* @__PURE__ */ new Map,u=/* @__PURE__ */ new Map,d=()=>({running:Object.fromEntries(l)});c.init(d());let f=(e,t,n)=>n===0?a({effect:e,phase:t}):n<=r,p=(e,t)=>{e.phase===`start`?(u.set(e.id,t),f(e.effect,`start`,t)&&l.set(e.id,{type:e.type,effect:e.effect,...e.traceGroupId!==void 0&&{traceGroupId:e.traceGroupId}})):(u.delete(e.id),l.delete(e.id))},m=!1,h=!1,g=(e,t)=>{m||h||t!==0||e===`start`||(h=!0,globalThis.console?.warn(`[nanoeffects] reduxDevtools got a task but no emit event: add bus.use(tracePlugin()) to see the emits.`))},_=e=>{let{payload:t,...n}=e;return o===`all`||o===`essential`&&(e.effect===`emit`||ne.has(e.phase))?{...n,payload:s(t)}:n},v=(e,t)=>{c.send({..._(e),type:`${e.type}/${e.effect}/${e.phase}`,event:e.type,...e.phase===`error`&&{error:t instanceof Error?t.message:s(t)}},d())};return({error:e,...t})=>{if(t.effect===`emit`){m=!0,c.send({..._(t),event:t.type},d());return}let r=(t.parentId===void 0?-1:u.get(t.parentId)??-1)+1;p(t,r),g(t.phase,r),(t.phase===`error`&&r===0||f(t.effect,t.phase,r))&&(t.phase!==`start`||n)&&v(t,e)}},se=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)}}},ce=()=>{},le=e=>{if(typeof e.traceGroupId==`string`)return e.traceGroupId;let t=J();if(typeof t!=`object`&&typeof t!=`function`||t===null)return;let n=Reflect.get(t,d),r=typeof n==`object`&&n?Reflect.get(n,`traceGroupId`):void 0;return typeof r==`string`?r:void 0},ue=(n,r={})=>{let i=n,a=se(i),{filter:s,sample:l=1}=r,u=0,d=(Array.isArray(i)?i:[i]).flatMap(e=>e.task?[e.task]:[]),f=t=>{let n={ref:t,id:t.id,type:t.type};t.parentRef&&(n.parent=t.parentRef),t.event!==void 0&&(n.event=t.event),t.leaf&&(n.leaf=!0),n.emitted=t.emitted,t.group!==void 0&&(n.traceGroupId=t.group);for(let t of d)try{t(n)}catch(t){e(`trace logger failed`,t)}},p=e=>typeof l==`function`?l({type:e.type,payload:e.payload}):Math.random()<l,m={task:(e,t)=>{let n={id:++u,root:t?.root??u,parent:t?.id,parentRef:d.length>0?t:void 0,leaf:e.leaf,emitted:o()===t,type:e.type,payload:e.payload,sampled:t?.sampled??p(e),group:le(e)??t?.group};return d.length>0&&n.sampled&&f(n),n},rename:(e,t)=>{e.event??=e.type,e.type=t,d.length>0&&e.sampled&&f(e)},report:(e,t,n,r)=>{if(!e.sampled)return;let i={id:e.id,type:e.type,effect:t,phase:n,payload:e.payload};typeof e.parent==`number`&&(i.parentId=e.parent),e.root!==e.id&&(i.rootId=e.root),e.group!==void 0&&(i.traceGroupId=e.group),n===`error`&&(i.error=r),(!s||s(i))&&a?.(i)},settler:(e,t)=>{if(!e.sampled)return ce;let n=!1;return(r,i)=>{n||(n=!0,m.report(e,t,r,i))}},run:(e,n,r,i)=>{if(!e.sampled)return i();let a=m.settler(e,n);m.report(e,n,`start`),t({signal:r},()=>a(`cancel`));let o;try{o=i()}catch(e){throw a(`error`,e),e}return c(o)?Promise.resolve(o).then(e=>(a(`done`),e),e=>{throw a(`error`,e),e}):(a(`done`),o)}};return m};export{W as consoleLogger,ee as createTraceRecorder,ue as createTracer,U as graphLogger,K as performanceLogger,oe as reduxDevtools,L as safeSerialize,$ as tracePlugin};
1
+ import{n as e}from"./site-DLvUoXs3.js";import{n as t,r as n,t as r}from"./tracer-v7m-Qah_.js";const i=e=>{let t=/* @__PURE__ */ new Map;for(let{from:n,to:r}of e){let e=t.get(n)??[];e.push(r),t.set(n,e),t.has(r)||t.set(r,[])}let n=/* @__PURE__ */ new Map,r=/* @__PURE__ */ new Map,i=/* @__PURE__ */ new Set,a=[],o=[],s=0,c=(e,t)=>{n.set(e,s),r.set(e,s),s+=1,a.push(e),i.add(e),t.push({name:e,next:0})},l=e=>{let n=[],r;do{if(r=a.pop(),r===void 0)break;i.delete(r),n.push(r)}while(r!==e);let[s]=n,c=n.length===1&&s!==void 0&&t.get(s)?.includes(s);(n.length>1||c)&&o.push(n.reverse())},u=(e,t)=>{r.set(e,Math.min(r.get(e)??t,t))},d=(e,r)=>{let a=t.get(r.name)?.[r.next];return a!==void 0&&(r.next+=1,n.has(a)?i.has(a)&&u(r.name,n.get(a)??0):c(a,e),!0)},f=(e,t)=>{e.pop();let i=e.at(-1);i&&u(i.name,r.get(t.name)??0),r.get(t.name)===n.get(t.name)&&l(t.name)},p=e=>{let t=[];c(e,t);for(let e=t.at(-1);e;e=t.at(-1))d(t,e)||f(t,e)};for(let e of t.keys())n.has(e)||p(e);return o},a=(e,t)=>{if(t===`prefix`){let t=e.indexOf(`/`);return t>0?e.slice(0,t):void 0}return t?.(e)},o=e=>e.replaceAll(`"`,`#quot;`).replaceAll(`<`,`#lt;`).replaceAll(`>`,`#gt;`).replaceAll(/\r?\n/g,` `),s=e=>e.replaceAll(`\\`,`\\\\`).replaceAll(`"`,`\\"`).replaceAll(/\r?\n/g,`\\n`),c=e=>new Map(e.nodes.map((e,t)=>[e.name,`n${t}`])),l=(e,t)=>{let n=/* @__PURE__ */ new Map;for(let{name:r}of e.nodes){let e=a(r,t);e!==void 0&&n.set(e,[...n.get(e)??[],r])}return n},u=(e,t={})=>{let n=c(e),r=[`flowchart LR`],i=/* @__PURE__ */ new Set;for(let[a,s]of l(e,t.group)){r.push(` subgraph g_${r.length}["${o(a)}"]`);for(let e of s)i.add(e),r.push(` ${n.get(e)}["${o(e)}"]`);r.push(` end`)}for(let{name:t}of e.nodes)i.has(t)||r.push(` ${n.get(t)}["${o(t)}"]`);let a=[];for(let[t,i]of e.edges.entries())r.push(` ${n.get(i.from)} -->|x${i.count}| ${n.get(i.to)}`),i.inCycle&&a.push(t);return a.length>0&&r.push(` linkStyle ${a.join(`,`)} stroke:red,stroke-width:2px`),r.join(`
2
+ `)},d=(e,t={})=>{let n=c(e),r=[`digraph events {`];e.name!==void 0&&r.push(` label="${s(e.name)}";`);let i=/* @__PURE__ */ new Set;for(let[a,o]of l(e,t.group)){r.push(` subgraph "cluster_${s(a)}" {`,` label="${s(a)}";`);for(let e of o)i.add(e),r.push(` ${n.get(e)} [label="${s(e)}"];`);r.push(` }`)}for(let{name:t}of e.nodes)i.has(t)||r.push(` ${n.get(t)} [label="${s(t)}"];`);for(let t of e.edges){let e=t.inCycle?`, color=red, penwidth=2`:``;r.push(` ${n.get(t.from)} -> ${n.get(t.to)} [label="x${t.count}"${e}];`)}return r.push(`}`),r.join(`
3
+ `)},f=e=>e.kind===`storm`?"an emit from a component or a timer repeats: stop it with `equals` of useEmitter, debounce, or a guard":e.kind===`runaway`?`one chain started a huge number of tasks: look for event names that are made from a counter or an id`:e.path.length<=2?`a handler emits its own event: emit a different event for the result`:`handlers feed each other: break the loop with a condition, or emit a different event for the result`,p=(t,n)=>{let r=n===void 0?`[nanoeffects]`:`[nanoeffects ${n}]`,i=t.traceGroupId===void 0?``:` (flow ${t.traceGroupId})`,a=t.kind===`cycle`?`cycle: ${t.path.join(` → `)} (repeated ${t.repeats} times, started at ${t.root})`:`${t.kind}: ${t.path.join(` → `)} (${t.repeats} in a row, started at ${t.root})`,o=[...new Set(t.path)].flatMap(t=>{let n=e(t);return n===void 0?[]:[`${t} at ${n}`]});return`${r} ${a}${i}${o.length>0?`\n ${o.join(`; `)}`:``}\n ${f(t)}`},m=(e,t)=>{if(!e)return;let n=e.connect({name:t});n.init({findings:0});let r=0;return e=>{r+=1,n.send({type:`cycle/detected`,kind:e.kind,path:e.path,repeats:e.repeats,root:e.root},{findings:r})}},h=2e3,g=e=>{let t=Object.getPrototypeOf(e),n=t===null?void 0:Reflect.get(t,`constructor`),r=typeof n==`function`?n.name:``;return typeof r==`string`&&r!==``?r:`Object`},_=e=>{let t=Object.getPrototypeOf(e);return t===null||t===Object.prototype},v=e=>typeof Reflect.get(e,`nodeType`)==`number`&&typeof Reflect.get(e,`nodeName`)==`string`,y=e=>e.length>h?`${e.slice(0,h)}…`:e,b=e=>{switch(typeof e){case`string`:return y(e);case`boolean`:return e;case`number`:return Number.isFinite(e)?e:String(e);case`bigint`:return`${e}n`;case`symbol`:return String(e);case`function`:return`[Function ${e.name||`anonymous`}]`;default:return e===null?null:void 0}},x=e=>{if(e instanceof WeakMap)return`[WeakMap]`;if(e instanceof WeakSet)return`[WeakSet]`;if(e instanceof Promise)return`[Promise]`;if(v(e))return`[DOM ${String(Reflect.get(e,`nodeName`))}]`;if(e instanceof Date)return Number.isNaN(e.getTime())?`[Invalid Date]`:e.toISOString()},S=(e,t,n)=>{if(t.budget<=0)return`[Cut]`;--t.budget;let r=b(e);return r===void 0?typeof e!=`object`||!e?`[undefined]`:C(e,t,n):r},C=(e,t,n)=>{try{let r=x(e);return r===void 0?t.path.has(e)?`[Circular]`:n>=t.maxDepth?Array.isArray(e)?`[Array]`:`[${g(e)}]`:w(e,t,n):r}catch{return`[Unserializable]`}},w=(e,t,n)=>{t.path.add(e);try{return T(e,t,n)}finally{t.path.delete(e)}},T=(e,t,n)=>e instanceof Error?E(e,t,n):Array.isArray(e)?D(e,t,n):e instanceof Map?{$map:D([...e.entries()],t,n)}:e instanceof Set?{$set:D([...e.values()],t,n)}:ArrayBuffer.isView(e)?{$class:g(e),length:Number(Reflect.get(e,`length`))}:O(e,t,n,_(e)?void 0:g(e)),E=(e,t,n)=>{let r={name:y(e.name),message:y(e.message)};return typeof e.stack==`string`&&(r.stack=y(e.stack)),`cause`in e&&(r.cause=S(e.cause,t,n+1)),r},D=(e,t,n)=>{let r=[];for(let[i,a]of e.entries()){if(t.budget<=0){r.push(`[${e.length-i} more]`);break}r.push(S(a,t,n+1))}return r},O=(e,t,n,r)=>{let i={};r!==void 0&&(i.$class=r);for(let r of Object.keys(e)){let a=Object.getOwnPropertyDescriptor(e,r);a&&(i[r]=`value`in a?S(a.value,t,n+1):`[Getter]`)}return i},k=(e,t={})=>{let n={maxDepth:t.maxDepth??6,budget:t.maxSize??1e3,path:/* @__PURE__ */ new Set};try{return S(e,n,0)}catch{return`[Unserializable]`}},A=(e,t)=>`${e}\u0000${t}`,j=e=>{if(typeof e==`function`)return e;let t=new Set(e);return e=>t.has(e)},M=e=>e.event===void 0?[e.node]:[e.event,e.node],N=e=>{let t=e.slice(0,-1),n=t.reduce((e,n,r)=>n<(t[e]??n)?r:e,0);return[...t.slice(n),...t.slice(0,n)].join(`\0`)},P=(e,t)=>{let{node:n}=t,r=[],i=e;for(;i&&i.node!==n;)r.push(i),i=i.parent;let a=r.reverse();return{path:[n,...a.flatMap(M),...M(t)],names:[n,...a.map(e=>e.node),n]}},F=(t={})=>{let n=t.repeats??3,r=t.maxSteps??5e3,a=t.storm===!1?void 0:t.storm??{count:100,perMs:1e3},o=j(t.ignore),s=t.now??(()=>globalThis.performance.now()),c=t.console??globalThis.console,l=/* @__PURE__ */ new Map,f=/* @__PURE__ */ new Map,h=/* @__PURE__ */ new Map,g=/* @__PURE__ */ new WeakMap,_=/* @__PURE__ */ new Map,v=/* @__PURE__ */ new Set,y=!1,b=!1,x,S,C=!1,w=!1,T=e=>{let t=l.get(e)??{count:0};t.count+=1,l.set(e,t)},E=(e,t)=>{let n=A(e,t),r=f.get(n)??{from:e,to:t,count:0,inCycle:!1};r.count+=1,f.set(n,r)},D=e=>{if(t.devtools&&!C){C=!0;let e=t.extension??globalThis.__REDUX_DEVTOOLS_EXTENSION__;S=m(e,t.name??`nanoeffects graph`)}S?.(e),t.onCycle?t.onCycle(e):c?.warn(p(e,t.name))},O=(e,t)=>{let n=h.get(e);if(n){n.turns+=1;return}let r=t();if(h.set(e,r),!w){w=!0;try{D(r)}catch(e){globalThis.console?.error(`[nanoeffects] graph logger report failed`,e)}finally{w=!1}}},M=(e,t)=>{let n=new Map(e.counts);n.set(t,(n.get(t)??0)+1),e.counts=n},F=(e,t)=>{let r=e.counts.get(e.node)??0;if(r<n||o(e.node))return;let{path:i,names:a}=P(e.parent,e);O(`cycle:${N(a)}`,()=>{let n={kind:`cycle`,path:i,repeats:r,turns:1,root:e.root.name,source:`chain`};return t.traceGroupId!==void 0&&(n.traceGroupId=t.traceGroupId),n})},I=e=>{e.root.steps+=1,!(e.root.steps<=r||e.root.flagged)&&(e.root.flagged=!0,O(`runaway:${e.root.name}`,()=>({kind:`runaway`,path:[e.root.name],repeats:e.root.steps,turns:1,root:e.root.name,source:`chain`})))},L=e=>{if(!a||o(e))return;let t=s(),n=(_.get(e)??[]).filter(e=>t-e<a.perMs);n.push(t),_.set(e,n),n.length<a.count?v.delete(e):v.has(e)||(v.add(e),O(`storm:${e}:${t}`,()=>({kind:`storm`,path:[e],repeats:n.length,turns:1,root:e,source:`chain`})))},R=(e,t)=>{let n=x;return n!==void 0&&n.parent===e&&n.type===t},z=(e,t,n)=>({node:e.type,parent:t,counts:t?.counts??/* @__PURE__ */ new Map,root:t?.root??{name:e.type,steps:0,flagged:!1},inner:n}),B=()=>{b||(b=!0,queueMicrotask(()=>{y||c?.warn(`[nanoeffects] graphLogger got tasks but no emit event: add bus.use(tracePlugin()) for a finer graph.`)}))},V=(e,t,n,r)=>{M(t,e.type),(e.leaf===!0||r||!y)&&(T(e.type),n?E(n.node,e.type):L(e.type)),e.leaf||o(e.type)||(I(t),F(t,e))},H=e=>{let t=e.parent?g.get(e.parent):void 0;e.leaf?(y=!0,x={parent:t,type:e.type}):B();let n=e.emitted===!1,r=!e.leaf&&y&&!n&&!R(t,e.type),i=r&&!t,a=z(e,t,n||r&&!i);g.set(e.ref,a),a.inner||V(e,a,t,i)},U=(e,t)=>{let n=new Map(e.counts),r=e.node;n.set(r,Math.max(0,(n.get(r)??1)-1)),n.set(t.type,(n.get(t.type)??0)+1),e.counts=n,e.node=t.type,e.event=t.event,T(t.type),t.event!==void 0&&E(t.event,t.type),e.inner||F(e,t)},W=e=>{let t=g.get(e.ref);t?U(t,e):H(e)},G=e=>{if(e.phase!==`done`&&e.phase!==`error`)return;let t=l.get(e.type);t&&(t.last=e.phase===`error`?{payload:e.payload,error:e.error}:{payload:e.payload})},K=()=>{let n=J(),r=/* @__PURE__ */ new Set;for(let e of n)q(e,r);let i={nodes:[...l].map(([t,n])=>{let r=e(t);return r===void 0?{name:t,count:n.count}:{name:t,count:n.count,site:r}}),edges:[...f.values()].map(e=>({...e,inCycle:r.has(A(e.from,e.to))})),cycles:n};return t.name!==void 0&&(i.name=t.name),i},q=(e,t)=>{if(e.source===`chain`){for(let[n,r]of e.path.entries()){let i=e.path[n+1];i!==void 0&&t.add(A(r,i))}return}let n=new Set(e.path);for(let e of f.values())n.has(e.from)&&n.has(e.to)&&t.add(A(e.from,e.to))},J=()=>{let e=[...h.values()].filter(e=>e.kind===`cycle`),t=new Set(e.flatMap(e=>e.path)),n=[],r=[...f.values()].filter(e=>!(o(e.from)||o(e.to)));for(let e of i(r))e.every(e=>t.has(e))||n.push({kind:`cycle`,path:e,repeats:e.length,turns:0,root:e[0]??``,source:`graph`});return[...h.values(),...n.filter(t=>!e.some(e=>e.path.join()===t.path.join()))]};return Object.assign(G,{task:W,cycles:()=>J(),toMermaid:e=>u(K(),e),toDot:e=>d(K(),e),toJSON:(e={})=>{let t=K();if(!e.payload)return t;for(let e of t.nodes){let t=l.get(e.name)?.last;t&&(e.last={payload:k(t.payload),...t.error!==void 0&&{error:k(t.error)}})}return t},clear:()=>{l=/* @__PURE__ */ new Map,f=/* @__PURE__ */ new Map,h=/* @__PURE__ */ new Map,g=/* @__PURE__ */ new WeakMap,_=/* @__PURE__ */ new Map,v=/* @__PURE__ */ new Set,x=void 0}})},I=(e,t)=>`${e}\u0000${t}`,L=e=>{let t=e.slice(0,-1),n=t.reduce((e,n,r)=>n<(t[e]??n)?r:e,0);return[...t.slice(n),...t.slice(0,n)]},R=e=>{let t=e.kind===`cycle`?L(e.path):[e.root];return[e.kind,e.source,e.traceGroupId??``,...t].join(`\0`)},z=(e,t)=>{let n={name:t.name,count:t.count},r=t.site??e?.site;e&&(n.count+=e.count),r!==void 0&&(n.site=e?.site??r);let i=t.last??e?.last;return i!==void 0&&(n.last=i),n},B=(...e)=>{let t=/* @__PURE__ */ new Map,n=/* @__PURE__ */ new Map,r=/* @__PURE__ */ new Map,i;for(let a of e){i??=a.name;for(let e of a.nodes)t.set(e.name,z(t.get(e.name),e));for(let e of a.edges){let t=I(e.from,e.to),r=n.get(t);n.set(t,{from:e.from,to:e.to,count:e.count+(r?.count??0),inCycle:e.inCycle||(r?.inCycle??!1)})}for(let e of a.cycles){let t=R(e),n=r.get(t);r.set(t,{...e,path:[...e.path],turns:e.turns+(n?.turns??0),repeats:Math.max(e.repeats,n?.repeats??0)})}}let a={nodes:[...t.values()],edges:[...n.values()],cycles:[...r.values()]};return i!==void 0&&(a.name=i),a},V=/ \([^()]*:\d+:\d+\)$/,H=(e,t)=>{let n=new Set(t.nodes.map(e=>e.name)),r=[];for(let[t,i]of Object.entries(e)){let e=n.has(t);for(let a of i){let i=a.replace(V,``);i===`<anonymous>`||n.has(i)||r.push({event:t,listener:i,kind:e?`unrun`:`unemitted`})}}return r},U=e=>`events`in e?e.events:e,W=e=>`tasks`in e?e.tasks:/* @__PURE__ */ new Map,G=(e,t)=>{let n=/* @__PURE__ */ new Map;for(let t of U(e))n.set(t.id,t);let r=W(e),i=[],a=/* @__PURE__ */ new Set,o=t;for(;o!==void 0&&!a.has(o);){a.add(o);let e=n.get(o),t=r.get(o),s=K(o,e,t);if(!s)break;i.push(s),o=e?.parentId??t?.parentId}return i.reverse()},K=(e,t,n)=>{let r=t??{},i=n??{},a=r.type??i.type;if(a===void 0)return;let o=r.source??i.source,s=r.traceGroupId??i.traceGroupId;return{id:e,type:a,...t?{effect:t.effect,phase:t.phase}:{},...o===void 0?{}:{source:o},...s===void 0?{}:{traceGroupId:s}}},q=e=>{let t=/* @__PURE__ */ new Map,n=/* @__PURE__ */ new WeakMap;return{task:({ref:r,parent:i,id:a,type:o,source:s,traceGroupId:c})=>{n.set(r,a);let l=i===void 0?void 0:n.get(i),u={type:o,...l===void 0?{}:{parentId:l},...s===void 0?{}:{source:s},...c===void 0?{}:{traceGroupId:c}};if(t.set(a,u),e>0&&t.size>e){let e=t.keys().next().value;e!==void 0&&t.delete(e)}},tasks:t,clear:()=>t.clear()}},J=(e={})=>{let t=e.console??globalThis.console,n=e.prefix??`[nanoeffects]`,r=e.source===!0,i=e=>r&&e!==void 0?` (${e})`:``,a=/* @__PURE__ */ new Map,o=e.chain===!0?q(1e3):void 0,s=(e,t)=>{if(!o||t!==`error`)return``;let n=[],r=/* @__PURE__ */ new Set,i=e;for(;i!==void 0&&!r.has(i);){r.add(i);let e=o.tasks.get(i);if(!e)break;n.push(e.type),i=e.parentId}return n.length>1?` (${n.reverse().join(` → `)})`:``},c=({id:e,parentId:r,type:o,effect:c,phase:l,payload:u,error:d,traceGroupId:f,source:p})=>{a.has(e)||a.set(e,typeof r==`number`?(a.get(r)??0)+1:0);let m=` `.repeat(a.get(e)??0);l!==`start`&&a.delete(e);let h=f===void 0?``:` [${f}]`,g=i(p),_=s(e,l),v=`${n}${h} ${m}${o} · ${c} ${l}${g}${_}`;l===`error`?t?.error(v,d):t?.debug(v,u)};return o&&(c.task=o.task),c},Y=(e,t={})=>{let r=t.source===!0,i=e=>{let t=e.name??`<anonymous>`;return r&&e.source!==void 0?`${t} (${e.source})`:t},a={};for(let[t,r]of n(e)??[])typeof t==`string`&&(a[t]=r.map(i));return a},X=e=>{if(e instanceof Error)return`${e.name}: ${e.message}`;let t=k(e);return typeof t==`string`?t:JSON.stringify(t)},Z=(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:X(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})}},Q=e=>{let t=e?.capacity??0,n=Number.isInteger(t)&&t>0?t:0,r=[],i=q(n),a=0,o=e=>{n===0?r.push(e):(r[a%n]=e,a+=1)},s=()=>{r.length=0,a=0,i.clear()},c=()=>{let e=Math.min(a,n),t=a>n?a%n:0,i=[];for(let a=0;a<e;a+=1){let e=r[(t+a)%n];e&&i.push(e)}return i},l=Object.assign(o,{clear:s,events:r,tasks:i.tasks,task:i.task,toJSON:()=>(n>0?c():r).map(e=>k(e))});return n>0&&Object.defineProperty(l,"events",{get:c}),l},$=()=>{},ee=/* @__PURE__ */ new Set([`cancel`,`drop`,`error`]),te=()=>!1,ne=()=>!0,re=e=>{if(typeof e==`function`)return e;if(Array.isArray(e)){let t=new Set(e);return({phase:e})=>t.has(e)}return e?ne:te},ie=(e={})=>{let t=e.extension??globalThis.__REDUX_DEVTOOLS_EXTENSION__;if(!t)return $;let{starts:n=!1,depth:r=0,maxAge:i}=e,a=re(e.policies),o=e.payload??`essential`,s=e.serialize===!1?e=>e:e.serialize??(e=>k(e)),c=t.connect({name:e.name??`nanoeffects`,...i!==void 0&&{maxAge:i}}),l=/* @__PURE__ */ new Map,u=/* @__PURE__ */ new Map,d=()=>({running:Object.fromEntries(l)});c.init(d());let f=(e,t,n)=>n===0?a({effect:e,phase:t}):n<=r,p=(e,t)=>{e.phase===`start`?(u.set(e.id,t),f(e.effect,`start`,t)&&l.set(e.id,{type:e.type,effect:e.effect,...e.traceGroupId!==void 0&&{traceGroupId:e.traceGroupId}})):(u.delete(e.id),l.delete(e.id))},m=!1,h=!1,g=(e,t)=>{m||h||t!==0||e===`start`||(h=!0,globalThis.console?.warn(`[nanoeffects] reduxDevtools got a task but no emit event: add bus.use(tracePlugin()) to see the emits.`))},_=e=>{let{payload:t,...n}=e;return o===`all`||o===`essential`&&(e.effect===`emit`||ee.has(e.phase))?{...n,payload:s(t)}:n},v=(e,t)=>{c.send({..._(e),type:`${e.type}/${e.effect}/${e.phase}`,event:e.type,...e.phase===`error`&&{error:t instanceof Error?t.message:s(t)}},d())};return({error:e,...t})=>{if(t.effect===`emit`){m=!0,c.send({..._(t),event:t.type},d());return}let r=(t.parentId===void 0?-1:u.get(t.parentId)??-1)+1;p(t,r),g(t.phase,r),(t.phase===`error`&&r===0||f(t.effect,t.phase,r))&&(t.phase!==`start`||n)&&v(t,e)}},ae=()=>typeof globalThis.performance?.now==`function`?globalThis.performance.now():Date.now(),oe=e=>({id:e.id,type:e.type,effect:e.effect,...e.parentId===void 0?{}:{parentId:e.parentId},...e.rootId===void 0?{}:{rootId:e.rootId},...e.source===void 0?{}:{source:e.source}}),se=(e={})=>{let t=e.now??ae,n=e.capacity??0,r=Number.isInteger(n)&&n>0?n:0,i=/* @__PURE__ */ new Map,a=[];return Object.assign(e=>{let n=`${e.id}:${e.effect}`,o=t();if(e.phase===`start`){i.set(n,{...oe(e),startedAt:o});return}let s=i.get(n);if(!s)return;i.delete(n);let{startedAt:c,...l}=s;a.push({...l,phase:e.phase,ms:o-c}),r>0&&a.length>r&&a.shift()},{durations:a,pending:()=>{let e=t();return[...i.values()].map(({startedAt:t,...n})=>({...n,ms:e-t}))},clear:()=>{i.clear(),a.length=0}})};export{G as chainOf,J as consoleLogger,Q as createTraceRecorder,r as createTracer,Y as describeBus,H as findOrphans,F as graphLogger,B as mergeGraphs,Z as performanceLogger,ie as reduxDevtools,k as safeSerialize,se as timingLogger,t as tracePlugin};
@@ -0,0 +1,2 @@
1
+ import{i as e,n as t,r as n}from"./caller-DULg_ZYV.js";import{n as r,t as i}from"./onAbort-BgMfspK4.js";import{a,c as o,n as s,o as c,r as l,s as u}from"./context-Dp_QRXzb.js";import{n as d}from"./promise-CSLpzwSR.js";import{t as f}from"./origin-key-BbWN3gmN.js";import{t as p}from"./scope-key-B7l7mUS5.js";const m=/* @__PURE__ */ new WeakMap,h=e=>{let t=m.get(e);if(t)return t;let n=/* @__PURE__ */ new Map;return m.set(e,n),n},g=e=>m.get(e),_=(e,t,n)=>{let r=e.get(t)??[];r.push(n),e.set(t,r)},v=(e,t,n)=>{let r=e.get(t),i=r?.indexOf(n)??-1;!r||i<0||(r.splice(i,1),r.length===0&&e.delete(t))},y=(e,t,n)=>(e.get(t)??[]).findLast(e=>e.handler===n);let b;const x=()=>b,S=(e,t)=>{let n=b;b=e;try{return t()}finally{b=n}},C=(e,t,n={})=>{let{trace:r}=e;if(!r){e.emit(t);return}let{traceId:i,traceGroupId:a}=n,{ctx:o,unlink:c}=s({event:{type:i??t.type,payload:t,...a===void 0?{}:{traceGroupId:a}},bus:{emit:e.emit,on:e.on,off:e.off,ctx:e.ctx,addContext:e.addContext},tracer:r});u(o,`run`,`start`);try{o.emit(t),u(o,`run`,`done`)}catch(e){throw u(o,`run`,`error`,e),e}finally{c()}},w=e=>/^(.+):(\d+):(\d+)$/.exec(e)?e:void 0,T=e=>{let t=e.slice(3).replace(/^async /,``),n=t.lastIndexOf(` (`),r=n<0?t:t.slice(n+2).replace(/\)$/,``);return w(r)},E=e=>w(e.slice(e.indexOf(`@`)+1)),D=e=>{if(typeof e!=`string`)return[];let t=[];for(let n of e.split(`
2
+ `)){let e=n.trim();e.startsWith(`at `)?t.push(T(e)):e.includes(`@`)&&t.push(E(e))}return t},O=(e,t)=>D(e)[t],k=e=>typeof e==`string`?e:Reflect.get(Object(e),`type`),A=(e,t)=>typeof e==`object`?Reflect.get(Object(e),`payload`):t[0],j=(r={})=>i=>{if(!(o&&i.trace))return i;let{trace:s}=i,u=(e,t)=>{let n=s.task({type:k(e),payload:A(e,t),leaf:!0},l());s.report(n,`emit`,`done`)},d=i.emit;i.emit=(e,...t)=>S(e,()=>(u(e,t),d(e,...t))),Reflect.set(i,f,(e,t)=>{C(i,e,t)});let p=h(i),m=(e,t,n)=>(r,i)=>(a(i,t,n),c(i,`run`,()=>e(r,i))),g=(e,t)=>{let n=Reflect.get(Object(t),`traceId`);return typeof n==`string`?n:e.name||void 0},b=r.source===!0;b&&n();let x=/* @__PURE__ */ new Map,w=(e,t,n)=>{let r=e.name;if(!r&&b&&typeof t==`string`){let e=(x.get(t)??0)+1;x.set(t,e),r=`${t}#${e}`}let i=r===void 0?e.handler:m(e.handler,r,e.source);return n?(n,r)=>(v(p,t,e),i(n,r)):i},T=(n,r)=>{let i=(e,i,a)=>{let o=k(e),s=b?O(t(),2):void 0,c={handler:i,wrapper:i,name:g(i,a),source:s};c.wrapper=w(c,o,r),_(p,o,c);let l=n(e,c.wrapper,a);return()=>{v(p,o,c),l()}};return(t,n,r)=>e(()=>i(t,n,r))},E=i.off,D=(e,t)=>{e===void 0?p.clear():t===void 0&&p.delete(k(e));let n=e!==void 0&&t&&y(p,k(e),t);n&&v(p,k(e),n),E(e,n?n.wrapper:t)},j=i.on,M=i.once;return i.on=T(j,!1),i.once=T(M,!0),i.off=D,i},M=e=>{let t=typeof e==`function`?[e]:[...e??[]];return t.length===0?null:e=>{for(let n of t)try{n(e)}catch(e){r(`trace logger failed`,e)}}},N=()=>{},P=e=>{if(typeof e.traceGroupId==`string`)return e.traceGroupId;let t=x();if(typeof t!=`object`&&typeof t!=`function`||t===null)return;let n=Reflect.get(t,p),r=typeof n==`object`&&n?Reflect.get(n,`traceGroupId`):void 0;return typeof r==`string`?r:void 0},F=(e,t={})=>{let n=e,a=M(n),{filter:o,sample:s=1}=t,c=0,u=(Array.isArray(n)?n:[n]).flatMap(e=>e.task?[e.task]:[]),f=e=>{let t={ref:e,id:e.id,type:e.type};e.parentRef&&(t.parent=e.parentRef),e.event!==void 0&&(t.event=e.event),e.leaf&&(t.leaf=!0),t.emitted=e.emitted,e.group!==void 0&&(t.traceGroupId=e.group),e.source!==void 0&&(t.source=e.source);for(let e of u)try{e(t)}catch(e){r(`trace logger failed`,e)}},p=e=>typeof s==`function`?s({type:e.type,payload:e.payload}):Math.random()<s,m={task:(e,t)=>{let n={id:++c,root:t?.root??c,parent:t?.id,parentRef:u.length>0?t:void 0,leaf:e.leaf,emitted:l()===t,type:e.type,payload:e.payload,sampled:t?.sampled??p(e),group:P(e)??t?.group};return u.length>0&&n.sampled&&f(n),n},rename:(e,t,n)=>{e.event??=e.type,e.type=t,n!==void 0&&(e.source=n),u.length>0&&e.sampled&&f(e)},report:(e,t,n,r)=>{if(!e.sampled)return;let i={id:e.id,type:e.type,effect:t,phase:n,payload:e.payload};typeof e.parent==`number`&&(i.parentId=e.parent),e.root!==e.id&&(i.rootId=e.root),e.group!==void 0&&(i.traceGroupId=e.group),e.source!==void 0&&(i.source=e.source),n===`error`&&(i.error=r),(!o||o(i))&&a?.(i)},settler:(e,t)=>{if(!e.sampled)return N;let n=!1;return(r,i)=>{n||(n=!0,m.report(e,t,r,i))}},run:(e,t,n,r)=>{if(!e.sampled)return r();let a=m.settler(e,t);m.report(e,t,`start`),i({signal:n},()=>a(`cancel`));let o;try{o=r()}catch(e){throw a(`error`,e),e}return d(o)?Promise.resolve(o).then(e=>(a(`done`),e),e=>{throw a(`error`,e),e}):(a(`done`),o)}};return m};export{j as n,g as r,F as t};
@@ -1,5 +1,5 @@
1
- import { H as EventMap, c as Scope, l as WithFields, p as Effects } from "./action-creator-6rlBTmH9.js";
2
- import { t as BoundOf } from "./plugin-BWNP23hr.js";
1
+ import { H as EventMap, c as Scope, l as WithFields, p as Effects } from "./action-creator-DprJV-pN.js";
2
+ import { t as BoundOf } from "./plugin-2d3uuW7o.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/dist/vue.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { H as EventMap, T as EventKey, a as FreeActionCreator, t as ActionCreator, v as Bus } from "./action-creator-6rlBTmH9.js";
1
+ import { H as EventMap, T as EventKey, a as FreeActionCreator, t as ActionCreator, v as Bus } from "./action-creator-DprJV-pN.js";
2
2
  import { t as OriginOptions } from "./origin-key-CxK0SkeG.js";
3
3
  import { t as StateOf } from "./state-of-C19H6BoV.js";
4
4
  import { ShallowRef, WatchSource, WatchStopHandle } from "vue";
@@ -1 +1 @@
1
- import{n as e}from"./context-B5Z2RpJt.js";const t=Reflect.get(Symbol,`dispose`),n=n=>{let r=new AbortController,i=async(...t)=>{let i=t[0],{ctx:a,unlink:o}=e({event:{type:`withPolicy`,payload:i},parent:{signal:r.signal}});try{return await n(i,a)}finally{o()}},a=e=>{r.abort(e),r=new AbortController},o=Object.assign(i,{cancel:a});return t&&Reflect.set(o,t,()=>a()),o};export{n as t};
1
+ import{n as e}from"./context-Dp_QRXzb.js";const t=Reflect.get(Symbol,`dispose`),n=n=>{let r=new AbortController,i=async(...t)=>{let i=t[0],{ctx:a,unlink:o}=e({event:{type:`withPolicy`,payload:i},parent:{signal:r.signal}});try{return await n(i,a)}finally{o()}},a=e=>{r.abort(e),r=new AbortController},o=Object.assign(i,{cancel:a});return t&&Reflect.set(o,t,()=>a()),o};export{n as t};
@@ -1,4 +1,4 @@
1
- import { G as PayloadOf, H as EventMap, q as Task } from "./action-creator-6rlBTmH9.js";
1
+ import { G as PayloadOf, H as EventMap, q as Task } from "./action-creator-DprJV-pN.js";
2
2
  //#region src/policies/with-policy.d.ts
3
3
  /** What `withPolicy` returns: the task as a plain function that can be cancelled. */
4
4
  type PolicyFunction<P, R> = {