autotel-audit 1.1.5 → 1.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.
package/README.md CHANGED
@@ -54,6 +54,21 @@ Wraps an async operation with audit metadata and handles success/failure outcome
54
54
  - `forceKeep?: boolean`: Force event through tail-sampling (default: true)
55
55
  - `ctx?: AuditContext`: Provide custom audit context (auto-resolved from trace if omitted)
56
56
  - `logger?: RequestLogger`: Override the request logger instance
57
+ - `onMissingContext?: 'throw' | 'warn' | 'skip'`: What to do when no trace context is active (see below)
58
+
59
+ **Without an active trace context**, `withAudit` and `securityEvent` run your handler un-audited. `onMissingContext` sets how they report it:
60
+
61
+ - `skip` is the default when telemetry is off: autotel `init()` has not run and no OpenTelemetry tracer provider is registered. Tests and local runs without a backend stay quiet.
62
+ - `warn` is the default when telemetry is on and the call runs outside a span. You get one warning per action; wrap the call in `trace()`/`instrument()` or pass `ctx`.
63
+ - `throw` fails fast. An explicit `onMissingContext` takes precedence over both defaults.
64
+
65
+ Set a process-wide default with `configureAudit`. A per-call option overrides it:
66
+
67
+ ```ts
68
+ import { configureAudit } from 'autotel-audit';
69
+
70
+ configureAudit({ onMissingContext: 'throw' });
71
+ ```
57
72
 
58
73
  **Example with custom context:**
59
74
 
package/dist/index.cjs CHANGED
@@ -26,6 +26,18 @@ function resolveContextSafe(ctx) {
26
26
  setAttributes: (attrs) => span.setAttributes(attrs)
27
27
  };
28
28
  }
29
+ let defaultOnMissingContext;
30
+ /**
31
+ * Process-wide defaults. A per-call `onMissingContext` still wins; pass
32
+ * `undefined` to restore the built-in default.
33
+ */
34
+ function configureAudit(options) {
35
+ defaultOnMissingContext = options.onMissingContext;
36
+ }
37
+ /** Per-call option, then configureAudit(), then skip-if-telemetry-off-else-warn. */
38
+ function resolveOnMissingContext(explicit) {
39
+ return explicit ?? defaultOnMissingContext ?? ((0, autotel.isInitialized)() || (0, autotel.hasTracerProvider)() ? "warn" : "skip");
40
+ }
29
41
  /** A no-op {@link AuditContext} whose attribute setters do nothing. */
30
42
  function noopAuditContext() {
31
43
  return {
@@ -166,7 +178,7 @@ function securityEvent(metadata, options = {}) {
166
178
  const traceCtx = resolveContextSafe(options.ctx);
167
179
  if (options.metrics !== false) countSecurityEvent(metadata);
168
180
  if (!traceCtx) {
169
- const mode = options.onMissingContext ?? "warn";
181
+ const mode = resolveOnMissingContext(options.onMissingContext);
170
182
  if (mode === "throw") throw new Error(MISSING_CONTEXT_MESSAGE);
171
183
  if (mode === "warn") warnMissingContextOnce(metadata.name);
172
184
  return;
@@ -598,7 +610,7 @@ function setAuditAttributes(metadata, ctx) {
598
610
  async function withAudit(metadata, fn, options = {}) {
599
611
  const traceCtx = resolveContextSafe(options.ctx);
600
612
  if (!traceCtx) {
601
- const mode = options.onMissingContext ?? "warn";
613
+ const mode = resolveOnMissingContext(options.onMissingContext);
602
614
  if (mode === "throw") throw new Error(MISSING_CONTEXT_MESSAGE);
603
615
  if (mode === "warn") warnMissingContextOnce(metadata.action);
604
616
  return fn(noopAuditContext(), options.logger ?? (0, autotel.createNoopRequestLogger)());
@@ -607,7 +619,7 @@ async function withAudit(metadata, fn, options = {}) {
607
619
  setAuditAttributes(metadata, traceCtx);
608
620
  let logger = options.logger ?? (0, autotel.getRequestLoggerSafe)() ?? void 0;
609
621
  if (!logger) {
610
- if ((options.onMissingContext ?? "warn") === "warn") warnMissingLoggerOnce(metadata.action);
622
+ if (resolveOnMissingContext(options.onMissingContext) === "warn") warnMissingLoggerOnce(metadata.action);
611
623
  logger = (0, autotel.createNoopRequestLogger)();
612
624
  }
613
625
  logger.set({ audit: {
@@ -640,6 +652,7 @@ async function withAudit(metadata, fn, options = {}) {
640
652
  //#endregion
641
653
  exports.SUSPICIOUS_REQUEST_PATTERNS = SUSPICIOUS_REQUEST_PATTERNS;
642
654
  exports.applySecurityEventAttributes = applySecurityEventAttributes;
655
+ exports.configureAudit = configureAudit;
643
656
  exports.createMcpSecurityEventBridge = createMcpSecurityEventBridge;
644
657
  exports.createSecuritySignalProcessor = createSecuritySignalProcessor;
645
658
  exports.forceKeepAuditEvent = forceKeepAuditEvent;
package/dist/index.d.cts CHANGED
@@ -12,29 +12,38 @@ interface AuditContext {
12
12
  * How instrumentation should behave when no trace context is available.
13
13
  *
14
14
  * - `throw` — fail fast (original behaviour). Use when telemetry is mandatory.
15
- * - `warn` — run the wrapped handler un-audited and log one warning per action (default).
15
+ * - `warn` — run the wrapped handler un-audited and log one warning per action.
16
16
  * - `skip` — run the wrapped handler un-audited, silently.
17
17
  *
18
18
  * Telemetry is observability: a missing context should never crash the business
19
- * logic it wraps, so the default is best-effort (`warn`).
19
+ * logic it wraps, so the default is best-effort: `skip` when telemetry is off
20
+ * (no autotel init(), no tracer provider: nothing could be recorded anyway),
21
+ * `warn` otherwise.
20
22
  */
21
23
  type OnMissingContext = 'throw' | 'warn' | 'skip';
24
+ /**
25
+ * Process-wide defaults. A per-call `onMissingContext` still wins; pass
26
+ * `undefined` to restore the built-in default.
27
+ */
28
+ export declare function configureAudit(options: {
29
+ onMissingContext?: OnMissingContext;
30
+ }): void;
22
31
  //#endregion
23
32
  //#region src/security.d.ts
24
33
  /**
25
34
  * Security event categories, aligned with OWASP A09:2025
26
35
  * (Security Logging & Alerting Failures) and ASVS V7.
27
36
  */
28
- type SecurityEventCategory = 'authentication' | 'authorization' | 'data_access' | 'admin_action' | 'configuration' | 'secrets' | 'rate_limit' | 'validation' | 'supply_chain' | 'llm';
29
- type SecurityOutcome = 'success' | 'failure' | 'denied' | 'blocked' | 'error';
37
+ export type SecurityEventCategory = 'authentication' | 'authorization' | 'data_access' | 'admin_action' | 'configuration' | 'secrets' | 'rate_limit' | 'validation' | 'supply_chain' | 'llm';
38
+ export type SecurityOutcome = 'success' | 'failure' | 'denied' | 'blocked' | 'error';
30
39
  /**
31
40
  * Well-known security event names. Free-form names are allowed —
32
41
  * this union exists for autocomplete and consistency across services.
33
42
  */
34
- type SuggestedSecurityEventName = 'auth.login.success' | 'auth.login.failed' | 'auth.mfa.failed' | 'auth.session.revoked' | 'auth.password.reset' | 'auth.account.locked' | 'access.denied' | 'access.role.changed' | 'access.permission.changed' | 'access.tenant.violation' | 'admin.action' | 'config.changed' | 'secret.accessed' | 'secret.rotation.failed' | 'api_key.created' | 'api_key.revoked' | 'rate_limit.exceeded' | 'validation.failed' | 'webhook.signature.failed' | 'dependency.scan.failed' | 'llm.prompt_injection.detected' | 'llm.tool_call.denied' | 'llm.output.blocked' | 'llm.output.budget_exceeded' | 'llm.guard.triggered' | 'llm.action_chain.suspicious' | 'llm.manifest.suspicious' | 'llm.plan.risk.elevated';
43
+ export type SuggestedSecurityEventName = 'auth.login.success' | 'auth.login.failed' | 'auth.mfa.failed' | 'auth.session.revoked' | 'auth.password.reset' | 'auth.account.locked' | 'access.denied' | 'access.role.changed' | 'access.permission.changed' | 'access.tenant.violation' | 'admin.action' | 'config.changed' | 'secret.accessed' | 'secret.rotation.failed' | 'api_key.created' | 'api_key.revoked' | 'rate_limit.exceeded' | 'validation.failed' | 'webhook.signature.failed' | 'dependency.scan.failed' | 'llm.prompt_injection.detected' | 'llm.tool_call.denied' | 'llm.output.blocked' | 'llm.output.budget_exceeded' | 'llm.guard.triggered' | 'llm.action_chain.suspicious' | 'llm.manifest.suspicious' | 'llm.plan.risk.elevated';
35
44
  /** An attribute value, as OpenTelemetry allows one on a span. */
36
- type SecurityAttributeValue = string | number | boolean | string[] | number[] | boolean[];
37
- interface SecurityEventMetadata {
45
+ export type SecurityAttributeValue = string | number | boolean | string[] | number[] | boolean[];
46
+ export interface SecurityEventMetadata {
38
47
  /** Stable, dot-separated event name, e.g. `auth.login.failed`. */
39
48
  name: SuggestedSecurityEventName | (string & {});
40
49
  category: SecurityEventCategory;
@@ -51,7 +60,7 @@ interface SecurityEventMetadata {
51
60
  /** Extra fields ride along as span attributes; see AuditMetadataValue. */
52
61
  [key: string]: AuditMetadataValue;
53
62
  }
54
- interface SecurityEventOptions {
63
+ export interface SecurityEventOptions {
55
64
  ctx?: AuditContext;
56
65
  /**
57
66
  * Security events are exempt from tail sampling by default —
@@ -71,17 +80,17 @@ interface SecurityEventOptions {
71
80
  */
72
81
  metrics?: boolean;
73
82
  /**
74
- * Behaviour when no trace context can be resolved. Defaults to `warn`
75
- * (best-effort: record nothing, warn once). A dropped security event is still
76
- * better than a crashed request — but the warning makes the gap visible.
83
+ * Behaviour when no trace context can be resolved. Defaults to the
84
+ * configureAudit() value, else `skip` when telemetry is off and `warn`
85
+ * (once per event) otherwise. See {@link OnMissingContext}.
77
86
  */
78
87
  onMissingContext?: OnMissingContext;
79
88
  }
80
- type WithSecurityOptions = SecurityEventOptions;
89
+ export type WithSecurityOptions = SecurityEventOptions;
81
90
  interface SecurityAttributeSink {
82
91
  setAttribute(key: string, value: SecurityAttributeValue): void;
83
92
  }
84
- declare function applySecurityEventAttributes(sink: SecurityAttributeSink, metadata: SecurityEventMetadata, options?: Pick<SecurityEventOptions, 'forceKeep' | 'metrics'>): void;
93
+ export declare function applySecurityEventAttributes(sink: SecurityAttributeSink, metadata: SecurityEventMetadata, options?: Pick<SecurityEventOptions, 'forceKeep' | 'metrics'>): void;
85
94
  /**
86
95
  * Record a security event on the active trace and request logger.
87
96
  *
@@ -101,7 +110,7 @@ declare function applySecurityEventAttributes(sink: SecurityAttributeSink, metad
101
110
  * });
102
111
  * ```
103
112
  */
104
- declare function securityEvent(metadata: SecurityEventMetadata, options?: SecurityEventOptions): void;
113
+ export declare function securityEvent(metadata: SecurityEventMetadata, options?: SecurityEventOptions): void;
105
114
  /**
106
115
  * Wrap a security-sensitive operation. On success the event outcome is
107
116
  * recorded as given (default `success`); a thrown error records
@@ -115,8 +124,8 @@ declare function securityEvent(metadata: SecurityEventMetadata, options?: Securi
115
124
  * );
116
125
  * ```
117
126
  */
118
- declare function withSecurity<T>(metadata: SecurityEventMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithSecurityOptions): Promise<T>;
119
- interface HashIdentifierOptions {
127
+ export declare function withSecurity<T>(metadata: SecurityEventMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithSecurityOptions): Promise<T>;
128
+ export interface HashIdentifierOptions {
120
129
  /** Optional salt; use one stable per-deployment salt to defeat rainbow lookups. */
121
130
  salt?: string;
122
131
  /** Digest length in hex chars (default 16). */
@@ -128,7 +137,7 @@ interface HashIdentifierOptions {
128
137
  *
129
138
  * NOT for secrets — never log secrets in any form, hashed or not.
130
139
  */
131
- declare function hashIdentifier(value: string, options?: HashIdentifierOptions): string;
140
+ export declare function hashIdentifier(value: string, options?: HashIdentifierOptions): string;
132
141
  //#endregion
133
142
  //#region src/security-signals.d.ts
134
143
  /**
@@ -155,13 +164,13 @@ declare function hashIdentifier(value: string, options?: HashIdentifierOptions):
155
164
  * observability backend — this processor's job is to make the signals
156
165
  * exist, survive sampling, and stay queryable under a stable schema.
157
166
  */
158
- type AttributeValue = string | number | boolean | Array<null | undefined | string> | Array<null | undefined | number> | Array<null | undefined | boolean>;
167
+ export type AttributeValue = string | number | boolean | Array<null | undefined | string> | Array<null | undefined | number> | Array<null | undefined | boolean>;
159
168
  /** The parent context OTel hands a processor. This package never reads it. */
160
- interface SpanParentContext {
169
+ export interface SpanParentContext {
161
170
  getValue?: (key: symbol) => ContextValue;
162
171
  }
163
172
  /** Whatever OTel stored under a context key. This package never reads one. */
164
- type ContextValue = object | string | number | boolean | undefined;
173
+ export type ContextValue = object | string | number | boolean | undefined;
165
174
  interface MutableSpanLike {
166
175
  attributes: Record<string, AttributeValue | undefined>;
167
176
  spanContext?: {
@@ -175,20 +184,20 @@ interface ReadableSpanLike {
175
184
  traceId: string;
176
185
  };
177
186
  }
178
- interface SecuritySignalProcessor {
187
+ export interface SecuritySignalProcessor {
179
188
  onStart(span: MutableSpanLike, parentContext?: SpanParentContext): void;
180
189
  onEnd(span: ReadableSpanLike): void;
181
190
  shutdown(): Promise<void>;
182
191
  forceFlush(): Promise<void>;
183
192
  }
184
- interface SuspiciousRequestSignal {
193
+ export interface SuspiciousRequestSignal {
185
194
  signal: 'suspicious_request';
186
195
  /** Which pattern matched, e.g. `path_traversal`. */
187
196
  pattern: string;
188
197
  /** The matched request path/URL (as found on the span). */
189
198
  target: string;
190
199
  }
191
- interface AuthFailureBurstSignal {
200
+ export interface AuthFailureBurstSignal {
192
201
  signal: 'auth_failure_burst';
193
202
  /** Value of the configured key attribute (e.g. client address). */
194
203
  key: string;
@@ -197,14 +206,14 @@ interface AuthFailureBurstSignal {
197
206
  windowMs: number;
198
207
  status: number;
199
208
  }
200
- interface LlmExcessiveTokensSignal {
209
+ export interface LlmExcessiveTokensSignal {
201
210
  signal: 'llm_excessive_tokens';
202
211
  /** Total tokens consumed by the single LLM call. */
203
212
  tokens: number;
204
213
  maxTokens: number;
205
214
  model?: string;
206
215
  }
207
- interface LlmTokenBudgetSignal {
216
+ export interface LlmTokenBudgetSignal {
208
217
  signal: 'llm_token_budget_exceeded';
209
218
  /** Value of the configured key attribute (e.g. end-user id). */
210
219
  key: string;
@@ -213,7 +222,7 @@ interface LlmTokenBudgetSignal {
213
222
  budget: number;
214
223
  windowMs: number;
215
224
  }
216
- interface LlmActionChainSuspiciousSignal {
225
+ export interface LlmActionChainSuspiciousSignal {
217
226
  signal: 'llm_action_chain_suspicious';
218
227
  /** Trace where the suspicious chain was observed. */
219
228
  traceId: string;
@@ -223,8 +232,8 @@ interface LlmActionChainSuspiciousSignal {
223
232
  elapsedMs: number;
224
233
  untrustedTool?: string;
225
234
  }
226
- type SecuritySignal = SuspiciousRequestSignal | AuthFailureBurstSignal | LlmExcessiveTokensSignal | LlmTokenBudgetSignal | LlmActionChainSuspiciousSignal;
227
- interface BurstOptions {
235
+ export type SecuritySignal = SuspiciousRequestSignal | AuthFailureBurstSignal | LlmExcessiveTokensSignal | LlmTokenBudgetSignal | LlmActionChainSuspiciousSignal;
236
+ export interface BurstOptions {
228
237
  /** HTTP statuses counted toward a burst. Default `[401, 403]`. */
229
238
  statuses?: number[];
230
239
  /** Denied responses within the window that trigger a signal. Default 10. */
@@ -239,7 +248,7 @@ interface BurstOptions {
239
248
  /** Max distinct clients tracked (oldest evicted). Default 10_000. */
240
249
  maxKeys?: number;
241
250
  }
242
- interface LlmSignalOptions {
251
+ export interface LlmSignalOptions {
243
252
  /**
244
253
  * Single-call token ceiling (`gen_ai.usage.total_tokens`, or input+output).
245
254
  * Default 100_000. Pass `false` to disable the per-call check.
@@ -263,7 +272,7 @@ interface LlmSignalOptions {
263
272
  maxKeys?: number;
264
273
  };
265
274
  }
266
- interface SecuritySignalProcessorOptions {
275
+ export interface SecuritySignalProcessorOptions {
267
276
  /** Flag suspicious request paths on span start. Default true. */
268
277
  detectSuspiciousRequests?: boolean;
269
278
  /** Additional name → pattern pairs checked against the request target. */
@@ -298,14 +307,14 @@ interface SecuritySignalProcessorOptions {
298
307
  * Conservative request-target patterns. Tuned for scanner/probe traffic —
299
308
  * high signal, low false-positive — not as a WAF. Extend via `extraPatterns`.
300
309
  */
301
- declare const SUSPICIOUS_REQUEST_PATTERNS: {
310
+ export declare const SUSPICIOUS_REQUEST_PATTERNS: {
302
311
  path_traversal: RegExp;
303
312
  sensitive_file_probe: RegExp;
304
313
  sqli_probe: RegExp;
305
314
  xss_probe: RegExp;
306
315
  null_byte: RegExp;
307
316
  };
308
- declare function createSecuritySignalProcessor(options?: SecuritySignalProcessorOptions): SecuritySignalProcessor;
317
+ export declare function createSecuritySignalProcessor(options?: SecuritySignalProcessorOptions): SecuritySignalProcessor;
309
318
  //#endregion
310
319
  //#region src/security-heartbeat.d.ts
311
320
  /**
@@ -327,16 +336,16 @@ declare function createSecuritySignalProcessor(options?: SecuritySignalProcessor
327
336
  * heartbeat.stop();
328
337
  * ```
329
338
  */
330
- interface SecurityHeartbeatOptions {
339
+ export interface SecurityHeartbeatOptions {
331
340
  /** Beat interval in milliseconds. Default 60_000. */
332
341
  intervalMs?: number;
333
342
  /** Extra counter attributes (keep cardinality low — labels, not data). */
334
343
  attributes?: Record<string, string | number | boolean>;
335
344
  }
336
- interface SecurityHeartbeat {
345
+ export interface SecurityHeartbeat {
337
346
  stop(): void;
338
347
  }
339
- declare function startSecurityHeartbeat(options?: SecurityHeartbeatOptions): SecurityHeartbeat;
348
+ export declare function startSecurityHeartbeat(options?: SecurityHeartbeatOptions): SecurityHeartbeat;
340
349
  //#endregion
341
350
  //#region src/mcp-bridge.d.ts
342
351
  /**
@@ -344,7 +353,7 @@ declare function startSecurityHeartbeat(options?: SecurityHeartbeatOptions): Sec
344
353
  * unified `security.*` schema. Used by `autotel-mcp-instrumentation` when
345
354
  * `bridgeSecurityEvents` is enabled.
346
355
  */
347
- interface McpBridgedSecurityEvent {
356
+ export interface McpBridgedSecurityEvent {
348
357
  name: SecurityEventMetadata['name'];
349
358
  category: 'llm';
350
359
  outcome: SecurityEventMetadata['outcome'];
@@ -356,7 +365,7 @@ interface McpBridgedSecurityEvent {
356
365
  /** Extra fields ride along as span attributes; see AuditMetadataValue. */
357
366
  [key: string]: AuditMetadataValue;
358
367
  }
359
- interface McpSecurityEventBridgeOptions extends SecurityEventOptions {
368
+ export interface McpSecurityEventBridgeOptions extends SecurityEventOptions {
360
369
  /** Optional fixed audit context for bridged events. */
361
370
  ctx?: AuditContext;
362
371
  }
@@ -375,10 +384,10 @@ interface McpSecurityEventBridgeOptions extends SecurityEventOptions {
375
384
  * });
376
385
  * ```
377
386
  */
378
- declare function createMcpSecurityEventBridge(options?: McpSecurityEventBridgeOptions): (metadata: McpBridgedSecurityEvent) => void;
387
+ export declare function createMcpSecurityEventBridge(options?: McpSecurityEventBridgeOptions): (metadata: McpBridgedSecurityEvent) => void;
379
388
  //#endregion
380
389
  //#region src/index.d.ts
381
- interface AuditMetadata {
390
+ export interface AuditMetadata {
382
391
  action: string;
383
392
  resource?: string;
384
393
  actorId?: string;
@@ -392,22 +401,23 @@ interface AuditMetadata {
392
401
  * span. Scalars and scalar arrays pass through; a Date becomes an ISO string;
393
402
  * anything else nested is JSON-serialized.
394
403
  */
395
- type AuditMetadataValue = string | number | boolean | null | undefined | Date | Array<AuditMetadataValue> | {
404
+ export type AuditMetadataValue = string | number | boolean | null | undefined | Date | Array<AuditMetadataValue> | {
396
405
  [key: string]: AuditMetadataValue;
397
406
  };
398
- interface WithAuditOptions {
407
+ export interface WithAuditOptions {
399
408
  ctx?: AuditContext;
400
409
  emitNow?: boolean;
401
410
  forceKeep?: boolean;
402
411
  logger?: RequestLogger;
403
412
  /**
404
- * Behaviour when no trace context can be resolved. Defaults to `warn`
405
- * (best-effort: run un-audited, warn once). See {@link OnMissingContext}.
413
+ * Behaviour when no trace context can be resolved. Defaults to the
414
+ * configureAudit() value, else `skip` when telemetry is off and `warn`
415
+ * otherwise. See {@link OnMissingContext}.
406
416
  */
407
417
  onMissingContext?: OnMissingContext;
408
418
  }
409
- declare function forceKeepAuditEvent(ctx?: AuditContext): void;
410
- declare function setAuditAttributes(metadata: AuditMetadata, ctx?: AuditContext): void;
411
- declare function withAudit<T>(metadata: AuditMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithAuditOptions): Promise<T>;
419
+ export declare function forceKeepAuditEvent(ctx?: AuditContext): void;
420
+ export declare function setAuditAttributes(metadata: AuditMetadata, ctx?: AuditContext): void;
421
+ export declare function withAudit<T>(metadata: AuditMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithAuditOptions): Promise<T>;
412
422
  //#endregion
413
- export { AttributeValue, type AuditContext, AuditMetadata, AuditMetadataValue, AuthFailureBurstSignal, BurstOptions, ContextValue, HashIdentifierOptions, LlmActionChainSuspiciousSignal, LlmExcessiveTokensSignal, LlmSignalOptions, LlmTokenBudgetSignal, McpBridgedSecurityEvent, McpSecurityEventBridgeOptions, type OnMissingContext, SUSPICIOUS_REQUEST_PATTERNS, SecurityAttributeValue, SecurityEventCategory, SecurityEventMetadata, SecurityEventOptions, SecurityHeartbeat, SecurityHeartbeatOptions, SecurityOutcome, type SecuritySeverity, SecuritySignal, SecuritySignalProcessor, SecuritySignalProcessorOptions, SpanParentContext, SuggestedSecurityEventName, SuspiciousRequestSignal, WithAuditOptions, WithSecurityOptions, applySecurityEventAttributes, createMcpSecurityEventBridge, createSecuritySignalProcessor, forceKeepAuditEvent, hashIdentifier, securityEvent, setAuditAttributes, startSecurityHeartbeat, withAudit, withSecurity };
423
+ export type { AuditContext, OnMissingContext, SecuritySeverity };
package/dist/index.d.ts CHANGED
@@ -12,29 +12,38 @@ interface AuditContext {
12
12
  * How instrumentation should behave when no trace context is available.
13
13
  *
14
14
  * - `throw` — fail fast (original behaviour). Use when telemetry is mandatory.
15
- * - `warn` — run the wrapped handler un-audited and log one warning per action (default).
15
+ * - `warn` — run the wrapped handler un-audited and log one warning per action.
16
16
  * - `skip` — run the wrapped handler un-audited, silently.
17
17
  *
18
18
  * Telemetry is observability: a missing context should never crash the business
19
- * logic it wraps, so the default is best-effort (`warn`).
19
+ * logic it wraps, so the default is best-effort: `skip` when telemetry is off
20
+ * (no autotel init(), no tracer provider: nothing could be recorded anyway),
21
+ * `warn` otherwise.
20
22
  */
21
23
  type OnMissingContext = 'throw' | 'warn' | 'skip';
24
+ /**
25
+ * Process-wide defaults. A per-call `onMissingContext` still wins; pass
26
+ * `undefined` to restore the built-in default.
27
+ */
28
+ export declare function configureAudit(options: {
29
+ onMissingContext?: OnMissingContext;
30
+ }): void;
22
31
  //#endregion
23
32
  //#region src/security.d.ts
24
33
  /**
25
34
  * Security event categories, aligned with OWASP A09:2025
26
35
  * (Security Logging & Alerting Failures) and ASVS V7.
27
36
  */
28
- type SecurityEventCategory = 'authentication' | 'authorization' | 'data_access' | 'admin_action' | 'configuration' | 'secrets' | 'rate_limit' | 'validation' | 'supply_chain' | 'llm';
29
- type SecurityOutcome = 'success' | 'failure' | 'denied' | 'blocked' | 'error';
37
+ export type SecurityEventCategory = 'authentication' | 'authorization' | 'data_access' | 'admin_action' | 'configuration' | 'secrets' | 'rate_limit' | 'validation' | 'supply_chain' | 'llm';
38
+ export type SecurityOutcome = 'success' | 'failure' | 'denied' | 'blocked' | 'error';
30
39
  /**
31
40
  * Well-known security event names. Free-form names are allowed —
32
41
  * this union exists for autocomplete and consistency across services.
33
42
  */
34
- type SuggestedSecurityEventName = 'auth.login.success' | 'auth.login.failed' | 'auth.mfa.failed' | 'auth.session.revoked' | 'auth.password.reset' | 'auth.account.locked' | 'access.denied' | 'access.role.changed' | 'access.permission.changed' | 'access.tenant.violation' | 'admin.action' | 'config.changed' | 'secret.accessed' | 'secret.rotation.failed' | 'api_key.created' | 'api_key.revoked' | 'rate_limit.exceeded' | 'validation.failed' | 'webhook.signature.failed' | 'dependency.scan.failed' | 'llm.prompt_injection.detected' | 'llm.tool_call.denied' | 'llm.output.blocked' | 'llm.output.budget_exceeded' | 'llm.guard.triggered' | 'llm.action_chain.suspicious' | 'llm.manifest.suspicious' | 'llm.plan.risk.elevated';
43
+ export type SuggestedSecurityEventName = 'auth.login.success' | 'auth.login.failed' | 'auth.mfa.failed' | 'auth.session.revoked' | 'auth.password.reset' | 'auth.account.locked' | 'access.denied' | 'access.role.changed' | 'access.permission.changed' | 'access.tenant.violation' | 'admin.action' | 'config.changed' | 'secret.accessed' | 'secret.rotation.failed' | 'api_key.created' | 'api_key.revoked' | 'rate_limit.exceeded' | 'validation.failed' | 'webhook.signature.failed' | 'dependency.scan.failed' | 'llm.prompt_injection.detected' | 'llm.tool_call.denied' | 'llm.output.blocked' | 'llm.output.budget_exceeded' | 'llm.guard.triggered' | 'llm.action_chain.suspicious' | 'llm.manifest.suspicious' | 'llm.plan.risk.elevated';
35
44
  /** An attribute value, as OpenTelemetry allows one on a span. */
36
- type SecurityAttributeValue = string | number | boolean | string[] | number[] | boolean[];
37
- interface SecurityEventMetadata {
45
+ export type SecurityAttributeValue = string | number | boolean | string[] | number[] | boolean[];
46
+ export interface SecurityEventMetadata {
38
47
  /** Stable, dot-separated event name, e.g. `auth.login.failed`. */
39
48
  name: SuggestedSecurityEventName | (string & {});
40
49
  category: SecurityEventCategory;
@@ -51,7 +60,7 @@ interface SecurityEventMetadata {
51
60
  /** Extra fields ride along as span attributes; see AuditMetadataValue. */
52
61
  [key: string]: AuditMetadataValue;
53
62
  }
54
- interface SecurityEventOptions {
63
+ export interface SecurityEventOptions {
55
64
  ctx?: AuditContext;
56
65
  /**
57
66
  * Security events are exempt from tail sampling by default —
@@ -71,17 +80,17 @@ interface SecurityEventOptions {
71
80
  */
72
81
  metrics?: boolean;
73
82
  /**
74
- * Behaviour when no trace context can be resolved. Defaults to `warn`
75
- * (best-effort: record nothing, warn once). A dropped security event is still
76
- * better than a crashed request — but the warning makes the gap visible.
83
+ * Behaviour when no trace context can be resolved. Defaults to the
84
+ * configureAudit() value, else `skip` when telemetry is off and `warn`
85
+ * (once per event) otherwise. See {@link OnMissingContext}.
77
86
  */
78
87
  onMissingContext?: OnMissingContext;
79
88
  }
80
- type WithSecurityOptions = SecurityEventOptions;
89
+ export type WithSecurityOptions = SecurityEventOptions;
81
90
  interface SecurityAttributeSink {
82
91
  setAttribute(key: string, value: SecurityAttributeValue): void;
83
92
  }
84
- declare function applySecurityEventAttributes(sink: SecurityAttributeSink, metadata: SecurityEventMetadata, options?: Pick<SecurityEventOptions, 'forceKeep' | 'metrics'>): void;
93
+ export declare function applySecurityEventAttributes(sink: SecurityAttributeSink, metadata: SecurityEventMetadata, options?: Pick<SecurityEventOptions, 'forceKeep' | 'metrics'>): void;
85
94
  /**
86
95
  * Record a security event on the active trace and request logger.
87
96
  *
@@ -101,7 +110,7 @@ declare function applySecurityEventAttributes(sink: SecurityAttributeSink, metad
101
110
  * });
102
111
  * ```
103
112
  */
104
- declare function securityEvent(metadata: SecurityEventMetadata, options?: SecurityEventOptions): void;
113
+ export declare function securityEvent(metadata: SecurityEventMetadata, options?: SecurityEventOptions): void;
105
114
  /**
106
115
  * Wrap a security-sensitive operation. On success the event outcome is
107
116
  * recorded as given (default `success`); a thrown error records
@@ -115,8 +124,8 @@ declare function securityEvent(metadata: SecurityEventMetadata, options?: Securi
115
124
  * );
116
125
  * ```
117
126
  */
118
- declare function withSecurity<T>(metadata: SecurityEventMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithSecurityOptions): Promise<T>;
119
- interface HashIdentifierOptions {
127
+ export declare function withSecurity<T>(metadata: SecurityEventMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithSecurityOptions): Promise<T>;
128
+ export interface HashIdentifierOptions {
120
129
  /** Optional salt; use one stable per-deployment salt to defeat rainbow lookups. */
121
130
  salt?: string;
122
131
  /** Digest length in hex chars (default 16). */
@@ -128,7 +137,7 @@ interface HashIdentifierOptions {
128
137
  *
129
138
  * NOT for secrets — never log secrets in any form, hashed or not.
130
139
  */
131
- declare function hashIdentifier(value: string, options?: HashIdentifierOptions): string;
140
+ export declare function hashIdentifier(value: string, options?: HashIdentifierOptions): string;
132
141
  //#endregion
133
142
  //#region src/security-signals.d.ts
134
143
  /**
@@ -155,13 +164,13 @@ declare function hashIdentifier(value: string, options?: HashIdentifierOptions):
155
164
  * observability backend — this processor's job is to make the signals
156
165
  * exist, survive sampling, and stay queryable under a stable schema.
157
166
  */
158
- type AttributeValue = string | number | boolean | Array<null | undefined | string> | Array<null | undefined | number> | Array<null | undefined | boolean>;
167
+ export type AttributeValue = string | number | boolean | Array<null | undefined | string> | Array<null | undefined | number> | Array<null | undefined | boolean>;
159
168
  /** The parent context OTel hands a processor. This package never reads it. */
160
- interface SpanParentContext {
169
+ export interface SpanParentContext {
161
170
  getValue?: (key: symbol) => ContextValue;
162
171
  }
163
172
  /** Whatever OTel stored under a context key. This package never reads one. */
164
- type ContextValue = object | string | number | boolean | undefined;
173
+ export type ContextValue = object | string | number | boolean | undefined;
165
174
  interface MutableSpanLike {
166
175
  attributes: Record<string, AttributeValue | undefined>;
167
176
  spanContext?: {
@@ -175,20 +184,20 @@ interface ReadableSpanLike {
175
184
  traceId: string;
176
185
  };
177
186
  }
178
- interface SecuritySignalProcessor {
187
+ export interface SecuritySignalProcessor {
179
188
  onStart(span: MutableSpanLike, parentContext?: SpanParentContext): void;
180
189
  onEnd(span: ReadableSpanLike): void;
181
190
  shutdown(): Promise<void>;
182
191
  forceFlush(): Promise<void>;
183
192
  }
184
- interface SuspiciousRequestSignal {
193
+ export interface SuspiciousRequestSignal {
185
194
  signal: 'suspicious_request';
186
195
  /** Which pattern matched, e.g. `path_traversal`. */
187
196
  pattern: string;
188
197
  /** The matched request path/URL (as found on the span). */
189
198
  target: string;
190
199
  }
191
- interface AuthFailureBurstSignal {
200
+ export interface AuthFailureBurstSignal {
192
201
  signal: 'auth_failure_burst';
193
202
  /** Value of the configured key attribute (e.g. client address). */
194
203
  key: string;
@@ -197,14 +206,14 @@ interface AuthFailureBurstSignal {
197
206
  windowMs: number;
198
207
  status: number;
199
208
  }
200
- interface LlmExcessiveTokensSignal {
209
+ export interface LlmExcessiveTokensSignal {
201
210
  signal: 'llm_excessive_tokens';
202
211
  /** Total tokens consumed by the single LLM call. */
203
212
  tokens: number;
204
213
  maxTokens: number;
205
214
  model?: string;
206
215
  }
207
- interface LlmTokenBudgetSignal {
216
+ export interface LlmTokenBudgetSignal {
208
217
  signal: 'llm_token_budget_exceeded';
209
218
  /** Value of the configured key attribute (e.g. end-user id). */
210
219
  key: string;
@@ -213,7 +222,7 @@ interface LlmTokenBudgetSignal {
213
222
  budget: number;
214
223
  windowMs: number;
215
224
  }
216
- interface LlmActionChainSuspiciousSignal {
225
+ export interface LlmActionChainSuspiciousSignal {
217
226
  signal: 'llm_action_chain_suspicious';
218
227
  /** Trace where the suspicious chain was observed. */
219
228
  traceId: string;
@@ -223,8 +232,8 @@ interface LlmActionChainSuspiciousSignal {
223
232
  elapsedMs: number;
224
233
  untrustedTool?: string;
225
234
  }
226
- type SecuritySignal = SuspiciousRequestSignal | AuthFailureBurstSignal | LlmExcessiveTokensSignal | LlmTokenBudgetSignal | LlmActionChainSuspiciousSignal;
227
- interface BurstOptions {
235
+ export type SecuritySignal = SuspiciousRequestSignal | AuthFailureBurstSignal | LlmExcessiveTokensSignal | LlmTokenBudgetSignal | LlmActionChainSuspiciousSignal;
236
+ export interface BurstOptions {
228
237
  /** HTTP statuses counted toward a burst. Default `[401, 403]`. */
229
238
  statuses?: number[];
230
239
  /** Denied responses within the window that trigger a signal. Default 10. */
@@ -239,7 +248,7 @@ interface BurstOptions {
239
248
  /** Max distinct clients tracked (oldest evicted). Default 10_000. */
240
249
  maxKeys?: number;
241
250
  }
242
- interface LlmSignalOptions {
251
+ export interface LlmSignalOptions {
243
252
  /**
244
253
  * Single-call token ceiling (`gen_ai.usage.total_tokens`, or input+output).
245
254
  * Default 100_000. Pass `false` to disable the per-call check.
@@ -263,7 +272,7 @@ interface LlmSignalOptions {
263
272
  maxKeys?: number;
264
273
  };
265
274
  }
266
- interface SecuritySignalProcessorOptions {
275
+ export interface SecuritySignalProcessorOptions {
267
276
  /** Flag suspicious request paths on span start. Default true. */
268
277
  detectSuspiciousRequests?: boolean;
269
278
  /** Additional name → pattern pairs checked against the request target. */
@@ -298,14 +307,14 @@ interface SecuritySignalProcessorOptions {
298
307
  * Conservative request-target patterns. Tuned for scanner/probe traffic —
299
308
  * high signal, low false-positive — not as a WAF. Extend via `extraPatterns`.
300
309
  */
301
- declare const SUSPICIOUS_REQUEST_PATTERNS: {
310
+ export declare const SUSPICIOUS_REQUEST_PATTERNS: {
302
311
  path_traversal: RegExp;
303
312
  sensitive_file_probe: RegExp;
304
313
  sqli_probe: RegExp;
305
314
  xss_probe: RegExp;
306
315
  null_byte: RegExp;
307
316
  };
308
- declare function createSecuritySignalProcessor(options?: SecuritySignalProcessorOptions): SecuritySignalProcessor;
317
+ export declare function createSecuritySignalProcessor(options?: SecuritySignalProcessorOptions): SecuritySignalProcessor;
309
318
  //#endregion
310
319
  //#region src/security-heartbeat.d.ts
311
320
  /**
@@ -327,16 +336,16 @@ declare function createSecuritySignalProcessor(options?: SecuritySignalProcessor
327
336
  * heartbeat.stop();
328
337
  * ```
329
338
  */
330
- interface SecurityHeartbeatOptions {
339
+ export interface SecurityHeartbeatOptions {
331
340
  /** Beat interval in milliseconds. Default 60_000. */
332
341
  intervalMs?: number;
333
342
  /** Extra counter attributes (keep cardinality low — labels, not data). */
334
343
  attributes?: Record<string, string | number | boolean>;
335
344
  }
336
- interface SecurityHeartbeat {
345
+ export interface SecurityHeartbeat {
337
346
  stop(): void;
338
347
  }
339
- declare function startSecurityHeartbeat(options?: SecurityHeartbeatOptions): SecurityHeartbeat;
348
+ export declare function startSecurityHeartbeat(options?: SecurityHeartbeatOptions): SecurityHeartbeat;
340
349
  //#endregion
341
350
  //#region src/mcp-bridge.d.ts
342
351
  /**
@@ -344,7 +353,7 @@ declare function startSecurityHeartbeat(options?: SecurityHeartbeatOptions): Sec
344
353
  * unified `security.*` schema. Used by `autotel-mcp-instrumentation` when
345
354
  * `bridgeSecurityEvents` is enabled.
346
355
  */
347
- interface McpBridgedSecurityEvent {
356
+ export interface McpBridgedSecurityEvent {
348
357
  name: SecurityEventMetadata['name'];
349
358
  category: 'llm';
350
359
  outcome: SecurityEventMetadata['outcome'];
@@ -356,7 +365,7 @@ interface McpBridgedSecurityEvent {
356
365
  /** Extra fields ride along as span attributes; see AuditMetadataValue. */
357
366
  [key: string]: AuditMetadataValue;
358
367
  }
359
- interface McpSecurityEventBridgeOptions extends SecurityEventOptions {
368
+ export interface McpSecurityEventBridgeOptions extends SecurityEventOptions {
360
369
  /** Optional fixed audit context for bridged events. */
361
370
  ctx?: AuditContext;
362
371
  }
@@ -375,10 +384,10 @@ interface McpSecurityEventBridgeOptions extends SecurityEventOptions {
375
384
  * });
376
385
  * ```
377
386
  */
378
- declare function createMcpSecurityEventBridge(options?: McpSecurityEventBridgeOptions): (metadata: McpBridgedSecurityEvent) => void;
387
+ export declare function createMcpSecurityEventBridge(options?: McpSecurityEventBridgeOptions): (metadata: McpBridgedSecurityEvent) => void;
379
388
  //#endregion
380
389
  //#region src/index.d.ts
381
- interface AuditMetadata {
390
+ export interface AuditMetadata {
382
391
  action: string;
383
392
  resource?: string;
384
393
  actorId?: string;
@@ -392,22 +401,23 @@ interface AuditMetadata {
392
401
  * span. Scalars and scalar arrays pass through; a Date becomes an ISO string;
393
402
  * anything else nested is JSON-serialized.
394
403
  */
395
- type AuditMetadataValue = string | number | boolean | null | undefined | Date | Array<AuditMetadataValue> | {
404
+ export type AuditMetadataValue = string | number | boolean | null | undefined | Date | Array<AuditMetadataValue> | {
396
405
  [key: string]: AuditMetadataValue;
397
406
  };
398
- interface WithAuditOptions {
407
+ export interface WithAuditOptions {
399
408
  ctx?: AuditContext;
400
409
  emitNow?: boolean;
401
410
  forceKeep?: boolean;
402
411
  logger?: RequestLogger;
403
412
  /**
404
- * Behaviour when no trace context can be resolved. Defaults to `warn`
405
- * (best-effort: run un-audited, warn once). See {@link OnMissingContext}.
413
+ * Behaviour when no trace context can be resolved. Defaults to the
414
+ * configureAudit() value, else `skip` when telemetry is off and `warn`
415
+ * otherwise. See {@link OnMissingContext}.
406
416
  */
407
417
  onMissingContext?: OnMissingContext;
408
418
  }
409
- declare function forceKeepAuditEvent(ctx?: AuditContext): void;
410
- declare function setAuditAttributes(metadata: AuditMetadata, ctx?: AuditContext): void;
411
- declare function withAudit<T>(metadata: AuditMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithAuditOptions): Promise<T>;
419
+ export declare function forceKeepAuditEvent(ctx?: AuditContext): void;
420
+ export declare function setAuditAttributes(metadata: AuditMetadata, ctx?: AuditContext): void;
421
+ export declare function withAudit<T>(metadata: AuditMetadata, fn: (ctx: AuditContext, logger: RequestLogger) => T | Promise<T>, options?: WithAuditOptions): Promise<T>;
412
422
  //#endregion
413
- export { AttributeValue, type AuditContext, AuditMetadata, AuditMetadataValue, AuthFailureBurstSignal, BurstOptions, ContextValue, HashIdentifierOptions, LlmActionChainSuspiciousSignal, LlmExcessiveTokensSignal, LlmSignalOptions, LlmTokenBudgetSignal, McpBridgedSecurityEvent, McpSecurityEventBridgeOptions, type OnMissingContext, SUSPICIOUS_REQUEST_PATTERNS, SecurityAttributeValue, SecurityEventCategory, SecurityEventMetadata, SecurityEventOptions, SecurityHeartbeat, SecurityHeartbeatOptions, SecurityOutcome, type SecuritySeverity, SecuritySignal, SecuritySignalProcessor, SecuritySignalProcessorOptions, SpanParentContext, SuggestedSecurityEventName, SuspiciousRequestSignal, WithAuditOptions, WithSecurityOptions, applySecurityEventAttributes, createMcpSecurityEventBridge, createSecuritySignalProcessor, forceKeepAuditEvent, hashIdentifier, securityEvent, setAuditAttributes, startSecurityHeartbeat, withAudit, withSecurity };
423
+ export type { AuditContext, OnMissingContext, SecuritySeverity };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { AUTOTEL_SAMPLING_TAIL_EVALUATED, AUTOTEL_SAMPLING_TAIL_KEEP, REDACTOR_PATTERNS, createCounter, createNoopRequestLogger, forceKeep, getRequestLoggerSafe, getTraceContext, otelTrace } from "autotel";
1
+ import { AUTOTEL_SAMPLING_TAIL_EVALUATED, AUTOTEL_SAMPLING_TAIL_KEEP, REDACTOR_PATTERNS, createCounter, createNoopRequestLogger, forceKeep, getRequestLoggerSafe, getTraceContext, hasTracerProvider, isInitialized, otelTrace } from "autotel";
2
2
  import { createHash } from "node:crypto";
3
3
  import { HTTP_STATUS_ATTRIBUTES, SECURITY_ATTR, SECURITY_DENIED_STATUSES, SECURITY_METRICS, escalateSecuritySeverity } from "autotel/security-schema";
4
4
 
@@ -25,6 +25,18 @@ function resolveContextSafe(ctx) {
25
25
  setAttributes: (attrs) => span.setAttributes(attrs)
26
26
  };
27
27
  }
28
+ let defaultOnMissingContext;
29
+ /**
30
+ * Process-wide defaults. A per-call `onMissingContext` still wins; pass
31
+ * `undefined` to restore the built-in default.
32
+ */
33
+ function configureAudit(options) {
34
+ defaultOnMissingContext = options.onMissingContext;
35
+ }
36
+ /** Per-call option, then configureAudit(), then skip-if-telemetry-off-else-warn. */
37
+ function resolveOnMissingContext(explicit) {
38
+ return explicit ?? defaultOnMissingContext ?? (isInitialized() || hasTracerProvider() ? "warn" : "skip");
39
+ }
28
40
  /** A no-op {@link AuditContext} whose attribute setters do nothing. */
29
41
  function noopAuditContext() {
30
42
  return {
@@ -165,7 +177,7 @@ function securityEvent(metadata, options = {}) {
165
177
  const traceCtx = resolveContextSafe(options.ctx);
166
178
  if (options.metrics !== false) countSecurityEvent(metadata);
167
179
  if (!traceCtx) {
168
- const mode = options.onMissingContext ?? "warn";
180
+ const mode = resolveOnMissingContext(options.onMissingContext);
169
181
  if (mode === "throw") throw new Error(MISSING_CONTEXT_MESSAGE);
170
182
  if (mode === "warn") warnMissingContextOnce(metadata.name);
171
183
  return;
@@ -597,7 +609,7 @@ function setAuditAttributes(metadata, ctx) {
597
609
  async function withAudit(metadata, fn, options = {}) {
598
610
  const traceCtx = resolveContextSafe(options.ctx);
599
611
  if (!traceCtx) {
600
- const mode = options.onMissingContext ?? "warn";
612
+ const mode = resolveOnMissingContext(options.onMissingContext);
601
613
  if (mode === "throw") throw new Error(MISSING_CONTEXT_MESSAGE);
602
614
  if (mode === "warn") warnMissingContextOnce(metadata.action);
603
615
  return fn(noopAuditContext(), options.logger ?? createNoopRequestLogger());
@@ -606,7 +618,7 @@ async function withAudit(metadata, fn, options = {}) {
606
618
  setAuditAttributes(metadata, traceCtx);
607
619
  let logger = options.logger ?? getRequestLoggerSafe() ?? void 0;
608
620
  if (!logger) {
609
- if ((options.onMissingContext ?? "warn") === "warn") warnMissingLoggerOnce(metadata.action);
621
+ if (resolveOnMissingContext(options.onMissingContext) === "warn") warnMissingLoggerOnce(metadata.action);
610
622
  logger = createNoopRequestLogger();
611
623
  }
612
624
  logger.set({ audit: {
@@ -637,4 +649,4 @@ async function withAudit(metadata, fn, options = {}) {
637
649
  }
638
650
 
639
651
  //#endregion
640
- export { SUSPICIOUS_REQUEST_PATTERNS, applySecurityEventAttributes, createMcpSecurityEventBridge, createSecuritySignalProcessor, forceKeepAuditEvent, hashIdentifier, securityEvent, setAuditAttributes, startSecurityHeartbeat, withAudit, withSecurity };
652
+ export { SUSPICIOUS_REQUEST_PATTERNS, applySecurityEventAttributes, configureAudit, createMcpSecurityEventBridge, createSecuritySignalProcessor, forceKeepAuditEvent, hashIdentifier, securityEvent, setAuditAttributes, startSecurityHeartbeat, withAudit, withSecurity };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "autotel-audit",
3
- "version": "1.1.5",
3
+ "version": "1.2.0",
4
4
  "description": "Audit-focused helpers for Autotel (force-keep + structured audit instrumentation)",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -29,18 +29,13 @@
29
29
  "author": "Jag Reehal <jag@jagreehal.com> (https://jagreehal.com)",
30
30
  "license": "Apache-2.0",
31
31
  "dependencies": {
32
- "autotel": "7.8.0"
32
+ "autotel": "7.10.0"
33
33
  },
34
34
  "devDependencies": {
35
- "@types/node": "^26.1.2",
36
- "@typescript-eslint/eslint-plugin": "^8.65.0",
37
- "@typescript-eslint/parser": "^8.65.0",
38
- "eslint-config-prettier": "^10.1.8",
39
- "eslint-plugin-unicorn": "^64.0.0",
40
- "tsdown": "^0.22.14",
41
- "typescript": "^6.0.3",
42
- "typescript-eslint": "^8.65.0",
43
- "vitest": "^4.1.10"
35
+ "@types/node": "^26.6.3",
36
+ "tsdown": "^0.23.0",
37
+ "typescript": "^7.0.2",
38
+ "vitest": "^5.0.2"
44
39
  },
45
40
  "repository": {
46
41
  "type": "git",
@@ -54,7 +49,7 @@
54
49
  "scripts": {
55
50
  "build": "tsdown",
56
51
  "dev": "tsdown --watch",
57
- "lint": "eslint src/**/*.ts",
52
+ "lint": "oxlint -c oxlint.json --disable-nested-config src",
58
53
  "type-check": "tsc --noEmit",
59
54
  "test": "vitest run"
60
55
  }