nanoeffects 0.0.0-stage → 0.2.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 (56) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +96 -2
  3. package/dist/action-rqZEnRIp.d.ts +303 -0
  4. package/dist/actions.d.ts +58 -0
  5. package/dist/actions.js +1 -0
  6. package/dist/bus-CRnlwmQ4.js +1 -0
  7. package/dist/context-DlA80GOA.js +1 -0
  8. package/dist/delay-CIHnOh_L.js +1 -0
  9. package/dist/dev.d.ts +46 -0
  10. package/dist/dev.js +1 -0
  11. package/dist/effects.d.ts +284 -0
  12. package/dist/effects.js +1 -0
  13. package/dist/event-0RIBGYqS.js +1 -0
  14. package/dist/index.d.ts +2 -0
  15. package/dist/index.js +1 -0
  16. package/dist/module-BSCdR9D1.d.ts +167 -0
  17. package/dist/notrace/action-rqZEnRIp.d.ts +303 -0
  18. package/dist/notrace/actions.d.ts +222 -0
  19. package/dist/notrace/actions.js +1 -0
  20. package/dist/notrace/bus-Dx0l9X6h.js +1 -0
  21. package/dist/notrace/context-yAWj0BFZ.js +1 -0
  22. package/dist/notrace/delay-Cgvn16oY.js +1 -0
  23. package/dist/notrace/effects.d.ts +284 -0
  24. package/dist/notrace/effects.js +1 -0
  25. package/dist/notrace/event-0RIBGYqS.js +1 -0
  26. package/dist/notrace/index.d.ts +2 -0
  27. package/dist/notrace/index.js +1 -0
  28. package/dist/notrace/policies.d.ts +171 -0
  29. package/dist/notrace/policies.js +1 -0
  30. package/dist/notrace/promise-CSLpzwSR.js +1 -0
  31. package/dist/notrace/redux.d.ts +92 -0
  32. package/dist/notrace/redux.js +1 -0
  33. package/dist/observable.d.ts +20 -0
  34. package/dist/observable.js +1 -0
  35. package/dist/onAbort-BgMfspK4.js +1 -0
  36. package/dist/policies.d.ts +171 -0
  37. package/dist/policies.js +1 -0
  38. package/dist/production/dev.js +1 -0
  39. package/dist/promise-CSLpzwSR.js +1 -0
  40. package/dist/redux.d.ts +92 -0
  41. package/dist/redux.js +1 -0
  42. package/dist/trace.d.ts +162 -0
  43. package/dist/trace.js +1 -0
  44. package/docs/README.md +15 -0
  45. package/docs/actions.md +78 -0
  46. package/docs/context.md +15 -0
  47. package/docs/effects.md +137 -0
  48. package/docs/errors.md +23 -0
  49. package/docs/guide.md +229 -0
  50. package/docs/hmr.md +36 -0
  51. package/docs/observable.md +22 -0
  52. package/docs/policies.md +53 -0
  53. package/docs/semantics.md +7 -0
  54. package/docs/stores.md +50 -0
  55. package/docs/tracing.md +117 -0
  56. package/package.json +184 -5
@@ -0,0 +1,117 @@
1
+ # Tracing
2
+
3
+ ## Tracing
4
+
5
+ Pass `trace` to `createBus` to observe every task phase. Make it with `createTracer` from `nanoeffects/trace`, which takes a logger (a function) or an array of them. The tracing code lives in that entry, so a bus without `trace` does not carry it.
6
+
7
+ ```ts
8
+ import { createBus } from "nanoeffects";
9
+ import { createTracer } from "nanoeffects/trace";
10
+
11
+ const bus = createBus<Events>({
12
+ trace: createTracer((event) => console.log(event)),
13
+ });
14
+ ```
15
+
16
+ Each `TraceEvent` has:
17
+
18
+ | Field | Meaning |
19
+ | --------- | -------------------------------------------------------------------- |
20
+ | `id` | Unique task id within the bus. |
21
+ | `parent` | Id of the task that started this one (absent for handler tasks). |
22
+ | `type` | Event type the task works on. |
23
+ | `effect` | `latest`, `debounce`, `throttle`, `leading`, `run`, `all` or `race`. |
24
+ | `phase` | `start`, `done`, `error`, `cancel` or `drop`. |
25
+ | `payload` | Event payload. |
26
+ | `error` | Thrown value, only for `error`. |
27
+
28
+ Phases:
29
+
30
+ - `start`: the work began.
31
+ - `done` / `error`: it finished or threw.
32
+ - `cancel`: it was aborted after it started (superseded by `latest`, parent aborted, lost a `race`).
33
+ - `drop`: it never started (`leading` while busy, a `throttle` call replaced by a newer one, a `debounce` call replaced before its delay ended).
34
+
35
+ `all` and `race` are traced when you pass them the handler `ctx`: the group is one task, every starter is a child `run` task.
36
+
37
+ ```ts
38
+ bus.on("load", async (id, ctx) => {
39
+ await all(ctx, { user: () => fetchUser(id), posts: () => fetchPosts(id) });
40
+ });
41
+ ```
42
+
43
+ ## Loggers
44
+
45
+ A logger is a function `(event: TraceEvent) => void` (the `TraceLogger` type). `createTracer` takes one logger or an array; a logger that throws is reported to `console.error` and never breaks the task or the other loggers.
46
+
47
+ ```ts
48
+ import { createBus } from "nanoeffects";
49
+ import { consoleLogger, createTracer, reduxDevtools } from "nanoeffects/trace";
50
+
51
+ const bus = createBus<Events>({
52
+ trace: createTracer([reduxDevtools({ name: "app" }), consoleLogger()]),
53
+ });
54
+ ```
55
+
56
+ `nanoeffects/trace` ships `createTracer` and these loggers, each a factory that returns a `TraceLogger`:
57
+
58
+ | Logger | What it does |
59
+ | ----------------------- | ------------------------------------------------------------------------------------ |
60
+ | `reduxDevtools()` | Sends tasks to Redux DevTools as `type/effect/phase`; state is `{ running }`. |
61
+ | `consoleLogger()` | Prints one line per phase, indented by task depth. |
62
+ | `performanceLogger()` | Records User Timing measures for the Timings track of the browser Performance panel. |
63
+ | `createTraceRecorder()` | Keeps events in `recorder.events`, for tests. |
64
+
65
+ ### Production: filter and sampling
66
+
67
+ `createTracer(loggers, options)` can cut the volume:
68
+
69
+ ```ts
70
+ createTracer(logger, {
71
+ sample: 0.05, // trace 5% of the handler calls (a share, or a function of { type, payload })
72
+ filter: (event) => event.phase === "error", // and keep only failures
73
+ });
74
+ ```
75
+
76
+ - `sample` is decided once per root task (one handler call) and every task below it follows, so a trace is never cut in the middle. Tasks that are not sampled cost almost nothing: their effects run without tracing.
77
+ - `filter` runs on each event before any logger sees it.
78
+
79
+ Notes on `reduxDevtools`: it is read-only (the bus owns no state, so there is no time travel) and does nothing when the extension is not installed. It has its own instance in the DevTools picker, apart from your store.
80
+
81
+ It is quiet by default, so the log stays readable:
82
+
83
+ - **A task is one action**, sent when it ends (`done`, `error`, `cancel`, `drop`). The tasks that are running are in the state, `{ running }`. `starts: true` also sends every start.
84
+ - **Only the top is shown**: the handler tasks and the effects they start (`retry`, `timeout`, ...). The attempts and starters under them are hidden. `depth: 0` shows the handler tasks only, `depth: 3` more, `Infinity` everything.
85
+ - `maxAge: 200` sets how many actions DevTools keeps (its own default is 50).
86
+
87
+ ```ts
88
+ reduxDevtools({ name: "app", depth: 0 }); // one line per handler call
89
+ reduxDevtools({ name: "app", starts: true, depth: Infinity }); // everything, for a hunt for a bug
90
+ ```
91
+
92
+ For more control, `createTracer(logger, { filter, sample })` cuts events before any logger sees them.
93
+
94
+ To write your own, return a `TraceLogger`:
95
+
96
+ ```ts
97
+ import type { TraceLogger } from "nanoeffects";
98
+
99
+ const errorsOnly = (): TraceLogger => (event) => {
100
+ if (event.phase === "error") report(event.error);
101
+ };
102
+ ```
103
+
104
+ ## Removing tracing from a build
105
+
106
+ Without a tracer the hooks cost almost nothing (a lookup that finds no tracer), and `nanoeffects/trace` is a separate entry that is only bundled when imported. To also drop the tracing code from the core, use the `notrace` export condition: the package ships a second build of `index`, `effects`, `policies` and `actions` made with `__NANOEFFECTS_TRACE__` set to `false`, so the bundler removes the tracer calls.
107
+
108
+ ```ts
109
+ // vite / rolldown
110
+ resolve: { conditions: ["notrace"] }
111
+ // webpack
112
+ resolve: { conditionNames: ["notrace", "import", "..."] }
113
+ // esbuild
114
+ conditions: ["notrace"]
115
+ ```
116
+
117
+ In a build of your own from the sources, `define: { __NANOEFFECTS_TRACE__: "false" }` does the same. With the condition set, the types of that build have no `trace` option: `createBus({ trace })` is a type error, so tracing cannot be left on by mistake (`scripts/notrace-types.mjs` makes `BusOptions.trace` `never` there). `nanoeffects/trace` has no `notrace` build. The saving is about 0.4 kB gzip of the whole library.
package/package.json CHANGED
@@ -1,6 +1,185 @@
1
1
  {
2
- "name": "nanoeffects",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
2
+ "name": "nanoeffects",
3
+ "version": "0.2.0",
4
+ "description": "Typed event bus where every handler is a task with an AbortSignal, plus policies (latest, debounce, throttle, queue), effects (retry, timeout, poll) and tracing. About 1.2 kB gzip.",
5
+ "keywords": [
6
+ "event-bus",
7
+ "event-emitter",
8
+ "effects",
9
+ "abort-signal",
10
+ "abortcontroller",
11
+ "debounce",
12
+ "throttle",
13
+ "queue",
14
+ "retry",
15
+ "side-effects",
16
+ "typescript"
17
+ ],
18
+ "license": "MIT",
19
+ "author": "Vladimir Yazykov <neizerth@gmail.com>",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/nanoeffects/nanoeffects.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/nanoeffects/nanoeffects/issues"
26
+ },
27
+ "homepage": "https://github.com/nanoeffects/nanoeffects#readme",
28
+ "engines": {
29
+ "node": ">=18"
30
+ },
31
+ "type": "module",
32
+ "packageManager": "pnpm@11.13.0",
33
+ "sideEffects": false,
34
+ "files": [
35
+ "dist",
36
+ "README.md",
37
+ "LICENSE",
38
+ "docs"
39
+ ],
40
+ "module": "./dist/index.js",
41
+ "types": "./dist/index.d.ts",
42
+ "exports": {
43
+ ".": {
44
+ "notrace": {
45
+ "types": "./dist/notrace/index.d.ts",
46
+ "default": "./dist/notrace/index.js"
47
+ },
48
+ "types": "./dist/index.d.ts",
49
+ "import": "./dist/index.js"
50
+ },
51
+ "./effects": {
52
+ "notrace": {
53
+ "types": "./dist/notrace/effects.d.ts",
54
+ "default": "./dist/notrace/effects.js"
55
+ },
56
+ "types": "./dist/effects.d.ts",
57
+ "import": "./dist/effects.js"
58
+ },
59
+ "./policies": {
60
+ "notrace": {
61
+ "types": "./dist/notrace/policies.d.ts",
62
+ "default": "./dist/notrace/policies.js"
63
+ },
64
+ "types": "./dist/policies.d.ts",
65
+ "import": "./dist/policies.js"
66
+ },
67
+ "./actions": {
68
+ "notrace": {
69
+ "types": "./dist/notrace/actions.d.ts",
70
+ "default": "./dist/notrace/actions.js"
71
+ },
72
+ "types": "./dist/actions.d.ts",
73
+ "import": "./dist/actions.js"
74
+ },
75
+ "./trace": {
76
+ "types": "./dist/trace.d.ts",
77
+ "import": "./dist/trace.js"
78
+ },
79
+ "./redux": {
80
+ "notrace": {
81
+ "types": "./dist/notrace/redux.d.ts",
82
+ "default": "./dist/notrace/redux.js"
83
+ },
84
+ "types": "./dist/redux.d.ts",
85
+ "import": "./dist/redux.js"
86
+ },
87
+ "./observable": {
88
+ "types": "./dist/observable.d.ts",
89
+ "import": "./dist/observable.js"
90
+ },
91
+ "./dev": {
92
+ "production": {
93
+ "types": "./dist/dev.d.ts",
94
+ "default": "./dist/production/dev.js"
95
+ },
96
+ "types": "./dist/dev.d.ts",
97
+ "import": "./dist/dev.js"
98
+ }
99
+ },
100
+ "scripts": {
101
+ "build": "tsdown && node scripts/notrace-types.mjs",
102
+ "prepublishOnly": "pnpm build",
103
+ "check": "biome check ./src ./examples ./integration ./scripts",
104
+ "format": "npx @biomejs/biome check --write --unsafe ./src ./examples ./integration ./scripts",
105
+ "tsgo": "tsc --noEmit",
106
+ "test": "vitest run",
107
+ "test:watch": "vitest",
108
+ "prepare": "lefthook install",
109
+ "lint:package": "publint && attw --pack . --profile esm-only",
110
+ "size": "size-limit",
111
+ "verify": "pnpm tsgo && pnpm check && pnpm test && pnpm build && pnpm test:integration && pnpm smoke && pnpm lint:package && pnpm size",
112
+ "test:integration": "vitest run --config vitest.integration.config.ts",
113
+ "smoke": "node scripts/smoke.mjs && node scripts/smoke.mjs --notrace",
114
+ "consumer-check": "node scripts/consumer-check.mjs"
115
+ },
116
+ "devDependencies": {
117
+ "@arethetypeswrong/cli": "^0.18.5",
118
+ "@biomejs/biome": "2.5.15",
119
+ "@commitlint/cli": "21.2.3",
120
+ "@commitlint/config-conventional": "21.2.3",
121
+ "@reduxjs/toolkit": "^2.13.0",
122
+ "@size-limit/esbuild": "^14.2.0",
123
+ "@size-limit/file": "^14.2.0",
124
+ "jotai": "^3.0.1",
125
+ "lefthook": "2.2.1",
126
+ "lodash": "4.17.21",
127
+ "mobx": "^7.0.6",
128
+ "publint": "^0.3.25",
129
+ "redux": "^5.0.1",
130
+ "size-limit": "^14.2.0",
131
+ "tsdown": "0.23.1",
132
+ "typescript": "7.0.2",
133
+ "unplugin-unused": "^0.6.0",
134
+ "vite": "^8.3.4",
135
+ "vitest": "5.0.5",
136
+ "webpack": "^5.112.0",
137
+ "zustand": "^5.0.15"
138
+ },
139
+ "publishConfig": {
140
+ "access": "public"
141
+ },
142
+ "size-limit": [
143
+ {
144
+ "name": "createBus",
145
+ "path": "dist/index.js",
146
+ "import": "{ createBus }",
147
+ "limit": "1.2 kB"
148
+ },
149
+ {
150
+ "name": "policies (all)",
151
+ "path": "dist/policies.js",
152
+ "limit": "2.6 kB"
153
+ },
154
+ {
155
+ "name": "effects (all)",
156
+ "path": "dist/effects.js",
157
+ "limit": "2.3 kB"
158
+ },
159
+ {
160
+ "name": "actions (all)",
161
+ "path": "dist/actions.js",
162
+ "limit": "1.8 kB"
163
+ },
164
+ {
165
+ "name": "redux",
166
+ "path": "dist/redux.js",
167
+ "limit": "1.5 kB"
168
+ },
169
+ {
170
+ "name": "observable",
171
+ "path": "dist/observable.js",
172
+ "limit": "0.5 kB"
173
+ },
174
+ {
175
+ "name": "dev",
176
+ "path": "dist/dev.js",
177
+ "limit": "1 kB"
178
+ },
179
+ {
180
+ "name": "dev (production)",
181
+ "path": "dist/production/dev.js",
182
+ "limit": "100 B"
183
+ }
184
+ ]
185
+ }