@dudousxd/nestjs-diagnostics 0.8.1 → 0.9.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 (63) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +29 -0
  3. package/dist/channel.d.ts +1 -1
  4. package/dist/channel.d.ts.map +1 -1
  5. package/dist/channel.js +3 -1
  6. package/dist/channel.js.map +1 -1
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +2 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/nestjs/delivery.d.ts +92 -0
  12. package/dist/nestjs/delivery.d.ts.map +1 -0
  13. package/dist/nestjs/delivery.js +2 -0
  14. package/dist/nestjs/delivery.js.map +1 -0
  15. package/dist/nestjs/diagnostics.explorer.d.ts +51 -11
  16. package/dist/nestjs/diagnostics.explorer.d.ts.map +1 -1
  17. package/dist/nestjs/diagnostics.explorer.js +209 -53
  18. package/dist/nestjs/diagnostics.explorer.js.map +1 -1
  19. package/dist/nestjs/diagnostics.module.d.ts +9 -2
  20. package/dist/nestjs/diagnostics.module.d.ts.map +1 -1
  21. package/dist/nestjs/diagnostics.module.js +23 -3
  22. package/dist/nestjs/diagnostics.module.js.map +1 -1
  23. package/dist/nestjs/diagnostics.options.d.ts +31 -0
  24. package/dist/nestjs/diagnostics.options.d.ts.map +1 -0
  25. package/dist/nestjs/diagnostics.options.js +3 -0
  26. package/dist/nestjs/diagnostics.options.js.map +1 -0
  27. package/dist/nestjs/index.d.ts +6 -3
  28. package/dist/nestjs/index.d.ts.map +1 -1
  29. package/dist/nestjs/index.js +4 -2
  30. package/dist/nestjs/index.js.map +1 -1
  31. package/dist/nestjs/on-diagnostic.decorator.d.ts +33 -7
  32. package/dist/nestjs/on-diagnostic.decorator.d.ts.map +1 -1
  33. package/dist/nestjs/on-diagnostic.decorator.js +0 -9
  34. package/dist/nestjs/on-diagnostic.decorator.js.map +1 -1
  35. package/dist/nestjs/queue-transport.d.ts +47 -0
  36. package/dist/nestjs/queue-transport.d.ts.map +1 -0
  37. package/dist/nestjs/queue-transport.js +45 -0
  38. package/dist/nestjs/queue-transport.js.map +1 -0
  39. package/dist/nestjs/role.d.ts +13 -0
  40. package/dist/nestjs/role.d.ts.map +1 -0
  41. package/dist/nestjs/role.js +13 -0
  42. package/dist/nestjs/role.js.map +1 -0
  43. package/dist/nestjs/transports.d.ts +125 -0
  44. package/dist/nestjs/transports.d.ts.map +1 -0
  45. package/dist/nestjs/transports.js +127 -0
  46. package/dist/nestjs/transports.js.map +1 -0
  47. package/dist/redis-relay.d.ts +60 -0
  48. package/dist/redis-relay.d.ts.map +1 -0
  49. package/dist/redis-relay.js +170 -0
  50. package/dist/redis-relay.js.map +1 -0
  51. package/dist/relayed.d.ts +8 -0
  52. package/dist/relayed.d.ts.map +1 -0
  53. package/dist/relayed.js +31 -0
  54. package/dist/relayed.js.map +1 -0
  55. package/dist/trace.d.ts.map +1 -1
  56. package/dist/trace.js +2 -0
  57. package/dist/trace.js.map +1 -1
  58. package/dist/types.d.ts +9 -0
  59. package/dist/types.d.ts.map +1 -1
  60. package/package.json +14 -6
  61. package/skills/emit-diagnostics/SKILL.md +5 -2
  62. package/skills/react-with-on-diagnostic/SKILL.md +41 -13
  63. package/skills/trace-spans/SKILL.md +2 -1
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: react-with-on-diagnostic
3
- description: React to diagnostics events inside a NestJS app with @OnDiagnostic(lib, event?) from @dudousxd/nestjs-diagnostics/nestjs, wired by DiagnosticsModule.forRoot(). Decorate provider methods to handle one exact aviary:<lib>:<event> channel or every aviary:<lib>:* channel (current and future). Handlers run on the DI-resolved instance; sync throws and async rejections are logged and swallowed so a reaction can never break the synchronous emit() that triggered it.
3
+ description: React to diagnostics events inside a NestJS app with @OnDiagnostic(lib, event?) from @dudousxd/nestjs-diagnostics/nestjs, wired by DiagnosticsModule.forRoot()/forRootAsync({ default, transports, role, nodeId }). Decorate provider methods to handle one exact aviary:<lib>:<event> channel, a RegExp match, or every aviary:<lib>:* channel (current and future). The handler parameter is checked against the ChannelRegistry payload for registered channels; each listener has a stable <ClassName>#<method> id. Handlers run on the DI-resolved instance; without a delivering transport sync throws and async rejections are logged and swallowed, while queue/durable transports propagate the handler error for retry with delivery once from the emitting process. role 'api' never consumes or runs listeners.
4
4
  license: MIT
5
5
  metadata:
6
6
  type: core
@@ -44,21 +44,37 @@ export class Reactions {
44
44
  @OnDiagnostic('resilience', 'circuit-opened') // one exact channel
45
45
  onCircuitOpen(e: DiagnosticEvent) { /* … */ }
46
46
 
47
+ @OnDiagnostic('durable', /^run\./) // every event of the lib whose name matches
48
+ onRun(e: DiagnosticEvent) { /* … */ }
49
+
47
50
  @OnDiagnostic('resilience') // every aviary:resilience:* channel
48
51
  onAnyResilience(e: DiagnosticEvent) { /* … */ }
49
52
  }
50
53
  ```
51
54
 
55
+ For a channel declared in the `ChannelRegistry`, the handler's parameter is
56
+ checked against the declared payload (see `DiagnosticEventOf`); untyped
57
+ channels accept any annotation. Each listener has a stable id,
58
+ `<ClassName>#<method>`; two listener classes with the same name fail the
59
+ bootstrap. To run listeners across processes, pass
60
+ `{ default, transports, role, nodeId }` to `forRoot()` (or `forRootAsync()`):
61
+ `transports.redis()`, `transports.queue()`, or `transports.durable()` select
62
+ the delivery, and `role: 'api'` emits and hands work to the transport but
63
+ never consumes or runs listeners (`'api'`/`'worker'` without a `default`
64
+ transport fail the bootstrap).
65
+
52
66
  Source: `packages/core/src/nestjs/diagnostics.module.ts`,
53
67
  `packages/core/src/nestjs/on-diagnostic.decorator.ts`,
54
68
  `packages/core/src/nestjs/diagnostics.explorer.ts`.
55
69
 
56
70
  ## Core patterns
57
71
 
58
- ### 1. Exact channel vs library wildcard
72
+ ### 1. Exact channel, RegExp match, or library wildcard
59
73
 
60
74
  - `@OnDiagnostic('resilience', 'circuit-opened')` subscribes to the exact
61
75
  `aviary:resilience:circuit-opened` channel.
76
+ - `@OnDiagnostic('durable', /^run\./)` subscribes to every
77
+ `aviary:durable:*` channel whose event name matches the `RegExp`.
62
78
  - `@OnDiagnostic('resilience')` (no `event`) subscribes to **every**
63
79
  `aviary:resilience:*` channel — both those already registered at bootstrap and
64
80
  any that appear later (a library's first `emit('resilience', 'newevent', …)`).
@@ -69,6 +85,12 @@ automatically.
69
85
 
70
86
  Source: `packages/core/src/nestjs/diagnostics.explorer.ts` (`onApplicationBootstrap`).
71
87
 
88
+ Each discovered method gets a stable listener id, `<ClassName>#<method>`,
89
+ which delivering transports (`queue`, `durable`) use to route work; keep it
90
+ stable while deliveries may be pending. Two listener classes with the same
91
+ name fail the bootstrap. `role: 'api'` never consumes or runs listeners —
92
+ it emits and hands work to the transport.
93
+
72
94
  ### 2. Handlers run on the DI-resolved instance
73
95
 
74
96
  The decorated method is invoked on the real provider instance, so injected
@@ -86,17 +108,21 @@ export class AlertReactions {
86
108
  }
87
109
  ```
88
110
 
89
- Source: `packages/core/src/nestjs/diagnostics.explorer.ts` (`safeInvoke` calls `fn.call(instance, event)`).
111
+ Source: `packages/core/src/nestjs/diagnostics.explorer.ts` (`invoke` calls `fn.call(instance, event)`).
90
112
 
91
- ### 3. Never-throw isolation
113
+ ### 3. Never-throw isolation without a delivering transport
92
114
 
93
115
  `diagnostics_channel.publish` is **synchronous**, so a subscriber that throws
94
- would propagate into the emitter's call stack. The explorer's `safeInvoke`
116
+ would propagate into the emitter's call stack. Without a delivering transport,
117
+ the explorer's `invoke` path
95
118
  catches synchronous throws and attaches a `.catch` to rejected promises, logging
96
119
  both — a reaction can never break the `emit()` that triggered it. Async handlers
97
- are therefore fire-and-forget (publish cannot await).
120
+ are therefore fire-and-forget (publish cannot await). With a delivering
121
+ transport (`queue`, `durable`), delivery happens once, from the emitting
122
+ process, and the handler's error rejects `invoke` so the transport can retry
123
+ instead of being swallowed.
98
124
 
99
- Source: `packages/core/src/nestjs/diagnostics.explorer.ts` (`safeInvoke`, `logError`).
125
+ Source: `packages/core/src/nestjs/diagnostics.explorer.ts` (`invoke`, `onEvent`, `deliver`).
100
126
 
101
127
  ## Common mistakes
102
128
 
@@ -143,21 +169,23 @@ Source: `packages/core/src/nestjs/diagnostics.explorer.ts` (`discovery.getProvid
143
169
  ### Throwing in a handler expecting the framework to retry
144
170
 
145
171
  ```ts
146
- // Wrong — assuming a throw bubbles up or triggers a retry.
172
+ // Wrong — assuming a throw bubbles up or triggers a retry (without a delivering transport it will NOT — it is logged and swallowed).
147
173
  @OnDiagnostic('billing', 'invoice-paid')
148
174
  onPaid(e: DiagnosticEvent) {
149
- throw new Error('will be retried'); // it will NOT — it is logged and swallowed
175
+ throw new Error('will be retried'); // only retried with transports.queue()/durable()
150
176
  }
151
177
  ```
152
178
 
153
179
  ```ts
154
- // Correct — handle failures inside the reaction; it is fire-and-forget.
180
+ // Correct — handle failures inside the reaction when running without a delivering transport; it is fire-and-forget.
155
181
  @OnDiagnostic('billing', 'invoice-paid')
156
182
  async onPaid(e: DiagnosticEvent) {
157
183
  try { await this.work(e); } catch (err) { this.logger.warn(err); }
158
184
  }
159
185
  ```
160
186
 
161
- `safeInvoke` swallows throws/rejections by design, so emission stays safe — there
162
- is no delivery guarantee, retry, or replay.
163
- Source: `packages/core/src/nestjs/diagnostics.explorer.ts` (`safeInvoke`).
187
+ Without a delivering transport, the explorer swallows throws/rejections by design, so emission stays safe — there
188
+ is no delivery guarantee, retry, or replay. With `transports.queue()` or
189
+ `transports.durable()`, the handler error propagates to the transport and is
190
+ retried (delivery happens once, from the emitting process).
191
+ Source: `packages/core/src/nestjs/diagnostics.explorer.ts` (`invoke`, `onEvent`).
@@ -42,7 +42,8 @@ export class AuthzService {
42
42
  ```
43
43
 
44
44
  Span events ride `aviary:<lib>:<event>:<phase>`; the base `aviary:<lib>:<event>`
45
- name is what gets registered for discovery. A `SpanEvent` carries `v`, `ts`,
45
+ name is what gets registered for discovery. A `SpanEvent` carries `v`, a unique
46
+ `id` (a UUID stamped by `trace`; correlate phases with `spanId`), `ts`,
46
47
  `lib`, `event`, `phase`, a per-span `spanId`, optional `traceId`, and
47
48
  `payload` / `result` / `error` / `durationMs` depending on the phase.
48
49