@autter/runtime-node 1.3.4 → 1.5.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/dist/index.d.ts CHANGED
@@ -1,4 +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
4
  import { Attributes } from '@opentelemetry/api';
3
5
 
4
6
  /**
@@ -23,8 +25,25 @@ interface RelayOptions {
23
25
  perIpRateLimit?: number | false;
24
26
  /** Called when the async forward fails (default: console.warn). */
25
27
  onError?: (err: unknown) => void;
28
+ /**
29
+ * Scrub secrets/PII from browser events (message, stack, name, nested
30
+ * context) before they leave your server — the same patterns as
31
+ * `initAutterServer({ redactAttributes })`. Catches old browser SDK
32
+ * versions and anything the browser's lean redactor misses. Pass a
33
+ * RedactOptions object to add your own patterns; `false` disables.
34
+ * Default true.
35
+ */
36
+ redact?: boolean | RedactOptions;
37
+ /**
38
+ * Warn once (server-side) when browser features in the forwarded events
39
+ * — CSP violations, network/timing capture — need a newer ingester than
40
+ * the one answering. Reads the ingester's version header from the forward
41
+ * response; never blocks the 202. Also disabled by AUTTER_COMPAT_CHECK=0.
42
+ * Default true.
43
+ */
44
+ compatCheck?: boolean;
26
45
  }
27
- declare function sanitizeBrowserPayload(raw: unknown): object | null;
46
+ declare function sanitizeBrowserPayload(raw: unknown, redactor?: Redactor$1): object | null;
28
47
  /**
29
48
  * Fetch-style handler (Next.js App Router route, Remix, Hono, Bun, Deno):
30
49
  *
@@ -43,32 +62,124 @@ declare function createBrowserRelayHandler(opts: RelayOptions): (req: IncomingMe
43
62
  body?: unknown;
44
63
  }, res: ServerResponse) => void;
45
64
 
46
- interface RedactOptions {
65
+ /** Mutable view of a record handed to enrichers before redaction/bounding. */
66
+ interface RuntimeEnrichEvent {
67
+ level: RuntimeLogLevel;
68
+ message: string;
69
+ attributes: Record<string, unknown>;
70
+ }
71
+ interface RuntimeEnrichContext {
72
+ /** The inbound request of a request summary (Node IncomingMessage or fetch Request). */
73
+ req?: unknown;
74
+ /** The response object, when the framework exposes one. */
75
+ res?: unknown;
76
+ operation: {
77
+ id: string;
78
+ name: string;
79
+ kind: RuntimeOperationKind;
80
+ };
81
+ }
82
+ /** Adds attributes to operation/request summaries. Must be cheap; errors are ignored. */
83
+ type RuntimeEnricher = (event: RuntimeEnrichEvent, context: RuntimeEnrichContext) => void;
84
+ interface RuntimeLoggingOptions {
85
+ /** Print records to the console (default sinks only). Default true. */
86
+ console?: boolean;
87
+ /** Drop plain log records below this level. Summaries are always kept. */
88
+ minLevel?: RuntimeLogLevel;
89
+ /**
90
+ * Fold debug/info messages logged inside an operation into its summary
91
+ * (`autter.operation.logs`, max 50) instead of emitting separate records;
92
+ * warn/error are folded AND emitted. Default true.
93
+ */
94
+ inline?: boolean;
95
+ /** Run on every operation/request summary before redaction. */
96
+ enrich?: RuntimeEnricher[];
47
97
  /**
48
- * Extra patterns matched against lower-cased attribute KEYS; a match
49
- * masks the whole value. Strings become case-insensitive substring
50
- * patterns. Extends the built-in list.
98
+ * Replace the default sinks (`[otlpSink(), consoleSink()]`, plus
99
+ * `fileSink()` when NODE_ENV=development).
51
100
  */
52
- additionalKeyPatterns?: (RegExp | string)[];
101
+ sinks?: RuntimeSink[];
53
102
  /**
54
- * Extra patterns scrubbed inside string VALUES (same semantics as the
55
- * built-in email/token patterns). Extends the built-in list.
103
+ * Local NDJSON files (`.autter/runtime/YYYY-MM-DD.jsonl`). Default: on only
104
+ * when NODE_ENV === "development". Ignored when `sinks` is set.
56
105
  */
57
- additionalValuePatterns?: (RegExp | string)[];
58
- /** Replacement token. Default "[redacted]". */
59
- mask?: string;
106
+ file?: boolean | FileSinkOptions;
60
107
  /**
61
- * Scrub email-shaped substrings from ALL string values, not just
62
- * sensitive keys. Default true.
108
+ * EXPERIMENTAL zero-code request summaries for plain `node:http` servers
109
+ * via the HTTP instrumentation hook (initAutterServer only). Uses
110
+ * AsyncLocalStorage.enterWith, which can leak context across keep-alive /
111
+ * pipelined requests on one socket — prefer `autterRequests()`. Default false.
63
112
  */
64
- scrubEmailValues?: boolean;
113
+ requests?: boolean;
65
114
  }
115
+ interface RuntimeOperation {
116
+ readonly id: string;
117
+ setContext(attributes: RuntimeLogContext): void;
118
+ outcome(status: RuntimeOutcome, message?: string): void;
119
+ step<T>(name: string, fn: () => T | Promise<T>): Promise<T>;
120
+ }
121
+ interface RuntimeOperationOptions {
122
+ /** Carrier from `runtimeContext.carrier()` (object or JSON string): links parent op, request id and trace. */
123
+ from?: RuntimeCarrier | string | null;
124
+ /** Receives the log flush promise once the operation completes (serverless `waitUntil`). */
125
+ waitUntil?: (promise: Promise<unknown>) => void;
126
+ }
127
+ declare function runtimeLogStats(): {
128
+ buffered: number;
129
+ dropped: number;
130
+ };
131
+ declare function flushRuntimeLogs(): Promise<void>;
132
+ declare function createRuntimeLogger(attributes?: RuntimeLogContext): {
133
+ debug: (message: string, extra?: RuntimeLogContext) => void;
134
+ info: (message: string, extra?: RuntimeLogContext) => void;
135
+ warn: (message: string, extra?: RuntimeLogContext) => void;
136
+ error: (error: unknown, extra?: RuntimeLogContext) => void;
137
+ };
138
+ declare const runtimeLogger: {
139
+ debug: (message: string, extra?: RuntimeLogContext) => void;
140
+ info: (message: string, extra?: RuntimeLogContext) => void;
141
+ warn: (message: string, extra?: RuntimeLogContext) => void;
142
+ error: (error: unknown, extra?: RuntimeLogContext) => void;
143
+ };
144
+ /**
145
+ * Run `fn` as a named operation: one summary record (outcome, duration,
146
+ * steps, context, inline messages) when it ends. Nested operations link via
147
+ * `autter.operation.parent_id`; pass `{ from: carrier }` to continue work
148
+ * handed over through a queue or another process.
149
+ */
150
+ declare function withRuntimeOperation<T>(name: string, fn: (operation: RuntimeOperation) => T | Promise<T>, attributes?: RuntimeLogContext, options?: RuntimeOperationOptions): Promise<T>;
151
+ /**
152
+ * Like `runtimeContext.fork` but not awaited: errors are recorded on the
153
+ * child operation (and its span) and never become unhandled rejections.
154
+ */
155
+ declare function runInBackground<T>(name: string, fn: (operation: RuntimeOperation) => T | Promise<T>): Promise<T | undefined>;
66
156
  /**
67
- * Return a copy of `attributes` with PII/secrets masked. Never mutates the
68
- * input; non-string primitives pass through untouched; `undefined` values
69
- * are dropped (OpenTelemetry rejects them).
157
+ * The current request/operation, from anywhere in its async call tree.
158
+ * Every method is a safe no-op (or plain log) outside an operation.
70
159
  */
71
- declare function redactAttributes(attributes?: Attributes | null, options?: RedactOptions): Attributes;
160
+ declare const runtimeContext: {
161
+ /** Merge attributes into the current summary's context. */
162
+ set(attributes: RuntimeLogContext): void;
163
+ /** Set the outcome explicitly (wins over status/thrown-error rules). */
164
+ outcome(status: RuntimeOutcome, message?: string): void;
165
+ debug(message: string, attributes?: RuntimeLogContext): void;
166
+ info(message: string, attributes?: RuntimeLogContext): void;
167
+ warn(message: string, attributes?: RuntimeLogContext): void;
168
+ /** Log an error and attach it (code/why/fix) to the current summary. */
169
+ error(error: unknown, attributes?: RuntimeLogContext): void;
170
+ /** Current operation id. */
171
+ readonly id: string | undefined;
172
+ /** Current request id (inherited by child operations and forks). */
173
+ readonly requestId: string | undefined;
174
+ /**
175
+ * Run `fn` as a child operation whose parent link is captured NOW, so it
176
+ * still links after the parent has finished (background work).
177
+ */
178
+ fork<T>(name: string, fn: (operation: RuntimeOperation) => T | Promise<T>): Promise<T>;
179
+ /** Serialisable link for queue payloads: `{ v: 1, op, req?, traceparent? }`. */
180
+ carrier(): RuntimeCarrier | undefined;
181
+ };
182
+ type RuntimeContextHandle = typeof runtimeContext;
72
183
 
73
184
  /**
74
185
  * Curated OpenTelemetry setup for Autter Runtime — deliberately NOT the
@@ -89,12 +200,20 @@ declare function redactAttributes(attributes?: Attributes | null, options?: Reda
89
200
  * request metrics : aggregated every 60 s, keyed by route
90
201
  * template (Express routes detected
91
202
  * out of the box — see captureExpressRoute)
92
- * logs : not collected
203
+ * operation / request summaries: 100% (withRuntimeOperation,
204
+ * autterRequests, … — one wide
205
+ * record per unit of work, never
206
+ * sampled)
207
+ * logs : runtimeLogger / runtimeContext records
208
+ * (debug/info folded into the current
209
+ * operation's summary; minLevel applies)
93
210
  *
94
211
  * Exports OTLP/HTTP JSON to the Autter ingester (`/v1/traces`,
95
- * `/v1/metrics`) with the ingest key as a bearer header.
212
+ * `/v1/metrics`, `/v1/logs`) with the ingest key as a bearer header.
96
213
  */
97
214
  interface AutterServerOptions {
215
+ /** Structured logs and completed operation summaries. */
216
+ logging?: RuntimeLoggingOptions;
98
217
  /** Private ingest key (autter_rt_…). */
99
218
  apiKey: string;
100
219
  /** Ingester base URL. Default: https://otlp.autter.dev */
@@ -133,12 +252,17 @@ interface AutterServerOptions {
133
252
  */
134
253
  autoFlush?: boolean;
135
254
  /**
136
- * Mask PII/secrets in custom attributes before they leave the process:
137
- * emails, tokens (JWT, sk-, gh_, AWS, Slack), bearer headers,
138
- * `scheme://user:pass@` URLs, and anything whose attribute KEY looks
139
- * sensitive (password/token/secret/cookie/…). Mirrors the browser
140
- * relay's whitelist sanitiser. `true`/undefined = defaults; pass a
141
- * RedactOptions object to extend the patterns; `false` disables.
255
+ * Mask secrets/PII before anything leaves the process — custom
256
+ * attributes, exception messages and stack traces, span status
257
+ * messages, URLs/query strings and attributes set by any
258
+ * instrumentation (scrubbed again at export), and structured logs:
259
+ * JWTs, bearer/basic credentials, Cookie/Authorization header text,
260
+ * `scheme://user:pass@` connection strings, vendor API keys (sk-, sk_live_,
261
+ * ghp_, xox*-, AIza, AKIA, …), PEM private keys, `password=`/`?token=`
262
+ * assignments, emails, card numbers, and anything whose attribute KEY
263
+ * looks sensitive (password/token/secret/cookie/authorization/session/…).
264
+ * `true`/undefined = defaults; pass a RedactOptions object to add your
265
+ * own key/value patterns; `false` disables (not recommended).
142
266
  * Default true.
143
267
  */
144
268
  redactAttributes?: boolean | RedactOptions;
@@ -156,6 +280,22 @@ interface AutterServerOptions {
156
280
  llmTracing?: boolean;
157
281
  /** Extra instrumentations (e.g. `new ExpressInstrumentation()`). */
158
282
  instrumentations?: unknown[];
283
+ /**
284
+ * Check once, in the background, that the ingester supports the features
285
+ * in use (operation logging, memory metrics, …) and print one warning per
286
+ * mismatch naming both versions and the fix. Never throws or delays
287
+ * startup. Also disabled by AUTTER_COMPAT_CHECK=0. Default true.
288
+ * Run `npx @autter/runtime-node doctor` for a full report.
289
+ */
290
+ compatCheck?: boolean;
291
+ /**
292
+ * @internal Wrapper packages (`@autter/runtime-next`) report their own
293
+ * name/version as the OTLP `telemetry.distro.*` resource attributes.
294
+ */
295
+ distro?: {
296
+ name: string;
297
+ version: string;
298
+ };
159
299
  }
160
300
  type AutterSeverity = "fatal" | "error" | "warning" | "info";
161
301
  /** Token usage (and optionally exact cost) of one LLM call. */
@@ -167,6 +307,8 @@ interface LlmUsage {
167
307
  * built-in per-model price estimate.
168
308
  */
169
309
  costUsd?: number;
310
+ /** Prompt tokens served from the provider cache (rolled into `autter.operation.ai`). */
311
+ cacheReadTokens?: number;
170
312
  }
171
313
  interface LlmCallInfo {
172
314
  /** Provider system: "openai", "anthropic", "google", "mistral_ai", … */
@@ -395,4 +537,278 @@ declare function startCaughtExceptionSampler(options?: {
395
537
  stop(): void;
396
538
  };
397
539
 
398
- export { type AutoFlushHandle, type AutoFlushOptions, type AutterServer, type AutterServerOptions, type AutterSeverity, type FlushTarget, type InstrumentLlmOptions, type LlmCallHandle, type LlmCallInfo, type LlmUsage, type RedactOptions, type RelayOptions, type SafeCapture, type TrackedLlmCall, captureException, captureMessage, createBrowserRelayFetchHandler, createBrowserRelayHandler, emitLlmSelftestTrace, initAutterServer, installAutterAutoFlush, instrumentLlmClient, makeSafeCapture, redactAttributes, reportOutcome, sanitizeBrowserPayload, startCaughtExceptionSampler, trackLlmCall, withLlmCall, withProcessSpan };
540
+ interface AutterRequestsOptions {
541
+ /** Path globs never summarised: `*` = one segment, `**` = any depth. */
542
+ ignore?: string[];
543
+ /** Request id header to honour and echo. Default "x-request-id". */
544
+ requestIdHeader?: string;
545
+ /** Honour an inbound request id that matches `^[\w.-]{8,128}$`. Default true. */
546
+ trustRequestId?: boolean;
547
+ }
548
+ interface AutterErrorResponseOptions {
549
+ /**
550
+ * Report the error as an exception. Default: errors with status ≥ 500,
551
+ * RuntimeErrors and any error with a valid code (expected ones included —
552
+ * they are recorded but never open incidents).
553
+ */
554
+ capture?: boolean | ((error: unknown) => boolean);
555
+ /** Header the request id is read from when no request summary is active. */
556
+ requestIdHeader?: string;
557
+ }
558
+ interface RuntimeRequestOptions {
559
+ /** Summary name suffix (default: the route). Name = `METHOD name`. */
560
+ name?: string;
561
+ /** Route template for `http.route` (default: pathname with ids → `:id`). */
562
+ route?: string;
563
+ requestIdHeader?: string;
564
+ trustRequestId?: boolean;
565
+ ignore?: string[];
566
+ /** Receives the log flush promise after the response (serverless `waitUntil`). */
567
+ waitUntil?: (promise: Promise<unknown>) => void;
568
+ }
569
+ /**
570
+ * Express / Connect middleware. Mount it early (before routers; after body
571
+ * parsers is fine too):
572
+ *
573
+ * app.use(autterRequests({ ignore: ["/healthz", "/metrics"] }));
574
+ *
575
+ * Echoes the request id in the response (`x-request-id`), stamps it on the
576
+ * server span and every record, and emits the summary on finish/close.
577
+ */
578
+ declare function autterRequests(options?: AutterRequestsOptions): (req: IncomingMessage, res: ServerResponse, next: (error?: unknown) => void) => void;
579
+ /**
580
+ * Express error middleware: records the error on the request summary,
581
+ * reports it (see `capture`), and answers with
582
+ * `{ error: { message, code?, why?, fix?, link?, requestId? } }` and the
583
+ * error's status (default 500). Never includes `internal`, stacks or causes;
584
+ * unstructured 5xx messages are replaced with a generic one.
585
+ *
586
+ * app.use(autterErrorResponse()); // after your routes
587
+ */
588
+ declare function autterErrorResponse(options?: AutterErrorResponseOptions): (error: unknown, req: IncomingMessage, res: ServerResponse, next: (error?: unknown) => void) => void;
589
+ interface FastifyLikeInstance {
590
+ addHook(name: string, hook: (...args: never[]) => unknown): unknown;
591
+ }
592
+ /**
593
+ * Fastify plugin (Fastify 4/5, no dependency on fastify itself):
594
+ *
595
+ * app.register(autterFastify, { ignore: ["/healthz"] });
596
+ *
597
+ * Skips plugin encapsulation, so its hooks cover every route.
598
+ */
599
+ declare function autterFastify(fastify: FastifyLikeInstance, options: AutterRequestsOptions | undefined, done: (error?: Error) => void): void;
600
+ /**
601
+ * Wrap a fetch-style handler `(request, ...rest) => Response` in a request
602
+ * summary. Thrown errors are recorded and reported, then rethrown.
603
+ *
604
+ * export const POST = withRuntimeRequest(handler, { name: "checkout" });
605
+ */
606
+ declare function withRuntimeRequest<A extends unknown[]>(handler: (request: Request, ...rest: A) => Response | Promise<Response>, options?: RuntimeRequestOptions): (request: Request, ...rest: A) => Promise<Response>;
607
+
608
+ /**
609
+ * Logger-only mode: requests, operations, coded errors, sinks and enrichers
610
+ * WITHOUT starting the OpenTelemetry NodeSDK. For apps that already run
611
+ * their own OTel (a second NodeSDK would fight it) or want logs only.
612
+ *
613
+ * initAutterLogging({ apiKey: process.env.AUTTER_RUNTIME_KEY, service: "api" });
614
+ *
615
+ * Exceptions are recorded on the app's active span when there is one
616
+ * (`exceptions: "auto"`); otherwise — or always with `exceptions: "log"` —
617
+ * they become error log records with `exception.*` and
618
+ * `autter.capture.mode = "log"`, which the ingester (1.5.0+) promotes to
619
+ * occurrences. Without an apiKey records go to the console/file sinks only.
620
+ */
621
+ interface AutterLoggingOptions {
622
+ /** Private ingest key (autter_rt_…). Omit to log locally only. */
623
+ apiKey?: string;
624
+ /** Ingester base URL. Default: https://otlp.autter.dev */
625
+ endpoint?: string;
626
+ service: string;
627
+ environment?: string;
628
+ release?: string;
629
+ logging?: RuntimeLoggingOptions;
630
+ /** Same semantics as initAutterServer. Default true. */
631
+ redactAttributes?: boolean | RedactOptions;
632
+ /** Capture crashes via process.uncaughtExceptionMonitor. Default true. */
633
+ captureGlobalErrors?: boolean;
634
+ /** Flush records on beforeExit/SIGINT/SIGTERM. Default true. */
635
+ autoFlush?: boolean;
636
+ debug?: boolean;
637
+ /**
638
+ * "auto" (default): record on the app's active recording span if any,
639
+ * else emit a promoted log record. "log": always emit the log record
640
+ * (use when the app's own spans are not exported to Autter).
641
+ */
642
+ exceptions?: "auto" | "log";
643
+ }
644
+ interface AutterLogging {
645
+ captureException(error: unknown, attributes?: Attributes): void;
646
+ flush(): Promise<void>;
647
+ shutdown(): Promise<void>;
648
+ }
649
+ declare function initAutterLogging(options: AutterLoggingOptions): AutterLogging;
650
+
651
+ /** `user_agent.browser` ("Chrome 120"), `user_agent.os`, `user_agent.device`, `user_agent.bot`. */
652
+ declare function enrichUserAgent(): RuntimeEnricher;
653
+ /** `http.request.body.size` / `http.response.body.size` from Content-Length. */
654
+ declare function enrichRequestSize(): RuntimeEnricher;
655
+ /** `geo.country.iso_code` from CDN/edge headers (Cloudflare, Vercel, CloudFront, Fastly). Country only. */
656
+ declare function enrichEdgeGeo(): RuntimeEnricher;
657
+ /** `deployment.region` and `deployment.commit` from common platform environment variables. */
658
+ declare function enrichDeployment(env?: Record<string, string | undefined>): RuntimeEnricher;
659
+
660
+ /**
661
+ * Version compatibility between Autter Runtime SDKs, this ingester and its
662
+ * ClickHouse schema — the single source of truth.
663
+ *
664
+ * `compat-manifest.json` lists every feature that needs a minimum ingester
665
+ * version, a ClickHouse migration, a dedicated ingest route, or a minimum SDK
666
+ * version. Everything else derives from it:
667
+ *
668
+ * - the ingester serves it (evaluated against its own version and applied
669
+ * migrations) at `GET /v1/compat`;
670
+ * - `@autter/runtime-node` / `@autter/runtime-next` bundle this file at build
671
+ * time to warn once when an enabled feature needs a newer ingester, and to
672
+ * power `npx @autter/runtime-node doctor`;
673
+ * - the Python adapter (`adapters/python/compat.py`) embeds a copy that a
674
+ * parity test keeps identical.
675
+ *
676
+ * This module is dependency-free and side-effect-free on purpose: it is
677
+ * bundled into the Node SDK. Keep it that way.
678
+ *
679
+ * Adding a feature: append an entry to compat-manifest.json with the first
680
+ * ingester release that handles it, the migrations it writes to, its route
681
+ * (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.
683
+ */
684
+ interface CompatFeature {
685
+ id: string;
686
+ title: string;
687
+ /** First ingester release that stores this feature correctly. */
688
+ ingester: string;
689
+ /** ClickHouse migrations (migrations.ts ids) the feature writes to. */
690
+ migrations: string[];
691
+ /** Dedicated ingest route, when the feature has one. */
692
+ route?: string;
693
+ /** First release of each SDK package that emits the feature. */
694
+ sdks: Record<string, string>;
695
+ /** Browser payload event types that belong to this feature. */
696
+ browserEvents?: string[];
697
+ }
698
+ interface CompatManifest {
699
+ manifestVersion: number;
700
+ docs: string;
701
+ upgrade: {
702
+ ingester: string;
703
+ sdk: string;
704
+ };
705
+ features: CompatFeature[];
706
+ }
707
+ declare const COMPAT_MANIFEST: CompatManifest;
708
+ /** Response header carrying the ingester version on every ingest response. */
709
+ declare const INGESTER_VERSION_HEADER = "x-autter-ingester-version";
710
+ type SchemaStatus = "ready" | "pending" | "failed" | "unconfigured";
711
+ /** What is known about the ingester an SDK talks to. */
712
+ interface IngesterCompatInfo {
713
+ /** Exact version, or null when the ingester predates /v1/compat. */
714
+ version: string | null;
715
+ /** True when /v1/compat returned 404 (ingester 1.4.0 or older). */
716
+ legacy?: boolean;
717
+ schema?: {
718
+ status: SchemaStatus;
719
+ applied: string[];
720
+ };
721
+ /** Legacy ingesters: route → exists, learned by probing. */
722
+ routes?: Record<string, boolean>;
723
+ }
724
+ type CompatIssueKind = "ingester_too_old" | "schema_not_applied" | "sdk_too_old";
725
+ interface CompatIssue {
726
+ feature: string;
727
+ title: string;
728
+ kind: CompatIssueKind;
729
+ /** Package that must change: the ingester or an SDK package name. */
730
+ component: string;
731
+ required: string;
732
+ /** What was found ("1.3.4", "1.4.0 or older", …). */
733
+ actual: string;
734
+ /** One line: what is wrong, versions, and the fix. */
735
+ message: string;
736
+ fix: string;
737
+ }
738
+ interface SdkIdentity {
739
+ name: string;
740
+ version: string;
741
+ }
742
+ /**
743
+ * Every incompatibility for the features in use. Unknown is never an issue:
744
+ * when the ingester version can't be determined (and a legacy route probe
745
+ * didn't prove a route missing) nothing is reported, so the check has no
746
+ * false positives.
747
+ */
748
+ declare function evaluateCompat(input: {
749
+ features: Iterable<string>;
750
+ ingester: IngesterCompatInfo | null;
751
+ sdk?: SdkIdentity | null;
752
+ manifest?: CompatManifest;
753
+ }): CompatIssue[];
754
+
755
+ /**
756
+ * One-time, fire-and-forget version compatibility check.
757
+ *
758
+ * When a feature that needs a newer ingester is in use (operation logging,
759
+ * memory metrics, …), ask the ingester once — `GET /v1/compat`, or the
760
+ * `x-autter-ingester-version` header on responses the SDK already receives —
761
+ * and print ONE clear warning per incompatible feature naming both versions
762
+ * and the fix. Never throws, never blocks or delays startup or exit (the
763
+ * socket is unref'd), and is silent when versions match or can't be
764
+ * determined. Disable with `compatCheck: false` or AUTTER_COMPAT_CHECK=0.
765
+ */
766
+ declare const SDK_IDENTITY: SdkIdentity;
767
+ /**
768
+ * What the ingester at `endpoint` supports. `null` = unknown (unreachable,
769
+ * auth proxy, 5xx). A 404 on /v1/compat means a pre-compat ingester (1.4.0 or
770
+ * older); `probeRoutes` then learns which feature routes exist (an
771
+ * unauthenticated POST answers 401/503/… when the route exists, 404 when not).
772
+ */
773
+ declare function fetchIngesterCompat(endpoint: string, options?: {
774
+ probeRoutes?: string[];
775
+ unref?: boolean;
776
+ timeoutMs?: number;
777
+ }): Promise<{
778
+ info: IngesterCompatInfo | null;
779
+ report: unknown;
780
+ error?: string;
781
+ }>;
782
+
783
+ /**
784
+ * `npx @autter/runtime-node doctor` — one-shot version compatibility report:
785
+ * installed Autter SDK versions, the ingester's version and ClickHouse schema
786
+ * level, the ingest key (optional), and every feature the installed SDKs can
787
+ * use that the ingester can't store. Exit codes: 0 compatible, 1 a mismatch
788
+ * or rejected key, 2 the ingester could not be reached or identified.
789
+ */
790
+ interface DoctorOptions {
791
+ endpoint?: string;
792
+ key?: string;
793
+ features?: string[];
794
+ json?: boolean;
795
+ cwd?: string;
796
+ timeoutMs?: number;
797
+ }
798
+ interface DoctorReport {
799
+ endpoint: string;
800
+ sdks: SdkIdentity[];
801
+ ingester: IngesterCompatInfo | null;
802
+ ingesterError?: string;
803
+ key?: "accepted" | "rejected" | "client_key" | "storage_unavailable" | "unknown";
804
+ features: Array<{
805
+ id: string;
806
+ title: string;
807
+ status: "ok" | "incompatible" | "unknown";
808
+ }>;
809
+ issues: CompatIssue[];
810
+ exitCode: 0 | 1 | 2;
811
+ }
812
+ declare function runDoctor(options?: DoctorOptions): Promise<DoctorReport>;
813
+
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 };