@autter/runtime-node 1.5.0 → 1.6.1

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/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
- import { b as RedactOptions, c as Redactor$1, d as RuntimeLogLevel, e as RuntimeOperationKind, f as RuntimeSink, F as FileSinkOptions, g as RuntimeLogContext, a as RuntimeOutcome, h as RuntimeCarrier } from './sinks-RFV76lF1.cjs';
3
- export { i as CODE_PATTERN, j as ClientErrorBody, k as ConsoleSinkOptions, O as OtlpSinkOptions, l as RuntimeError, n as RuntimeErrorCatalog, o as RuntimeErrorDefinition, p as RuntimeErrorExtras, q as RuntimeErrorFactory, r as RuntimeErrorLike, s as RuntimeErrorOptions, R as RuntimeEvent, t as RuntimeLogContextValue, u as RuntimeSinkContext, v as consoleSink, w as defineRuntimeErrors, x as errorAttributes, y as fileSink, z as isRuntimeErrorLike, A as otlpSink, B as redactAttributes, D as redactText, E as toClientError } from './sinks-RFV76lF1.cjs';
2
+ import { b as RedactOptions, c as Redactor$1, d as RuntimeLogLevel, e as RuntimeOperationKind, f as RuntimeSink, F as FileSinkOptions, g as RuntimeLogContext, a as RuntimeOutcome, h as RuntimeCarrier, B as BreadcrumbInput } from './sinks-CPGDyfU8.cjs';
3
+ export { i as Breadcrumb, j as BreadcrumbLevel, k as BreadcrumbType, l as CODE_PATTERN, n as ClientErrorBody, o as ConsoleSinkOptions, O as OtlpSinkOptions, p as RuntimeError, q as RuntimeErrorCatalog, r as RuntimeErrorDefinition, s as RuntimeErrorExtras, t as RuntimeErrorFactory, u as RuntimeErrorLike, v as RuntimeErrorOptions, R as RuntimeEvent, w as RuntimeLogContextValue, x as RuntimeSinkContext, y as consoleSink, z as defineRuntimeErrors, A as errorAttributes, D as fileSink, E as isRuntimeErrorLike, G as otlpSink, H as redactAttributes, I as redactText, J as toClientError } from './sinks-CPGDyfU8.cjs';
4
4
  import { Attributes } from '@opentelemetry/api';
5
5
 
6
6
  /**
@@ -242,8 +242,23 @@ interface AutterServerOptions {
242
242
  metricIntervalMs?: number;
243
243
  /** Collect RSS, heap, limit, and GC signals per process instance. Default true. */
244
244
  memoryMetrics?: boolean;
245
- /** Capture crashing exceptions via process.uncaughtExceptionMonitor (default true). */
245
+ /**
246
+ * Capture crashing exceptions via process.uncaughtExceptionMonitor, and
247
+ * unhandled promise rejections (see `captureUnhandledRejections`).
248
+ * Default true; false turns both off.
249
+ */
246
250
  captureGlobalErrors?: boolean;
251
+ /**
252
+ * Record unhandled promise rejections as errors (severity "error",
253
+ * `autter.unhandled_rejection: true`). Never changes whether the process
254
+ * crashes: when Node would have crashed (the default
255
+ * `--unhandled-rejections=throw` mode and no other `unhandledRejection`
256
+ * listener), the rejection is rethrown on the next tick, so the process
257
+ * still exits with code 1 and the crash is recorded as fatal like any
258
+ * other. False restores 1.5.0 behaviour: a rejection is only seen when it
259
+ * crashes the process. Default true.
260
+ */
261
+ captureUnhandledRejections?: boolean;
247
262
  /**
248
263
  * Flush all exporters when the process exits (`beforeExit`, SIGINT,
249
264
  * SIGTERM) so a forgotten `shutdown()` doesn't silently drop buffered
@@ -266,6 +281,18 @@ interface AutterServerOptions {
266
281
  * Default true.
267
282
  */
268
283
  redactAttributes?: boolean | RedactOptions;
284
+ /**
285
+ * Query strings never leave the process with their values. Every span
286
+ * (any instrumentation, Next.js's own included) is exported with
287
+ * `http.target`, `http.url` and `url.full` cut at the `?`, `url.query`
288
+ * reduced to its parameter names (`email=[redacted]&page=[redacted]`,
289
+ * added when only the URL had the query) and the query dropped from span
290
+ * names. List parameters whose values are safe to keep in `url.query`,
291
+ * such as pagination or sorting: `keepQueryParams: ["page", "sort"]`
292
+ * (exact names; kept values are still scrubbed by `redactAttributes`).
293
+ * Applies even with `redactAttributes: false`. Default `[]`.
294
+ */
295
+ keepQueryParams?: string[];
269
296
  /**
270
297
  * Verbose lifecycle logging to stderr: "exported N spans", flushes and
271
298
  * auto-flush activity — handy while wiring the SDK up. Also enabled by
@@ -344,7 +371,12 @@ interface TrackedLlmCall extends LlmCallInfo, LlmUsage {
344
371
  error?: unknown;
345
372
  }
346
373
  interface AutterServer {
347
- /** Report a handled exception. Always recorded (never sampled out). */
374
+ /**
375
+ * Report a handled exception. Always recorded (never sampled out).
376
+ * `attributes.fingerprint` (a string or up to 10 strings) groups every
377
+ * error that carries it into one issue (ingester 1.6.0+); it is sent as
378
+ * `autter.fingerprint` on the exception event, not as a span attribute.
379
+ */
348
380
  captureException(error: unknown, attributes?: Attributes): void;
349
381
  /**
350
382
  * Report a warning (or info) without an exception — deprecated code
@@ -566,6 +598,17 @@ interface RuntimeRequestOptions {
566
598
  /** Receives the log flush promise after the response (serverless `waitUntil`). */
567
599
  waitUntil?: (promise: Promise<unknown>) => void;
568
600
  }
601
+ /**
602
+ * Report an error that reached a request boundary — a framework error hook,
603
+ * an exception filter, Next.js `onRequestError`. Unlike `captureException`
604
+ * it reports each error once (an error a handler or another hook already
605
+ * captured is skipped), and it records the exception, with its stack, on the
606
+ * request's HTTP server span even when a child span is active, so the failed
607
+ * request and its exception stay one issue. When the error was already
608
+ * captured (e.g. by `withRuntimeRequest`), `attributes` still go on the
609
+ * request span, without a second exception.
610
+ */
611
+ declare function captureRequestError(error: unknown, attributes?: Attributes): void;
569
612
  /**
570
613
  * Express / Connect middleware. Mount it early (before routers; after body
571
614
  * parsers is fine too):
@@ -605,6 +648,101 @@ declare function autterFastify(fastify: FastifyLikeInstance, options: AutterRequ
605
648
  */
606
649
  declare function withRuntimeRequest<A extends unknown[]>(handler: (request: Request, ...rest: A) => Response | Promise<Response>, options?: RuntimeRequestOptions): (request: Request, ...rest: A) => Promise<Response>;
607
650
 
651
+ /**
652
+ * Server error hooks for Express, Fastify and Koa. Each records the error,
653
+ * with its stack, on the request's span through `captureException`, then
654
+ * lets the framework carry on exactly as before (same error, same response).
655
+ * Without them a thrown error only reaches Autter as the 500 the framework
656
+ * answers with: a stackless `HttpServerError` grouped by route.
657
+ *
658
+ * No framework is a dependency: the request/reply shapes are structural.
659
+ */
660
+ interface AutterErrorHandlerOptions {
661
+ /**
662
+ * Which errors to report. Default: errors with status ≥ 500 (or no
663
+ * status), RuntimeErrors and any error with a valid code — so 4xx errors
664
+ * such as `ctx.throw(404)` or validation failures stay out of your issues.
665
+ * `true` reports every error; a predicate decides per error.
666
+ */
667
+ capture?: boolean | ((error: unknown) => boolean);
668
+ }
669
+ /**
670
+ * Express (4/5) / Connect error middleware that reports the error and calls
671
+ * `next(err)` unchanged. Mount it after your routes and before your own
672
+ * error handlers:
673
+ *
674
+ * app.use(autterErrorHandler());
675
+ * app.use((err, req, res, next) => res.status(500).send("…")); // yours
676
+ *
677
+ * (`autterErrorResponse()` reports too, and also answers the request.)
678
+ */
679
+ declare function autterErrorHandler(options?: AutterErrorHandlerOptions): (error: unknown, req: IncomingMessage, _res: ServerResponse, next: (error?: unknown) => void) => void;
680
+ interface FastifyHookInstance {
681
+ addHook(name: string, hook: (...args: never[]) => unknown): unknown;
682
+ }
683
+ /**
684
+ * Fastify (4/5) `onError` hook that reports the error; Fastify's error
685
+ * handler still builds the response. Register it as a plugin, or call it on
686
+ * the instance directly:
687
+ *
688
+ * app.register(autterFastifyErrors); // or: autterFastifyErrors(app)
689
+ * app.register(autterFastifyErrors, { capture: true });
690
+ *
691
+ * It skips plugin encapsulation, so it covers every route. `autterFastify`
692
+ * (request summaries) already includes the same hook; you don't need both.
693
+ */
694
+ declare function autterFastifyErrors(fastify: FastifyHookInstance, options?: AutterErrorHandlerOptions, done?: (error?: Error) => void): void;
695
+ interface KoaContextLike {
696
+ req?: IncomingMessage;
697
+ }
698
+ /**
699
+ * Koa (2/3) middleware that reports errors thrown downstream and rethrows
700
+ * them, so Koa's own error handling (and `app.on("error")`) is unchanged.
701
+ * Mount it first:
702
+ *
703
+ * app.use(autterKoa());
704
+ */
705
+ declare function autterKoa(options?: AutterErrorHandlerOptions): (ctx: KoaContextLike, next: () => Promise<unknown>) => Promise<void>;
706
+
707
+ /**
708
+ * Unhandled promise rejections, recorded without changing whether the
709
+ * process crashes.
710
+ *
711
+ * Node's `--unhandled-rejections` mode decides what an unhandled rejection
712
+ * does, and most modes behave differently once ANY `unhandledRejection`
713
+ * listener exists:
714
+ *
715
+ * mode no listener with a listener
716
+ * throw (default) crash (uncaught exception) listener only — no crash
717
+ * strict crash, then the listener same
718
+ * warn warning listener + warning
719
+ * warn-with-error-code warning + exit code 1 listener only
720
+ * none nothing listener only
721
+ *
722
+ * Adding our listener would therefore silently stop the default crash. So
723
+ * when ours is the only listener we do what Node would have done:
724
+ *
725
+ * - throw: rethrow the reason (or Node's `UnhandledPromiseRejection`
726
+ * wrapper for a non-error reason) on the next tick. The process crashes
727
+ * with exit code 1 as before, and `uncaughtExceptionMonitor` records it
728
+ * as a crash (fatal), exactly as it did without this listener. The one
729
+ * visible difference: `uncaughtException` listeners and the monitor
730
+ * receive origin `"uncaughtException"` instead of `"unhandledRejection"`.
731
+ * - warn-with-error-code: print Node's warning and set `process.exitCode = 1`.
732
+ * - strict: no listener at all — Node raises the rejection as an uncaught
733
+ * exception first, which the crash monitor already records.
734
+ *
735
+ * Everything else — the app has its own listener (it decides what happens),
736
+ * or the mode never crashes — is recorded as an error (severity "error", not
737
+ * fatal) with `autter.unhandled_rejection: true`.
738
+ */
739
+ type UnhandledRejectionsMode = "throw" | "strict" | "warn" | "warn-with-error-code" | "none";
740
+ /**
741
+ * Node's effective `--unhandled-rejections` mode: `NODE_OPTIONS` first, then
742
+ * the command line (which wins), last occurrence wins. Default `"throw"`.
743
+ */
744
+ declare function unhandledRejectionsMode(execArgv?: readonly string[], nodeOptions?: string | undefined): UnhandledRejectionsMode;
745
+
608
746
  /**
609
747
  * Logger-only mode: requests, operations, coded errors, sinks and enrichers
610
748
  * WITHOUT starting the OpenTelemetry NodeSDK. For apps that already run
@@ -629,8 +767,12 @@ interface AutterLoggingOptions {
629
767
  logging?: RuntimeLoggingOptions;
630
768
  /** Same semantics as initAutterServer. Default true. */
631
769
  redactAttributes?: boolean | RedactOptions;
632
- /** Capture crashes via process.uncaughtExceptionMonitor. Default true. */
770
+ /** Capture crashes via process.uncaughtExceptionMonitor, and unhandled
771
+ * rejections (`captureUnhandledRejections`). Default true. */
633
772
  captureGlobalErrors?: boolean;
773
+ /** Same semantics as initAutterServer: record unhandled rejections as
774
+ * errors without changing whether the process crashes. Default true. */
775
+ captureUnhandledRejections?: boolean;
634
776
  /** Flush records on beforeExit/SIGINT/SIGTERM. Default true. */
635
777
  autoFlush?: boolean;
636
778
  debug?: boolean;
@@ -679,7 +821,9 @@ declare function enrichDeployment(env?: Record<string, string | undefined>): Run
679
821
  * Adding a feature: append an entry to compat-manifest.json with the first
680
822
  * ingester release that handles it, the migrations it writes to, its route
681
823
  * (if it has its own), and the first SDK release that emits it. The
682
- * consistency test in compat.test.ts checks ids, migrations and routes.
824
+ * consistency test in compat.test.ts checks ids, migrations and routes, and
825
+ * that no version is ahead of its package's package.json: a feature for the
826
+ * next release bumps the packages it names in the same change.
683
827
  */
684
828
  interface CompatFeature {
685
829
  id: string;
@@ -811,4 +955,13 @@ interface DoctorReport {
811
955
  }
812
956
  declare function runDoctor(options?: DoctorOptions): Promise<DoctorReport>;
813
957
 
814
- export { type AutoFlushHandle, type AutoFlushOptions, type AutterErrorResponseOptions, type AutterLogging, type AutterLoggingOptions, type AutterRequestsOptions, type AutterServer, type AutterServerOptions, type AutterSeverity, COMPAT_MANIFEST, type CompatIssue, type DoctorOptions, type DoctorReport, FileSinkOptions, type FlushTarget, INGESTER_VERSION_HEADER, type IngesterCompatInfo, type InstrumentLlmOptions, type LlmCallHandle, type LlmCallInfo, type LlmUsage, RedactOptions, type RelayOptions, RuntimeCarrier, type RuntimeContextHandle, type RuntimeEnrichContext, type RuntimeEnrichEvent, type RuntimeEnricher, RuntimeLogContext, RuntimeLogLevel, type RuntimeLoggingOptions, type RuntimeOperation, RuntimeOperationKind, type RuntimeOperationOptions, RuntimeOutcome, type RuntimeRequestOptions, RuntimeSink, SDK_IDENTITY, type SafeCapture, type SdkIdentity, type TrackedLlmCall, autterErrorResponse, autterFastify, autterRequests, captureException, captureMessage, createBrowserRelayFetchHandler, createBrowserRelayHandler, createRuntimeLogger, emitLlmSelftestTrace, enrichDeployment, enrichEdgeGeo, enrichRequestSize, enrichUserAgent, evaluateCompat, fetchIngesterCompat, flushRuntimeLogs, initAutterLogging, initAutterServer, installAutterAutoFlush, instrumentLlmClient, makeSafeCapture, reportOutcome, runDoctor, runInBackground, runtimeContext, runtimeLogStats, runtimeLogger, sanitizeBrowserPayload, startCaughtExceptionSampler, trackLlmCall, withLlmCall, withProcessSpan, withRuntimeOperation, withRuntimeRequest };
958
+ /**
959
+ * Record a step (type "custom" unless you say otherwise) on the current
960
+ * request. The next exception captured in it carries the last 30. Message
961
+ * and data are scrubbed with your `redact` settings. Never throws.
962
+ *
963
+ * addBreadcrumb({ message: "Loaded cart", data: { items: 3 } });
964
+ */
965
+ declare function addBreadcrumb(input: BreadcrumbInput): void;
966
+
967
+ export { type AutoFlushHandle, type AutoFlushOptions, type AutterErrorHandlerOptions, type AutterErrorResponseOptions, type AutterLogging, type AutterLoggingOptions, type AutterRequestsOptions, type AutterServer, type AutterServerOptions, type AutterSeverity, BreadcrumbInput, COMPAT_MANIFEST, type CompatIssue, type DoctorOptions, type DoctorReport, FileSinkOptions, type FlushTarget, INGESTER_VERSION_HEADER, type IngesterCompatInfo, type InstrumentLlmOptions, type LlmCallHandle, type LlmCallInfo, type LlmUsage, RedactOptions, type RelayOptions, RuntimeCarrier, type RuntimeContextHandle, type RuntimeEnrichContext, type RuntimeEnrichEvent, type RuntimeEnricher, RuntimeLogContext, RuntimeLogLevel, type RuntimeLoggingOptions, type RuntimeOperation, RuntimeOperationKind, type RuntimeOperationOptions, RuntimeOutcome, type RuntimeRequestOptions, RuntimeSink, SDK_IDENTITY, type SafeCapture, type SdkIdentity, type TrackedLlmCall, type UnhandledRejectionsMode, addBreadcrumb, autterErrorHandler, autterErrorResponse, autterFastify, autterFastifyErrors, autterKoa, autterRequests, captureException, captureMessage, captureRequestError, createBrowserRelayFetchHandler, createBrowserRelayHandler, createRuntimeLogger, emitLlmSelftestTrace, enrichDeployment, enrichEdgeGeo, enrichRequestSize, enrichUserAgent, evaluateCompat, fetchIngesterCompat, flushRuntimeLogs, initAutterLogging, initAutterServer, installAutterAutoFlush, instrumentLlmClient, makeSafeCapture, reportOutcome, runDoctor, runInBackground, runtimeContext, runtimeLogStats, runtimeLogger, sanitizeBrowserPayload, startCaughtExceptionSampler, trackLlmCall, unhandledRejectionsMode, withLlmCall, withProcessSpan, withRuntimeOperation, withRuntimeRequest };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { IncomingMessage, ServerResponse } from 'node:http';
2
- import { b as RedactOptions, c as Redactor$1, d as RuntimeLogLevel, e as RuntimeOperationKind, f as RuntimeSink, F as FileSinkOptions, g as RuntimeLogContext, a as RuntimeOutcome, h as RuntimeCarrier } from './sinks-RFV76lF1.js';
3
- export { i as CODE_PATTERN, j as ClientErrorBody, k as ConsoleSinkOptions, O as OtlpSinkOptions, l as RuntimeError, n as RuntimeErrorCatalog, o as RuntimeErrorDefinition, p as RuntimeErrorExtras, q as RuntimeErrorFactory, r as RuntimeErrorLike, s as RuntimeErrorOptions, R as RuntimeEvent, t as RuntimeLogContextValue, u as RuntimeSinkContext, v as consoleSink, w as defineRuntimeErrors, x as errorAttributes, y as fileSink, z as isRuntimeErrorLike, A as otlpSink, B as redactAttributes, D as redactText, E as toClientError } from './sinks-RFV76lF1.js';
2
+ import { b as RedactOptions, c as Redactor$1, d as RuntimeLogLevel, e as RuntimeOperationKind, f as RuntimeSink, F as FileSinkOptions, g as RuntimeLogContext, a as RuntimeOutcome, h as RuntimeCarrier, B as BreadcrumbInput } from './sinks-CPGDyfU8.js';
3
+ export { i as Breadcrumb, j as BreadcrumbLevel, k as BreadcrumbType, l as CODE_PATTERN, n as ClientErrorBody, o as ConsoleSinkOptions, O as OtlpSinkOptions, p as RuntimeError, q as RuntimeErrorCatalog, r as RuntimeErrorDefinition, s as RuntimeErrorExtras, t as RuntimeErrorFactory, u as RuntimeErrorLike, v as RuntimeErrorOptions, R as RuntimeEvent, w as RuntimeLogContextValue, x as RuntimeSinkContext, y as consoleSink, z as defineRuntimeErrors, A as errorAttributes, D as fileSink, E as isRuntimeErrorLike, G as otlpSink, H as redactAttributes, I as redactText, J as toClientError } from './sinks-CPGDyfU8.js';
4
4
  import { Attributes } from '@opentelemetry/api';
5
5
 
6
6
  /**
@@ -242,8 +242,23 @@ interface AutterServerOptions {
242
242
  metricIntervalMs?: number;
243
243
  /** Collect RSS, heap, limit, and GC signals per process instance. Default true. */
244
244
  memoryMetrics?: boolean;
245
- /** Capture crashing exceptions via process.uncaughtExceptionMonitor (default true). */
245
+ /**
246
+ * Capture crashing exceptions via process.uncaughtExceptionMonitor, and
247
+ * unhandled promise rejections (see `captureUnhandledRejections`).
248
+ * Default true; false turns both off.
249
+ */
246
250
  captureGlobalErrors?: boolean;
251
+ /**
252
+ * Record unhandled promise rejections as errors (severity "error",
253
+ * `autter.unhandled_rejection: true`). Never changes whether the process
254
+ * crashes: when Node would have crashed (the default
255
+ * `--unhandled-rejections=throw` mode and no other `unhandledRejection`
256
+ * listener), the rejection is rethrown on the next tick, so the process
257
+ * still exits with code 1 and the crash is recorded as fatal like any
258
+ * other. False restores 1.5.0 behaviour: a rejection is only seen when it
259
+ * crashes the process. Default true.
260
+ */
261
+ captureUnhandledRejections?: boolean;
247
262
  /**
248
263
  * Flush all exporters when the process exits (`beforeExit`, SIGINT,
249
264
  * SIGTERM) so a forgotten `shutdown()` doesn't silently drop buffered
@@ -266,6 +281,18 @@ interface AutterServerOptions {
266
281
  * Default true.
267
282
  */
268
283
  redactAttributes?: boolean | RedactOptions;
284
+ /**
285
+ * Query strings never leave the process with their values. Every span
286
+ * (any instrumentation, Next.js's own included) is exported with
287
+ * `http.target`, `http.url` and `url.full` cut at the `?`, `url.query`
288
+ * reduced to its parameter names (`email=[redacted]&page=[redacted]`,
289
+ * added when only the URL had the query) and the query dropped from span
290
+ * names. List parameters whose values are safe to keep in `url.query`,
291
+ * such as pagination or sorting: `keepQueryParams: ["page", "sort"]`
292
+ * (exact names; kept values are still scrubbed by `redactAttributes`).
293
+ * Applies even with `redactAttributes: false`. Default `[]`.
294
+ */
295
+ keepQueryParams?: string[];
269
296
  /**
270
297
  * Verbose lifecycle logging to stderr: "exported N spans", flushes and
271
298
  * auto-flush activity — handy while wiring the SDK up. Also enabled by
@@ -344,7 +371,12 @@ interface TrackedLlmCall extends LlmCallInfo, LlmUsage {
344
371
  error?: unknown;
345
372
  }
346
373
  interface AutterServer {
347
- /** Report a handled exception. Always recorded (never sampled out). */
374
+ /**
375
+ * Report a handled exception. Always recorded (never sampled out).
376
+ * `attributes.fingerprint` (a string or up to 10 strings) groups every
377
+ * error that carries it into one issue (ingester 1.6.0+); it is sent as
378
+ * `autter.fingerprint` on the exception event, not as a span attribute.
379
+ */
348
380
  captureException(error: unknown, attributes?: Attributes): void;
349
381
  /**
350
382
  * Report a warning (or info) without an exception — deprecated code
@@ -566,6 +598,17 @@ interface RuntimeRequestOptions {
566
598
  /** Receives the log flush promise after the response (serverless `waitUntil`). */
567
599
  waitUntil?: (promise: Promise<unknown>) => void;
568
600
  }
601
+ /**
602
+ * Report an error that reached a request boundary — a framework error hook,
603
+ * an exception filter, Next.js `onRequestError`. Unlike `captureException`
604
+ * it reports each error once (an error a handler or another hook already
605
+ * captured is skipped), and it records the exception, with its stack, on the
606
+ * request's HTTP server span even when a child span is active, so the failed
607
+ * request and its exception stay one issue. When the error was already
608
+ * captured (e.g. by `withRuntimeRequest`), `attributes` still go on the
609
+ * request span, without a second exception.
610
+ */
611
+ declare function captureRequestError(error: unknown, attributes?: Attributes): void;
569
612
  /**
570
613
  * Express / Connect middleware. Mount it early (before routers; after body
571
614
  * parsers is fine too):
@@ -605,6 +648,101 @@ declare function autterFastify(fastify: FastifyLikeInstance, options: AutterRequ
605
648
  */
606
649
  declare function withRuntimeRequest<A extends unknown[]>(handler: (request: Request, ...rest: A) => Response | Promise<Response>, options?: RuntimeRequestOptions): (request: Request, ...rest: A) => Promise<Response>;
607
650
 
651
+ /**
652
+ * Server error hooks for Express, Fastify and Koa. Each records the error,
653
+ * with its stack, on the request's span through `captureException`, then
654
+ * lets the framework carry on exactly as before (same error, same response).
655
+ * Without them a thrown error only reaches Autter as the 500 the framework
656
+ * answers with: a stackless `HttpServerError` grouped by route.
657
+ *
658
+ * No framework is a dependency: the request/reply shapes are structural.
659
+ */
660
+ interface AutterErrorHandlerOptions {
661
+ /**
662
+ * Which errors to report. Default: errors with status ≥ 500 (or no
663
+ * status), RuntimeErrors and any error with a valid code — so 4xx errors
664
+ * such as `ctx.throw(404)` or validation failures stay out of your issues.
665
+ * `true` reports every error; a predicate decides per error.
666
+ */
667
+ capture?: boolean | ((error: unknown) => boolean);
668
+ }
669
+ /**
670
+ * Express (4/5) / Connect error middleware that reports the error and calls
671
+ * `next(err)` unchanged. Mount it after your routes and before your own
672
+ * error handlers:
673
+ *
674
+ * app.use(autterErrorHandler());
675
+ * app.use((err, req, res, next) => res.status(500).send("…")); // yours
676
+ *
677
+ * (`autterErrorResponse()` reports too, and also answers the request.)
678
+ */
679
+ declare function autterErrorHandler(options?: AutterErrorHandlerOptions): (error: unknown, req: IncomingMessage, _res: ServerResponse, next: (error?: unknown) => void) => void;
680
+ interface FastifyHookInstance {
681
+ addHook(name: string, hook: (...args: never[]) => unknown): unknown;
682
+ }
683
+ /**
684
+ * Fastify (4/5) `onError` hook that reports the error; Fastify's error
685
+ * handler still builds the response. Register it as a plugin, or call it on
686
+ * the instance directly:
687
+ *
688
+ * app.register(autterFastifyErrors); // or: autterFastifyErrors(app)
689
+ * app.register(autterFastifyErrors, { capture: true });
690
+ *
691
+ * It skips plugin encapsulation, so it covers every route. `autterFastify`
692
+ * (request summaries) already includes the same hook; you don't need both.
693
+ */
694
+ declare function autterFastifyErrors(fastify: FastifyHookInstance, options?: AutterErrorHandlerOptions, done?: (error?: Error) => void): void;
695
+ interface KoaContextLike {
696
+ req?: IncomingMessage;
697
+ }
698
+ /**
699
+ * Koa (2/3) middleware that reports errors thrown downstream and rethrows
700
+ * them, so Koa's own error handling (and `app.on("error")`) is unchanged.
701
+ * Mount it first:
702
+ *
703
+ * app.use(autterKoa());
704
+ */
705
+ declare function autterKoa(options?: AutterErrorHandlerOptions): (ctx: KoaContextLike, next: () => Promise<unknown>) => Promise<void>;
706
+
707
+ /**
708
+ * Unhandled promise rejections, recorded without changing whether the
709
+ * process crashes.
710
+ *
711
+ * Node's `--unhandled-rejections` mode decides what an unhandled rejection
712
+ * does, and most modes behave differently once ANY `unhandledRejection`
713
+ * listener exists:
714
+ *
715
+ * mode no listener with a listener
716
+ * throw (default) crash (uncaught exception) listener only — no crash
717
+ * strict crash, then the listener same
718
+ * warn warning listener + warning
719
+ * warn-with-error-code warning + exit code 1 listener only
720
+ * none nothing listener only
721
+ *
722
+ * Adding our listener would therefore silently stop the default crash. So
723
+ * when ours is the only listener we do what Node would have done:
724
+ *
725
+ * - throw: rethrow the reason (or Node's `UnhandledPromiseRejection`
726
+ * wrapper for a non-error reason) on the next tick. The process crashes
727
+ * with exit code 1 as before, and `uncaughtExceptionMonitor` records it
728
+ * as a crash (fatal), exactly as it did without this listener. The one
729
+ * visible difference: `uncaughtException` listeners and the monitor
730
+ * receive origin `"uncaughtException"` instead of `"unhandledRejection"`.
731
+ * - warn-with-error-code: print Node's warning and set `process.exitCode = 1`.
732
+ * - strict: no listener at all — Node raises the rejection as an uncaught
733
+ * exception first, which the crash monitor already records.
734
+ *
735
+ * Everything else — the app has its own listener (it decides what happens),
736
+ * or the mode never crashes — is recorded as an error (severity "error", not
737
+ * fatal) with `autter.unhandled_rejection: true`.
738
+ */
739
+ type UnhandledRejectionsMode = "throw" | "strict" | "warn" | "warn-with-error-code" | "none";
740
+ /**
741
+ * Node's effective `--unhandled-rejections` mode: `NODE_OPTIONS` first, then
742
+ * the command line (which wins), last occurrence wins. Default `"throw"`.
743
+ */
744
+ declare function unhandledRejectionsMode(execArgv?: readonly string[], nodeOptions?: string | undefined): UnhandledRejectionsMode;
745
+
608
746
  /**
609
747
  * Logger-only mode: requests, operations, coded errors, sinks and enrichers
610
748
  * WITHOUT starting the OpenTelemetry NodeSDK. For apps that already run
@@ -629,8 +767,12 @@ interface AutterLoggingOptions {
629
767
  logging?: RuntimeLoggingOptions;
630
768
  /** Same semantics as initAutterServer. Default true. */
631
769
  redactAttributes?: boolean | RedactOptions;
632
- /** Capture crashes via process.uncaughtExceptionMonitor. Default true. */
770
+ /** Capture crashes via process.uncaughtExceptionMonitor, and unhandled
771
+ * rejections (`captureUnhandledRejections`). Default true. */
633
772
  captureGlobalErrors?: boolean;
773
+ /** Same semantics as initAutterServer: record unhandled rejections as
774
+ * errors without changing whether the process crashes. Default true. */
775
+ captureUnhandledRejections?: boolean;
634
776
  /** Flush records on beforeExit/SIGINT/SIGTERM. Default true. */
635
777
  autoFlush?: boolean;
636
778
  debug?: boolean;
@@ -679,7 +821,9 @@ declare function enrichDeployment(env?: Record<string, string | undefined>): Run
679
821
  * Adding a feature: append an entry to compat-manifest.json with the first
680
822
  * ingester release that handles it, the migrations it writes to, its route
681
823
  * (if it has its own), and the first SDK release that emits it. The
682
- * consistency test in compat.test.ts checks ids, migrations and routes.
824
+ * consistency test in compat.test.ts checks ids, migrations and routes, and
825
+ * that no version is ahead of its package's package.json: a feature for the
826
+ * next release bumps the packages it names in the same change.
683
827
  */
684
828
  interface CompatFeature {
685
829
  id: string;
@@ -811,4 +955,13 @@ interface DoctorReport {
811
955
  }
812
956
  declare function runDoctor(options?: DoctorOptions): Promise<DoctorReport>;
813
957
 
814
- export { type AutoFlushHandle, type AutoFlushOptions, type AutterErrorResponseOptions, type AutterLogging, type AutterLoggingOptions, type AutterRequestsOptions, type AutterServer, type AutterServerOptions, type AutterSeverity, COMPAT_MANIFEST, type CompatIssue, type DoctorOptions, type DoctorReport, FileSinkOptions, type FlushTarget, INGESTER_VERSION_HEADER, type IngesterCompatInfo, type InstrumentLlmOptions, type LlmCallHandle, type LlmCallInfo, type LlmUsage, RedactOptions, type RelayOptions, RuntimeCarrier, type RuntimeContextHandle, type RuntimeEnrichContext, type RuntimeEnrichEvent, type RuntimeEnricher, RuntimeLogContext, RuntimeLogLevel, type RuntimeLoggingOptions, type RuntimeOperation, RuntimeOperationKind, type RuntimeOperationOptions, RuntimeOutcome, type RuntimeRequestOptions, RuntimeSink, SDK_IDENTITY, type SafeCapture, type SdkIdentity, type TrackedLlmCall, autterErrorResponse, autterFastify, autterRequests, captureException, captureMessage, createBrowserRelayFetchHandler, createBrowserRelayHandler, createRuntimeLogger, emitLlmSelftestTrace, enrichDeployment, enrichEdgeGeo, enrichRequestSize, enrichUserAgent, evaluateCompat, fetchIngesterCompat, flushRuntimeLogs, initAutterLogging, initAutterServer, installAutterAutoFlush, instrumentLlmClient, makeSafeCapture, reportOutcome, runDoctor, runInBackground, runtimeContext, runtimeLogStats, runtimeLogger, sanitizeBrowserPayload, startCaughtExceptionSampler, trackLlmCall, withLlmCall, withProcessSpan, withRuntimeOperation, withRuntimeRequest };
958
+ /**
959
+ * Record a step (type "custom" unless you say otherwise) on the current
960
+ * request. The next exception captured in it carries the last 30. Message
961
+ * and data are scrubbed with your `redact` settings. Never throws.
962
+ *
963
+ * addBreadcrumb({ message: "Loaded cart", data: { items: 3 } });
964
+ */
965
+ declare function addBreadcrumb(input: BreadcrumbInput): void;
966
+
967
+ export { type AutoFlushHandle, type AutoFlushOptions, type AutterErrorHandlerOptions, type AutterErrorResponseOptions, type AutterLogging, type AutterLoggingOptions, type AutterRequestsOptions, type AutterServer, type AutterServerOptions, type AutterSeverity, BreadcrumbInput, COMPAT_MANIFEST, type CompatIssue, type DoctorOptions, type DoctorReport, FileSinkOptions, type FlushTarget, INGESTER_VERSION_HEADER, type IngesterCompatInfo, type InstrumentLlmOptions, type LlmCallHandle, type LlmCallInfo, type LlmUsage, RedactOptions, type RelayOptions, RuntimeCarrier, type RuntimeContextHandle, type RuntimeEnrichContext, type RuntimeEnrichEvent, type RuntimeEnricher, RuntimeLogContext, RuntimeLogLevel, type RuntimeLoggingOptions, type RuntimeOperation, RuntimeOperationKind, type RuntimeOperationOptions, RuntimeOutcome, type RuntimeRequestOptions, RuntimeSink, SDK_IDENTITY, type SafeCapture, type SdkIdentity, type TrackedLlmCall, type UnhandledRejectionsMode, addBreadcrumb, autterErrorHandler, autterErrorResponse, autterFastify, autterFastifyErrors, autterKoa, autterRequests, captureException, captureMessage, captureRequestError, createBrowserRelayFetchHandler, createBrowserRelayHandler, createRuntimeLogger, emitLlmSelftestTrace, enrichDeployment, enrichEdgeGeo, enrichRequestSize, enrichUserAgent, evaluateCompat, fetchIngesterCompat, flushRuntimeLogs, initAutterLogging, initAutterServer, installAutterAutoFlush, instrumentLlmClient, makeSafeCapture, reportOutcome, runDoctor, runInBackground, runtimeContext, runtimeLogStats, runtimeLogger, sanitizeBrowserPayload, startCaughtExceptionSampler, trackLlmCall, unhandledRejectionsMode, withLlmCall, withProcessSpan, withRuntimeOperation, withRuntimeRequest };