@nodii/telemetry 0.0.2 → 0.3.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 (82) hide show
  1. package/README.md +223 -1
  2. package/dist/active-span.d.ts +12 -0
  3. package/dist/active-span.d.ts.map +1 -0
  4. package/dist/active-span.js +20 -0
  5. package/dist/active-span.js.map +1 -0
  6. package/dist/agent-invocable.d.ts +24 -0
  7. package/dist/agent-invocable.d.ts.map +1 -0
  8. package/dist/agent-invocable.js +64 -0
  9. package/dist/agent-invocable.js.map +1 -0
  10. package/dist/audit-types.d.ts +15 -0
  11. package/dist/audit-types.d.ts.map +1 -0
  12. package/dist/audit-types.js +39 -0
  13. package/dist/audit-types.js.map +1 -0
  14. package/dist/audit.d.ts +226 -0
  15. package/dist/audit.d.ts.map +1 -0
  16. package/dist/audit.js +255 -0
  17. package/dist/audit.js.map +1 -0
  18. package/dist/configure.d.ts +34 -0
  19. package/dist/configure.d.ts.map +1 -0
  20. package/dist/configure.js +23 -0
  21. package/dist/configure.js.map +1 -0
  22. package/dist/context.d.ts +40 -0
  23. package/dist/context.d.ts.map +1 -0
  24. package/dist/context.js +70 -0
  25. package/dist/context.js.map +1 -0
  26. package/dist/drizzle/audit-schema.d.ts +884 -0
  27. package/dist/drizzle/audit-schema.d.ts.map +1 -0
  28. package/dist/drizzle/audit-schema.js +268 -0
  29. package/dist/drizzle/audit-schema.js.map +1 -0
  30. package/dist/drizzle/index.d.ts +3 -0
  31. package/dist/drizzle/index.d.ts.map +1 -0
  32. package/dist/drizzle/index.js +5 -0
  33. package/dist/drizzle/index.js.map +1 -0
  34. package/dist/index.d.ts +21 -2
  35. package/dist/index.d.ts.map +1 -1
  36. package/dist/index.js +31 -5
  37. package/dist/index.js.map +1 -1
  38. package/dist/init.d.ts +39 -0
  39. package/dist/init.d.ts.map +1 -0
  40. package/dist/init.js +114 -0
  41. package/dist/init.js.map +1 -0
  42. package/dist/intent.d.ts +21 -0
  43. package/dist/intent.d.ts.map +1 -0
  44. package/dist/intent.js +123 -0
  45. package/dist/intent.js.map +1 -0
  46. package/dist/logger.d.ts +19 -0
  47. package/dist/logger.d.ts.map +1 -0
  48. package/dist/logger.js +99 -0
  49. package/dist/logger.js.map +1 -0
  50. package/dist/metrics.d.ts +53 -0
  51. package/dist/metrics.d.ts.map +1 -0
  52. package/dist/metrics.js +152 -0
  53. package/dist/metrics.js.map +1 -0
  54. package/dist/otlp-adapter.d.ts +44 -0
  55. package/dist/otlp-adapter.d.ts.map +1 -0
  56. package/dist/otlp-adapter.js +351 -0
  57. package/dist/otlp-adapter.js.map +1 -0
  58. package/dist/outbox-emit.d.ts +34 -0
  59. package/dist/outbox-emit.d.ts.map +1 -0
  60. package/dist/outbox-emit.js +58 -0
  61. package/dist/outbox-emit.js.map +1 -0
  62. package/dist/redaction.d.ts +51 -0
  63. package/dist/redaction.d.ts.map +1 -0
  64. package/dist/redaction.js +173 -0
  65. package/dist/redaction.js.map +1 -0
  66. package/dist/sdk-counters.d.ts +14 -0
  67. package/dist/sdk-counters.d.ts.map +1 -0
  68. package/dist/sdk-counters.js +42 -0
  69. package/dist/sdk-counters.js.map +1 -0
  70. package/dist/tracer.d.ts +63 -0
  71. package/dist/tracer.d.ts.map +1 -0
  72. package/dist/tracer.js +214 -0
  73. package/dist/tracer.js.map +1 -0
  74. package/dist/types.d.ts +230 -0
  75. package/dist/types.d.ts.map +1 -0
  76. package/dist/types.js +66 -0
  77. package/dist/types.js.map +1 -0
  78. package/dist/uuid.d.ts +5 -0
  79. package/dist/uuid.d.ts.map +1 -0
  80. package/dist/uuid.js +34 -0
  81. package/dist/uuid.js.map +1 -0
  82. package/package.json +44 -7
package/README.md CHANGED
@@ -1,5 +1,227 @@
1
1
  # @nodii/telemetry
2
2
 
3
- Placeholder package at v0.0.1. Implementation lands at v0.1.0 per the locked feature_doc.
3
+ Substrate observability library for the Nodii microservice stack. v0.1.0
4
+ ships the SDK surface — bootstrap, log envelope, tracer, meter, audit
5
+ signal, intent lifecycle, agent registry, context propagation — without
6
+ the OTel-SDK wiring (deferred to a v0.1.x follow-up; see
7
+ `.agent-todo.md` TS-12).
4
8
 
5
9
  **Spec**: `https://planning.dev.nucleus-cloud.in/api/v1/feature-docs?serviceId=nodii-libs&docKey=telemetry`
10
+
11
+ ## Install
12
+
13
+ ```sh
14
+ bun add @nodii/telemetry
15
+ ```
16
+
17
+ ## Bootstrap (D152)
18
+
19
+ ```ts
20
+ import { initTelemetry } from "@nodii/telemetry";
21
+
22
+ initTelemetry({
23
+ serviceName: "nodii-billing-service",
24
+ env: process.env.APPLICATION_STATE!, // 'dev' | 'uat' | 'prod'
25
+ otlpEndpoint: process.env.OTLP_ENDPOINT,
26
+ vocabularyRegistry: {
27
+ billing_payments_total: {
28
+ family: "async_worker",
29
+ description: "Payments processed",
30
+ decision: "D23",
31
+ },
32
+ },
33
+ intentTypes: {
34
+ "billing.invoice.create": {
35
+ typeName: "billing.invoice.create",
36
+ server_mintable: true,
37
+ client_mintable: false,
38
+ timeout_seconds: 300,
39
+ },
40
+ },
41
+ });
42
+ ```
43
+
44
+ Subsequent `initTelemetry()` calls warn-log + no-op. Calling any public
45
+ API before init throws `TelemetryNotInitialized`.
46
+
47
+ ## Logger (D13)
48
+
49
+ ```ts
50
+ import { logger } from "@nodii/telemetry";
51
+
52
+ logger.info("payment.charged", { invoice_id, amount_minor_units });
53
+ logger.error("saga.compensation.failed", { saga_id, step, reason });
54
+ ```
55
+
56
+ The 11-field envelope (`level, ts, msg, service, env, tenant_id,
57
+ user_id, request_id, trace_id, span_id, intent_id`) is auto-attached
58
+ from the active `NodiiContext` + the init config + the active OTel
59
+ span. **Do not pass envelope fields yourself** — they get filled in.
60
+
61
+ D15 redaction runs on every line (structured-field keys against the D2
62
+ PII list + regex pass on the message string) and is **fail-closed**:
63
+ if redaction throws, the line is DROPPED and
64
+ `telemetry.sdk.redaction_failure_total{reason}` bumps.
65
+
66
+ ## Tracer (D26 / D27 / D28)
67
+
68
+ ```ts
69
+ import { tracer, withSpanAttributes } from "@nodii/telemetry";
70
+
71
+ await withSpanAttributes({ invoice_id }, async () => {
72
+ await tracer.span("billing.invoice.create", async (span) => {
73
+ span.setAttribute("payment.method", method);
74
+ // ... business logic; mandatory attrs auto-applied
75
+ });
76
+ });
77
+ ```
78
+
79
+ Mandatory attributes (`tenant_id, request_id, intent_id`) are stamped
80
+ on span start. 4 KB per-value cap with `_truncated=true` marker. D27
81
+ status mapping: `recordException` auto-pairs with `ERROR`; clean
82
+ return defaults to `OK`.
83
+
84
+ ## Metrics (D18 / D19 / D20 / D24)
85
+
86
+ ```ts
87
+ import { metrics } from "@nodii/telemetry";
88
+
89
+ const paymentsCounter = metrics.counter("billing_payments_total", {
90
+ family: "async_worker",
91
+ description: "Payments processed",
92
+ });
93
+ paymentsCounter.inc({ tenant_id, pgw, status });
94
+ ```
95
+
96
+ Names must exist in the vocabulary registry passed to
97
+ `initTelemetry({ vocabularyRegistry })` — D24 ADR-gated. Mismatched
98
+ family or off-vocab name → `MetricVocabularyError` + bumps
99
+ `telemetry.sdk.cardinality_rejected_total{family, reason}`.
100
+
101
+ D20 bare-label discipline: registration rejects `tenant.id` and
102
+ `tenantId` variants.
103
+
104
+ D19: exponential histograms, max 160 buckets.
105
+
106
+ ## Audit (D17 / D33)
107
+
108
+ ```ts
109
+ import { audit } from "@nodii/telemetry";
110
+
111
+ await audit.emit({
112
+ action: "payment.refund.issued",
113
+ target_kind: "payment",
114
+ target_id: payment.id,
115
+ payload: { amount_minor_units, reason },
116
+ });
117
+ ```
118
+
119
+ The library ships the adapter (write path); the emission policy
120
+ (method-level interceptor, saga lifecycle events, agent-layer
121
+ double-emission) and the `audit_log` schema live in the audit
122
+ doctrine + each consuming service.
123
+
124
+ ## Intent lifecycle (D46 / D155)
125
+
126
+ ```ts
127
+ import { intent } from "@nodii/telemetry";
128
+
129
+ const id = await intent.begin("billing.invoice.create", { invoice_id });
130
+ try {
131
+ // work
132
+ await intent.complete(id, { result: "ok" });
133
+ } catch (err) {
134
+ await intent.abandon(id, "error");
135
+ throw err;
136
+ }
137
+ ```
138
+
139
+ `intent.begin` HARD-validates the type name against the registry
140
+ (D155); unknown type → `IntentTypeNotRegistered`. Activates the intent
141
+ on the active `NodiiContext` (sets `intent_id`). Nested begins stack
142
+ by id match.
143
+
144
+ `intent.progress` is a no-op stub at v0.1.0 per D155 § M02
145
+ carry-forward.
146
+
147
+ ## @agentInvocable (D156)
148
+
149
+ ```ts
150
+ import { agentInvocable } from "@nodii/telemetry";
151
+
152
+ class PaymentService {
153
+ @agentInvocable({
154
+ mode: "composable",
155
+ authTier: "confirmation-required",
156
+ sideEffects: ["payment.refund"],
157
+ idempotency: "keyed-by-request-id",
158
+ description: "Refund a captured payment",
159
+ })
160
+ async refundPayment(req: RefundRequest): Promise<RefundResult> {
161
+ /* ... */
162
+ }
163
+ }
164
+ ```
165
+
166
+ Runtime is a no-op at v0.1.0 (D156). The decorator attaches the
167
+ config to the method + the class prototype under a symbol-keyed
168
+ property; the build-time codegen (separate tool, deferred) walks the
169
+ tsc AST + falls back to the runtime registry to emit
170
+ `agent-methods.generated.json`.
171
+
172
+ ## Context propagation (D40 / D41)
173
+
174
+ ```ts
175
+ import {
176
+ type NodiiContext,
177
+ withContext,
178
+ getContext,
179
+ requireContext,
180
+ } from "@nodii/telemetry";
181
+
182
+ const ctx: NodiiContext = {
183
+ tenant_id: "...",
184
+ user_id: "...",
185
+ actor_type: "user",
186
+ on_behalf_of: null,
187
+ role: "owner",
188
+ request_id: "...",
189
+ intent_id: null,
190
+ };
191
+ await withContext(ctx, async () => {
192
+ /* every log / span / metric / audit emit picks up this context */
193
+ });
194
+ ```
195
+
196
+ Read with `getContext()` (returns null when no scope active) or
197
+ `requireContext()` (throws). SDK middleware adapters (deferred to
198
+ TS-9) are the ONLY writers of the parent-scope context per D41 lock;
199
+ service code uses `withContext` for child scopes only.
200
+
201
+ ## SDK-internal counters
202
+
203
+ The library increments these on its own behaviors (do not register
204
+ them in your vocabulary):
205
+
206
+ - `telemetry.sdk.redaction_failure_total{reason}` — D15 fail-closed
207
+ drop.
208
+ - `telemetry.sdk.cardinality_rejected_total{family, reason}` — D18.
209
+ - `telemetry.sdk.export_failures_total{signal, reason}` — D153.
210
+ - `telemetry.sdk.trace_propagation_missing_total` — § 5.9 D25.
211
+
212
+ ## Deferred to v0.1.x
213
+
214
+ See `.agent-todo.md` at the repo root:
215
+
216
+ - **TS-9**: Subpath adapters (`/grpc`, `/bullmq`, `/outbox`,
217
+ `/system-process`, `/lambda`).
218
+ - **TS-12**: Real OTel SDK wiring — replaces the no-op
219
+ `SpanEmitter` + the default JSON log sink with the OTLP
220
+ exporters.
221
+ - **TS-13**: Smoke service per D157 at `ts/telemetry-smoke/`.
222
+ - **TS-14**: Telemetry-tax-budget benchmark (D28 ≤ 200µs SDK-side
223
+ per typical RPC).
224
+
225
+ ## License
226
+
227
+ MIT
@@ -0,0 +1,12 @@
1
+ export interface ActiveSpanRef {
2
+ trace_id: string;
3
+ span_id: string;
4
+ }
5
+ export type ActiveSpanGetter = () => ActiveSpanRef | null;
6
+ /** SDK-internal: the tracer module installs this on initialization. */
7
+ export declare function _setActiveSpanGetter(g: ActiveSpanGetter): void;
8
+ /** Read the active span ids. Returns null when no span is active. */
9
+ export declare function getActiveSpan(): ActiveSpanRef | null;
10
+ /** Test-only reset. */
11
+ export declare function _resetActiveSpanForTests(): void;
12
+ //# sourceMappingURL=active-span.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-span.d.ts","sourceRoot":"","sources":["../src/active-span.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,gBAAgB,GAAG,MAAM,aAAa,GAAG,IAAI,CAAC;AAI1D,uEAAuE;AACvE,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAE9D;AAED,qEAAqE;AACrE,wBAAgB,aAAa,IAAI,aAAa,GAAG,IAAI,CAEpD;AAED,uBAAuB;AACvB,wBAAgB,wBAAwB,IAAI,IAAI,CAE/C"}
@@ -0,0 +1,20 @@
1
+ // Active-span hooks. The tracer (§ 5.3) registers a getter that returns
2
+ // the current `{ trace_id, span_id }` pair, or null if no span is
3
+ // active. The logger reads this on every log line so envelope fields
4
+ // `trace_id` and `span_id` (D13) are auto-stamped without the logger
5
+ // importing the tracer (avoids a cycle and lets the OTel wiring land
6
+ // in TS-12 as a strict module-internal swap).
7
+ let getter = () => null;
8
+ /** SDK-internal: the tracer module installs this on initialization. */
9
+ export function _setActiveSpanGetter(g) {
10
+ getter = g;
11
+ }
12
+ /** Read the active span ids. Returns null when no span is active. */
13
+ export function getActiveSpan() {
14
+ return getter();
15
+ }
16
+ /** Test-only reset. */
17
+ export function _resetActiveSpanForTests() {
18
+ getter = () => null;
19
+ }
20
+ //# sourceMappingURL=active-span.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active-span.js","sourceRoot":"","sources":["../src/active-span.ts"],"names":[],"mappings":"AAAA,wEAAwE;AACxE,kEAAkE;AAClE,qEAAqE;AACrE,qEAAqE;AACrE,qEAAqE;AACrE,8CAA8C;AAS9C,IAAI,MAAM,GAAqB,GAAG,EAAE,CAAC,IAAI,CAAC;AAE1C,uEAAuE;AACvE,MAAM,UAAU,oBAAoB,CAAC,CAAmB;IACtD,MAAM,GAAG,CAAC,CAAC;AACb,CAAC;AAED,qEAAqE;AACrE,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,EAAE,CAAC;AAClB,CAAC;AAED,uBAAuB;AACvB,MAAM,UAAU,wBAAwB;IACtC,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC;AACtB,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { type AgentInvocableConfig } from "./types";
2
+ export declare const AGENT_INVOCABLE_METADATA: unique symbol;
3
+ /**
4
+ * Method decorator. TS legacy decorators are still the only widely
5
+ * deployed form for class methods; we attach metadata under a
6
+ * symbol-keyed property on the method itself + on the class prototype.
7
+ *
8
+ * Usage:
9
+ *
10
+ * class PaymentService {
11
+ * @agentInvocable({ mode: 'composable', authTier: 'confirmation-required',
12
+ * sideEffects: ['payment.refund'], idempotency: 'keyed-by-request-id',
13
+ * description: 'Refund a captured payment' })
14
+ * async refundPayment(req) { ... }
15
+ * }
16
+ */
17
+ export declare function agentInvocable(cfg: AgentInvocableConfig): (target: object, propertyKey: string | symbol, descriptor: PropertyDescriptor) => PropertyDescriptor;
18
+ /**
19
+ * Read the registry from a class. Used by tests + the codegen fallback
20
+ * (when AST discovery doesn't find a decorator, e.g. when the file was
21
+ * transformed by a different toolchain).
22
+ */
23
+ export declare function readAgentRegistry<T extends object>(ctor: T): Record<string | symbol, AgentInvocableConfig>;
24
+ //# sourceMappingURL=agent-invocable.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-invocable.d.ts","sourceRoot":"","sources":["../src/agent-invocable.ts"],"names":[],"mappings":"AASA,OAAO,EAEL,KAAK,oBAAoB,EAC1B,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,wBAAwB,eAEpC,CAAC;AAoBF;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,oBAAoB,IAGpD,QAAQ,MAAM,EACd,aAAa,MAAM,GAAG,MAAM,EAC5B,YAAY,kBAAkB,KAC7B,kBAAkB,CAuBtB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,MAAM,EAChD,IAAI,EAAE,CAAC,GACN,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,oBAAoB,CAAC,CAM/C"}
@@ -0,0 +1,64 @@
1
+ // `@agentInvocable` decorator per D156. Runtime no-op at v0.1.0 — the
2
+ // agent dispatcher consumes the build-time codegen registry
3
+ // (`agent-methods.generated.json`), not the runtime metadata.
4
+ //
5
+ // At v0.1.0 we attach the supplied config to the method's prototype
6
+ // under a well-known symbol so the codegen step (a separate tsc AST
7
+ // walk in TS-8 wave 2) can also discover registrations via runtime
8
+ // import if it falls back from the AST path.
9
+ import { AGENT_INVOCABLE_SIDE_EFFECTS, } from "./types";
10
+ export const AGENT_INVOCABLE_METADATA = Symbol.for("@nodii/telemetry/agentInvocable");
11
+ function validate(cfg) {
12
+ if (cfg.mode === "strict-only" && !cfg.allowedPipelines?.length) {
13
+ throw new Error("@agentInvocable: `allowedPipelines` is required when `mode = 'strict-only'`");
14
+ }
15
+ for (const eff of cfg.sideEffects) {
16
+ if (!AGENT_INVOCABLE_SIDE_EFFECTS.includes(eff)) {
17
+ throw new Error(`@agentInvocable: sideEffect '${eff}' is not in the locked vocabulary (D156).`);
18
+ }
19
+ }
20
+ if (!cfg.description) {
21
+ throw new Error("@agentInvocable: `description` is required");
22
+ }
23
+ }
24
+ /**
25
+ * Method decorator. TS legacy decorators are still the only widely
26
+ * deployed form for class methods; we attach metadata under a
27
+ * symbol-keyed property on the method itself + on the class prototype.
28
+ *
29
+ * Usage:
30
+ *
31
+ * class PaymentService {
32
+ * @agentInvocable({ mode: 'composable', authTier: 'confirmation-required',
33
+ * sideEffects: ['payment.refund'], idempotency: 'keyed-by-request-id',
34
+ * description: 'Refund a captured payment' })
35
+ * async refundPayment(req) { ... }
36
+ * }
37
+ */
38
+ export function agentInvocable(cfg) {
39
+ validate(cfg);
40
+ return function decorate(target, propertyKey, descriptor) {
41
+ const original = descriptor.value;
42
+ if (typeof original !== "function") {
43
+ throw new Error("@agentInvocable can only be applied to methods (PropertyDescriptor.value must be a function).");
44
+ }
45
+ // Attach metadata to the method function itself.
46
+ original[AGENT_INVOCABLE_METADATA] =
47
+ cfg;
48
+ // Mirror onto a class-level registry under the same symbol.
49
+ const ctor = target.constructor;
50
+ const existing = ctor[AGENT_INVOCABLE_METADATA] ?? {};
51
+ existing[propertyKey] = cfg;
52
+ ctor[AGENT_INVOCABLE_METADATA] = existing;
53
+ return descriptor;
54
+ };
55
+ }
56
+ /**
57
+ * Read the registry from a class. Used by tests + the codegen fallback
58
+ * (when AST discovery doesn't find a decorator, e.g. when the file was
59
+ * transformed by a different toolchain).
60
+ */
61
+ export function readAgentRegistry(ctor) {
62
+ return (ctor[AGENT_INVOCABLE_METADATA] ?? {});
63
+ }
64
+ //# sourceMappingURL=agent-invocable.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-invocable.js","sourceRoot":"","sources":["../src/agent-invocable.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,4DAA4D;AAC5D,8DAA8D;AAC9D,EAAE;AACF,oEAAoE;AACpE,oEAAoE;AACpE,mEAAmE;AACnE,6CAA6C;AAE7C,OAAO,EACL,4BAA4B,GAE7B,MAAM,SAAS,CAAC;AAEjB,MAAM,CAAC,MAAM,wBAAwB,GAAG,MAAM,CAAC,GAAG,CAChD,iCAAiC,CAClC,CAAC;AAEF,SAAS,QAAQ,CAAC,GAAyB;IACzC,IAAI,GAAG,CAAC,IAAI,KAAK,aAAa,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CACb,6EAA6E,CAC9E,CAAC;IACJ,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC;QAClC,IAAI,CAAC,4BAA4B,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAChD,MAAM,IAAI,KAAK,CACb,gCAAgC,GAAG,2CAA2C,CAC/E,CAAC;QACJ,CAAC;IACH,CAAC;IACD,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,cAAc,CAAC,GAAyB;IACtD,QAAQ,CAAC,GAAG,CAAC,CAAC;IACd,OAAO,SAAS,QAAQ,CACtB,MAAc,EACd,WAA4B,EAC5B,UAA8B;QAE9B,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC;QAClC,IAAI,OAAO,QAAQ,KAAK,UAAU,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,+FAA+F,CAChG,CAAC;QACJ,CAAC;QACD,iDAAiD;QAChD,QAA+C,CAAC,wBAAwB,CAAC;YACxE,GAAG,CAAC;QACN,4DAA4D;QAC5D,MAAM,IAAI,GAAI,MAAkC,CAAC,WAGhD,CAAC;QACF,MAAM,QAAQ,GACX,IAAI,CAAC,wBAAwB,CAEhB,IAAI,EAAE,CAAC;QACvB,QAAQ,CAAC,WAAW,CAAC,GAAG,GAAG,CAAC;QAC5B,IAAI,CAAC,wBAAwB,CAAC,GAAG,QAAQ,CAAC;QAC1C,OAAO,UAAU,CAAC;IACpB,CAAC,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAO;IAEP,OAAO,CACH,IAA2C,CAC3C,wBAAwB,CACyB,IAAI,EAAE,CAC1D,CAAC;AACJ,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Doctrine `02-audit-doctrine.md § 4` — the canonical `actor_kind` enum.
3
+ * 10 values, in this exact order; tests assert the order, so don't
4
+ * reorder without a drift entry. The SQL enum type is `audit_actor_kind`
5
+ * (one Postgres type shared across every service DB).
6
+ *
7
+ * `unknown` is the security marker per § 4.2 — emitted when no actor
8
+ * stamp can be derived; surfaces as a security alert via obs M17.
9
+ */
10
+ export declare const AUDIT_ACTOR_KINDS: readonly ["employee_user", "tenant_user", "tenant_customer", "service", "worker", "webhook_provider", "external_system", "agent", "system", "unknown"];
11
+ export type ActorKind = (typeof AUDIT_ACTOR_KINDS)[number];
12
+ /** Doctrine § 7 — 7-value `outcome` enum. Order matches the doctrine. */
13
+ export declare const AUDIT_OUTCOMES: readonly ["success", "failure", "partial", "queued", "dry_run", "denied_by_authz", "denied_by_mfa"];
14
+ export type AuditOutcome = (typeof AUDIT_OUTCOMES)[number];
15
+ //# sourceMappingURL=audit-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-types.d.ts","sourceRoot":"","sources":["../src/audit-types.ts"],"names":[],"mappings":"AAQA;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,wJAWpB,CAAC;AAEX,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,yEAAyE;AACzE,eAAO,MAAM,cAAc,qGAQjB,CAAC;AAEX,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,cAAc,CAAC,CAAC,MAAM,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ // Type + enum constants for the audit signal. Kept separate from
2
+ // `audit.ts` so the top-level `@nodii/telemetry` barrel does not
3
+ // transitively pull `drizzle-orm` (which lives under `./drizzle/`).
4
+ //
5
+ // Consumers who don't run Drizzle still get `ActorKind`, `AuditOutcome`,
6
+ // and the value arrays via the main barrel — and the Drizzle schema
7
+ // fragment that uses these is reachable via `@nodii/telemetry/drizzle`.
8
+ /**
9
+ * Doctrine `02-audit-doctrine.md § 4` — the canonical `actor_kind` enum.
10
+ * 10 values, in this exact order; tests assert the order, so don't
11
+ * reorder without a drift entry. The SQL enum type is `audit_actor_kind`
12
+ * (one Postgres type shared across every service DB).
13
+ *
14
+ * `unknown` is the security marker per § 4.2 — emitted when no actor
15
+ * stamp can be derived; surfaces as a security alert via obs M17.
16
+ */
17
+ export const AUDIT_ACTOR_KINDS = [
18
+ "employee_user",
19
+ "tenant_user",
20
+ "tenant_customer",
21
+ "service",
22
+ "worker",
23
+ "webhook_provider",
24
+ "external_system",
25
+ "agent",
26
+ "system",
27
+ "unknown",
28
+ ];
29
+ /** Doctrine § 7 — 7-value `outcome` enum. Order matches the doctrine. */
30
+ export const AUDIT_OUTCOMES = [
31
+ "success",
32
+ "failure",
33
+ "partial",
34
+ "queued",
35
+ "dry_run",
36
+ "denied_by_authz",
37
+ "denied_by_mfa",
38
+ ];
39
+ //# sourceMappingURL=audit-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit-types.js","sourceRoot":"","sources":["../src/audit-types.ts"],"names":[],"mappings":"AAAA,iEAAiE;AACjE,iEAAiE;AACjE,oEAAoE;AACpE,EAAE;AACF,yEAAyE;AACzE,oEAAoE;AACpE,wEAAwE;AAExE;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG;IAC/B,eAAe;IACf,aAAa;IACb,iBAAiB;IACjB,SAAS;IACT,QAAQ;IACR,kBAAkB;IAClB,iBAAiB;IACjB,OAAO;IACP,QAAQ;IACR,SAAS;CACD,CAAC;AAIX,yEAAyE;AACzE,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,SAAS;IACT,SAAS;IACT,SAAS;IACT,QAAQ;IACR,SAAS;IACT,iBAAiB;IACjB,eAAe;CACP,CAAC"}
@@ -0,0 +1,226 @@
1
+ import { AUDIT_ACTOR_KINDS, AUDIT_OUTCOMES, type ActorKind, type AuditOutcome } from "./audit-types";
2
+ export { AUDIT_ACTOR_KINDS, AUDIT_OUTCOMES };
3
+ export type { ActorKind, AuditOutcome };
4
+ /**
5
+ * Structured `actor` jsonb extension per doctrine § 4.1. Open-ended map;
6
+ * each `actor_kind` defines its own well-known fields (employee/user:
7
+ * `capacity`/`mfa`/`mfa_at`/`jti`; service: `instance_id`/`scopes`;
8
+ * worker: `queue_name`/`job_id`; webhook_provider: `transaction_id`/
9
+ * `signature_verified`; agent: `on_behalf_of`/`intent_id`/`tool`). NOT
10
+ * type-checked here — services that need stricter typing can layer their
11
+ * own discriminated union on top.
12
+ */
13
+ export type ActorStamp = Record<string, unknown>;
14
+ /**
15
+ * The rich audit-emit input shape per doctrine § 3 + § 6.0. Every field
16
+ * except `action` and `resourceType` is optional; the SDK resolves missing
17
+ * fields from `NodiiContext` + the active OTel span before handing the row
18
+ * to the writer.
19
+ *
20
+ * Field name convention: camelCase on the input; the SDK normalises to
21
+ * snake_case for the persisted row (`AuditEventRow`) matching the
22
+ * `<service>_audit_event` column names. This mirrors how Drizzle / pgx /
23
+ * SQLAlchemy schemas are typically declared in service code.
24
+ */
25
+ export interface AuditArgs {
26
+ tenantId?: string | null;
27
+ action: string;
28
+ resourceType: string;
29
+ resourceId?: string | null;
30
+ resourceLabel?: string | null;
31
+ secondaryResourceType?: string | null;
32
+ secondaryResourceId?: string | null;
33
+ actorKind?: ActorKind | null;
34
+ actorId?: string | null;
35
+ actorExternalId?: string | null;
36
+ actorDisplay?: string | null;
37
+ actorIp?: string | null;
38
+ actorUserAgent?: string | null;
39
+ actor?: ActorStamp | null;
40
+ outcome?: AuditOutcome;
41
+ httpStatus?: number | null;
42
+ grpcCode?: string | null;
43
+ errorCode?: string | null;
44
+ errorMessage?: string | null;
45
+ errorDetails?: Record<string, unknown> | null;
46
+ before?: Record<string, unknown> | null;
47
+ after?: Record<string, unknown> | null;
48
+ patch?: Record<string, unknown> | null;
49
+ changedFields?: string[] | null;
50
+ reasonCode?: string | null;
51
+ reasonText?: string | null;
52
+ requestId?: string | null;
53
+ correlationId?: string | null;
54
+ traceId?: string | null;
55
+ spanId?: string | null;
56
+ intentId?: string | null;
57
+ sagaId?: string | null;
58
+ stepId?: string | null;
59
+ idempotencyKey?: string | null;
60
+ queueName?: string | null;
61
+ jobId?: string | null;
62
+ parentAuditEventId?: string | null;
63
+ readCount?: number | null;
64
+ firstReadAt?: Date | null;
65
+ lastReadAt?: Date | null;
66
+ metadata?: Record<string, unknown>;
67
+ }
68
+ /**
69
+ * The fully-resolved row handed to the writer (and, if wired, to the chain
70
+ * adapter). Snake_case names match the `<service>_audit_event` columns 1:1
71
+ * per doctrine § 3 — the writer can copy fields into the SQL INSERT without
72
+ * a translation layer.
73
+ */
74
+ export interface AuditEventRow {
75
+ id: string;
76
+ tenant_id: string;
77
+ at: Date;
78
+ actor_kind: ActorKind;
79
+ actor_id: string | null;
80
+ actor_external_id: string | null;
81
+ actor_display: string | null;
82
+ actor_ip: string | null;
83
+ actor_user_agent: string | null;
84
+ actor: ActorStamp | null;
85
+ action: string;
86
+ resource_type: string;
87
+ resource_id: string | null;
88
+ resource_label: string | null;
89
+ secondary_resource_type: string | null;
90
+ secondary_resource_id: string | null;
91
+ outcome: AuditOutcome;
92
+ http_status: number | null;
93
+ grpc_code: string | null;
94
+ error_code: string | null;
95
+ error_message: string | null;
96
+ error_details: Record<string, unknown> | null;
97
+ before: Record<string, unknown> | null;
98
+ after: Record<string, unknown> | null;
99
+ patch: Record<string, unknown> | null;
100
+ changed_fields: string[] | null;
101
+ reason_code: string | null;
102
+ reason_text: string | null;
103
+ request_id: string | null;
104
+ correlation_id: string | null;
105
+ trace_id: string | null;
106
+ span_id: string | null;
107
+ intent_id: string | null;
108
+ saga_id: string | null;
109
+ step_id: string | null;
110
+ idempotency_key: string | null;
111
+ queue_name: string | null;
112
+ job_id: string | null;
113
+ parent_audit_event_id: string | null;
114
+ read_count: number | null;
115
+ first_read_at: Date | null;
116
+ last_read_at: Date | null;
117
+ prev_hash: Uint8Array | null;
118
+ row_hash: Uint8Array | null;
119
+ tenant_audit_seq: bigint | null;
120
+ metadata: Record<string, unknown>;
121
+ }
122
+ /**
123
+ * Legacy minimal shape from v0.1.0–v0.2.0. Still accepted by `audit.emit`
124
+ * so call sites in `@nodii/pii`, `@nodii/saga`, `@nodii/grpc-interceptors`
125
+ * continue to work unchanged. New callers should use `AuditArgs`.
126
+ *
127
+ * @deprecated Use `AuditArgs`. Mapping: `target_kind` → `resource_type`,
128
+ * `target_id` → `resource_id`, `payload` → `metadata`.
129
+ */
130
+ export interface AuditEvent {
131
+ /** D33-locked vocabulary, e.g. `payment.refund.issued`. */
132
+ action: string;
133
+ /** Maps to `resource_type` per doctrine § 3. */
134
+ target_kind: string;
135
+ /** Maps to `resource_id` per doctrine § 3. */
136
+ target_id: string | null;
137
+ /** Maps to `metadata` per doctrine § 3. */
138
+ payload?: Record<string, unknown>;
139
+ }
140
+ /**
141
+ * The pluggable Postgres-write path per doctrine § 15.1 + § 15.4.
142
+ *
143
+ * Services wire this at boot by calling `_setAuditWriter(...)` from a
144
+ * `@nodii/db-rls` adapter (or any service-supplied writer that implements
145
+ * this signature). The writer receives the canonical `AuditEventRow`
146
+ * matching `<service>_audit_event` columns 1:1.
147
+ *
148
+ * `tx` argument carries the in-flight transaction handle when `audit.emit`
149
+ * is called via Pattern A or B (in-tx); `undefined` for Pattern C
150
+ * (out-of-band — writer is responsible for opening its own short-lived tx
151
+ * scoped to `row.tenant_id`).
152
+ *
153
+ * v0.1.2 (drift `4cc80f62`) — the Noop default is GONE. If a service calls
154
+ * `audit.emit(...)` before wiring a real writer, the SDK throws
155
+ * `TelemetryAuditWriterMissing`. This closes the R1 violation in which
156
+ * audit rows were silently dropped because the lib defaulted to a no-op
157
+ * writer in production paths.
158
+ */
159
+ export type AuditWriter = (row: AuditEventRow, tx?: unknown) => Promise<void> | void;
160
+ /**
161
+ * Opt-in tamper-evident chain layer per doctrine § 13 + § 15.3. Wired via
162
+ * `configureTelemetry({audit: {chain}})` — typically from
163
+ * `@nodii/audit-chain`'s boot adapter.
164
+ *
165
+ * `augment` receives the canonical row (with `prev_hash` / `row_hash` /
166
+ * `tenant_audit_seq` all `null`) plus the in-flight tx (or `undefined`)
167
+ * and returns the computed chain triple. The implementation MUST acquire
168
+ * `pg_advisory_xact_lock(hash(tenant_id || 'audit'))` inside the tx so
169
+ * sequence allocation is per-tenant monotonic.
170
+ *
171
+ * Services that don't run the chain leave the three columns NULL; the
172
+ * library writes them as `null` to Postgres.
173
+ */
174
+ export interface AuditChainAdapter {
175
+ augment(row: AuditEventRow, tx?: unknown): Promise<{
176
+ prev_hash: Uint8Array | null;
177
+ row_hash: Uint8Array;
178
+ tenant_audit_seq: bigint;
179
+ }>;
180
+ }
181
+ /**
182
+ * Thrown by `audit.emit` when no `AuditWriter` has been wired. v0.1.2
183
+ * replaces the v0.1.0–v0.1.1 silent-Noop failure mode (R1 violation,
184
+ * drift `4cc80f62`). Services MUST wire a writer via `_setAuditWriter(...)`
185
+ * before the first `audit.emit` fires.
186
+ */
187
+ export declare class TelemetryAuditWriterMissing extends Error {
188
+ constructor();
189
+ }
190
+ /**
191
+ * SDK-internal: services or the `@nodii/db-rls` adapter sets the writer.
192
+ * Public callers MUST NOT call this; the override exists for the adapter
193
+ * layer.
194
+ */
195
+ export declare function _setAuditWriter(w: AuditWriter): void;
196
+ /** Test-only reset. Clears the wired writer; the next `audit.emit` will throw. */
197
+ export declare function _resetAuditWriterForTests(): void;
198
+ /**
199
+ * SDK-internal: `configureTelemetry({audit: {chain}})` calls this to wire
200
+ * the opt-in chain adapter. Setting `null` removes it.
201
+ */
202
+ export declare function _setAuditChain(adapter: AuditChainAdapter | null): void;
203
+ /** Test-only reset. Removes the wired chain adapter. */
204
+ export declare function _resetAuditChainForTests(): void;
205
+ /** SDK-internal accessor for tests + chain-layer integration probes. */
206
+ export declare function _getAuditChain(): AuditChainAdapter | null;
207
+ /**
208
+ * Pattern A / B (in-tx) — atomic with the mutation. Writer receives the
209
+ * caller's transaction handle and writes the audit row inside it.
210
+ */
211
+ declare function emit(tx: unknown, args: AuditArgs): Promise<void>;
212
+ /** Pattern C (out-of-band) — writer opens its own tenant-scoped tx. */
213
+ declare function emit(args: AuditArgs): Promise<void>;
214
+ /**
215
+ * Backward-compatible overload for the legacy minimal shape. Maps onto
216
+ * `AuditArgs` per doctrine § 3 before entering the shared write path.
217
+ *
218
+ * @deprecated Use the rich `AuditArgs` form. This overload exists so the
219
+ * v0.2.x call sites in `@nodii/pii`, `@nodii/saga`, `@nodii/grpc-
220
+ * interceptors` keep working unchanged while their authors migrate.
221
+ */
222
+ declare function emit(event: AuditEvent): Promise<void>;
223
+ export declare const audit: {
224
+ readonly emit: typeof emit;
225
+ };
226
+ //# sourceMappingURL=audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../src/audit.ts"],"names":[],"mappings":"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"}