@autter/runtime-node 1.4.0 → 1.6.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.cjs CHANGED
@@ -1,66 +1,83 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- captureException: () => captureException,
34
- captureMessage: () => captureMessage,
35
- createBrowserRelayFetchHandler: () => createBrowserRelayFetchHandler,
36
- createBrowserRelayHandler: () => createBrowserRelayHandler,
37
- createRuntimeLogger: () => createRuntimeLogger,
38
- emitLlmSelftestTrace: () => emitLlmSelftestTrace,
39
- flushRuntimeLogs: () => flushRuntimeLogs,
40
- initAutterServer: () => initAutterServer,
41
- installAutterAutoFlush: () => installAutterAutoFlush,
42
- instrumentLlmClient: () => instrumentLlmClient,
43
- makeSafeCapture: () => makeSafeCapture,
44
- redactAttributes: () => redactAttributes,
45
- reportOutcome: () => reportOutcome,
46
- runtimeLogStats: () => runtimeLogStats,
47
- runtimeLogger: () => runtimeLogger,
48
- sanitizeBrowserPayload: () => sanitizeBrowserPayload,
49
- startCaughtExceptionSampler: () => startCaughtExceptionSampler,
50
- trackLlmCall: () => trackLlmCall,
51
- withLlmCall: () => withLlmCall,
52
- withProcessSpan: () => withProcessSpan,
53
- withRuntimeOperation: () => withRuntimeOperation
54
- });
55
- module.exports = __toCommonJS(index_exports);
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+ var _chunkUKYTXZOQcjs = require('./chunk-UKYTXZOQ.cjs');
49
+
50
+
51
+ var _chunkUGNPCOIWcjs = require('./chunk-UGNPCOIW.cjs');
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+
66
+
67
+
68
+
69
+
70
+
71
+
72
+ var _chunkARN26OK6cjs = require('./chunk-ARN26OK6.cjs');
56
73
 
57
74
  // src/relay.ts
58
- var IpWindow = class {
59
- constructor(limitPerMinute) {
75
+ var IpWindow = (_class = class {
76
+ constructor(limitPerMinute) {;_class.prototype.__init.call(this);
60
77
  this.limitPerMinute = limitPerMinute;
61
78
  }
62
- limitPerMinute;
63
- windows = /* @__PURE__ */ new Map();
79
+
80
+ __init() {this.windows = /* @__PURE__ */ new Map()}
64
81
  allow(ip) {
65
82
  const start = Math.floor(Date.now() / 6e4) * 6e4;
66
83
  const entry = this.windows.get(ip);
@@ -72,10 +89,10 @@ var IpWindow = class {
72
89
  entry.count += 1;
73
90
  return entry.count <= this.limitPerMinute;
74
91
  }
75
- };
76
- function firstForwardedFor(value2) {
77
- const raw = Array.isArray(value2) ? value2[0] : value2;
78
- return raw ? (raw.split(",")[0] ?? "").trim() : "";
92
+ }, _class);
93
+ function firstForwardedFor(value) {
94
+ const raw = Array.isArray(value) ? value[0] : value;
95
+ return raw ? (_nullishCoalesce(raw.split(",")[0], () => ( ""))).trim() : "";
79
96
  }
80
97
  var DEFAULT_ENDPOINT = "https://otlp.autter.dev";
81
98
  var DEFAULT_MAX_BODY = 64 * 1024;
@@ -92,7 +109,142 @@ var EVENT_TYPES = /* @__PURE__ */ new Set([
92
109
  "timing"
93
110
  ]);
94
111
  var SEVERITIES = /* @__PURE__ */ new Set(["fatal", "error", "warning", "info"]);
95
- function sanitizeBrowserPayload(raw) {
112
+ var TRACE_ID = /^(?!0{32})[0-9a-f]{32}$/;
113
+ var CONTEXT_MAX_DEPTH = 6;
114
+ var CONTEXT_MAX_NODES = 256;
115
+ var CONTEXT_MAX_STRING = 4e3;
116
+ var CONTEXT_MAX_ARRAY = 100;
117
+ var CONTEXT_MAX_KEYS = 100;
118
+ function byteLength(text) {
119
+ return new TextEncoder().encode(text).length;
120
+ }
121
+ function boundContext(value) {
122
+ let nodes = 0;
123
+ const seen = /* @__PURE__ */ new WeakSet();
124
+ const walk = (v, depth) => {
125
+ if (v === null) return null;
126
+ const t = typeof v;
127
+ if (t === "string") return v.slice(0, CONTEXT_MAX_STRING);
128
+ if (t === "number" || t === "boolean") return v;
129
+ if (t !== "object") return void 0;
130
+ if (depth >= CONTEXT_MAX_DEPTH || nodes >= CONTEXT_MAX_NODES) return void 0;
131
+ const obj = v;
132
+ if (seen.has(obj)) return void 0;
133
+ seen.add(obj);
134
+ let isArr = false;
135
+ try {
136
+ isArr = Array.isArray(v);
137
+ } catch (e2) {
138
+ return void 0;
139
+ }
140
+ if (isArr) {
141
+ const arr = v;
142
+ const out2 = [];
143
+ let len = 0;
144
+ try {
145
+ len = arr.length;
146
+ } catch (e3) {
147
+ return out2;
148
+ }
149
+ for (let i = 0; i < len && i < CONTEXT_MAX_ARRAY; i++) {
150
+ if (nodes >= CONTEXT_MAX_NODES) break;
151
+ nodes++;
152
+ let el;
153
+ try {
154
+ el = walk(arr[i], depth + 1);
155
+ } catch (e4) {
156
+ el = void 0;
157
+ }
158
+ if (el !== void 0) out2.push(el);
159
+ }
160
+ return out2;
161
+ }
162
+ let keys;
163
+ try {
164
+ keys = Object.keys(obj);
165
+ } catch (e5) {
166
+ return void 0;
167
+ }
168
+ const out = {};
169
+ for (let i = 0; i < keys.length && i < CONTEXT_MAX_KEYS; i++) {
170
+ if (nodes >= CONTEXT_MAX_NODES) break;
171
+ const key = keys[i];
172
+ if (key === void 0) continue;
173
+ nodes++;
174
+ let child;
175
+ try {
176
+ child = walk(obj[key], depth + 1);
177
+ } catch (e6) {
178
+ child = void 0;
179
+ }
180
+ if (child !== void 0) out[key] = child;
181
+ }
182
+ return out;
183
+ };
184
+ let result;
185
+ try {
186
+ result = walk(value, 0);
187
+ } catch (e7) {
188
+ result = void 0;
189
+ }
190
+ return result && typeof result === "object" ? result : {};
191
+ }
192
+ async function readBodyBounded(request, maxBody) {
193
+ const body = request.body;
194
+ if (!body) {
195
+ const text = await request.text();
196
+ return byteLength(text) > maxBody ? { tooLarge: true } : { tooLarge: false, text };
197
+ }
198
+ const reader = body.getReader();
199
+ const chunks = [];
200
+ let total = 0;
201
+ for (; ; ) {
202
+ const { done, value } = await reader.read();
203
+ if (done) break;
204
+ if (!value) continue;
205
+ total += value.byteLength;
206
+ if (total > maxBody) {
207
+ void Promise.resolve().then(() => reader.cancel()).catch(() => {
208
+ });
209
+ return { tooLarge: true };
210
+ }
211
+ chunks.push(value);
212
+ }
213
+ const buf = new Uint8Array(total);
214
+ let offset = 0;
215
+ for (const chunk of chunks) {
216
+ buf.set(chunk, offset);
217
+ offset += chunk.byteLength;
218
+ }
219
+ return { tooLarge: false, text: new TextDecoder().decode(buf) };
220
+ }
221
+ function relayContext(raw, redactor) {
222
+ const bounded = boundContext(raw);
223
+ return Array.isArray(bounded) ? {} : { context: redactor(bounded) };
224
+ }
225
+ function relayBreadcrumbs(raw, redactor) {
226
+ const breadcrumbs = _chunkUKYTXZOQcjs.sanitizeBreadcrumbs.call(void 0, raw, redactor);
227
+ return breadcrumbs ? { breadcrumbs } : {};
228
+ }
229
+ var DEBUG_ID_RE = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
230
+ function relayDebugIds(raw, redactor) {
231
+ if (typeof raw !== "object" || raw === null || Array.isArray(raw)) return {};
232
+ const debugIds = {};
233
+ let count = 0;
234
+ for (const [url, id] of Object.entries(raw)) {
235
+ if (count >= 50) break;
236
+ if (typeof id !== "string" || !DEBUG_ID_RE.test(id) || url.length > 1e3) continue;
237
+ debugIds[redactor.text(url.split(/[?#]/)[0])] = id.toLowerCase();
238
+ count++;
239
+ }
240
+ return count ? { debugIds } : {};
241
+ }
242
+ function relayFingerprint(raw, redactor) {
243
+ const values = _chunkUKYTXZOQcjs.fingerprintValues.call(void 0, raw, redactor.text);
244
+ return values ? { fingerprint: Array.isArray(raw) ? values : values[0] } : {};
245
+ }
246
+ var defaultRelayRedactor = _chunkUKYTXZOQcjs.makeRedactor.call(void 0, true);
247
+ function sanitizeBrowserPayload(raw, redactor = defaultRelayRedactor) {
96
248
  if (typeof raw !== "object" || raw === null) return null;
97
249
  const p = raw;
98
250
  if (p.version !== 1) return null;
@@ -109,16 +261,20 @@ function sanitizeBrowserPayload(raw) {
109
261
  type: e.type,
110
262
  timestamp: e.timestamp,
111
263
  ...typeof e.severity === "string" && SEVERITIES.has(e.severity) ? { severity: e.severity } : {},
112
- message: typeof e.message === "string" ? e.message.slice(0, 4e3) : "",
113
- ...typeof e.name === "string" ? { name: e.name.slice(0, 200) } : {},
264
+ message: typeof e.message === "string" ? redactor.text(e.message.slice(0, 4512)).slice(0, 4e3) : "",
265
+ ...typeof e.name === "string" ? { name: redactor.text(e.name.slice(0, 712)).slice(0, 200) } : {},
114
266
  ...typeof e.durationMs === "number" && Number.isFinite(e.durationMs) ? { durationMs: Math.max(0, Math.min(12e4, e.durationMs)) } : {},
115
- ...typeof e.stack === "string" ? { stack: e.stack.slice(0, 32e3) } : {},
267
+ ...typeof e.stack === "string" ? { stack: redactor.text(e.stack.slice(0, 32512)).slice(0, 32e3) } : {},
116
268
  ...typeof e.errorType === "string" ? { errorType: e.errorType.slice(0, 200) } : {},
117
269
  ...typeof e.filename === "string" ? { filename: e.filename.split("?")[0].slice(0, 1e3) } : {},
118
270
  ...typeof e.line === "number" ? { line: e.line } : {},
119
271
  ...typeof e.column === "number" ? { column: e.column } : {},
120
272
  ...typeof e.route === "string" ? { route: e.route.split("?")[0].slice(0, 1e3) } : {},
121
- ...typeof e.context === "object" && e.context !== null ? { context: e.context } : {}
273
+ ...typeof e.context === "object" && e.context !== null ? relayContext(e.context, redactor) : {},
274
+ ...relayBreadcrumbs(e.breadcrumbs, redactor),
275
+ ...relayDebugIds(e.debugIds, redactor),
276
+ ...relayFingerprint(e.fingerprint, redactor),
277
+ ...typeof e.traceId === "string" && TRACE_ID.test(e.traceId) ? { traceId: e.traceId } : {}
122
278
  });
123
279
  }
124
280
  return {
@@ -127,11 +283,16 @@ function sanitizeBrowserPayload(raw) {
127
283
  service: p.service.slice(0, 200),
128
284
  environment: p.environment.slice(0, 100),
129
285
  ...typeof p.release === "string" ? { release: p.release.slice(0, 200) } : {},
286
+ // @autter/runtime-browser version, for the ingester's compat records.
287
+ ...typeof p.sdk === "string" && /^\d{1,6}\.\d{1,6}\.\d{1,6}[0-9A-Za-z.+-]{0,20}$/.test(p.sdk) ? { sdk: p.sdk } : {},
130
288
  events
131
289
  };
132
290
  }
133
291
  function forward(payload, opts) {
134
- const url = `${(opts.endpoint ?? DEFAULT_ENDPOINT).replace(/\/$/, "")}/v1/browser`;
292
+ const endpoint = (_nullishCoalesce(opts.endpoint, () => ( DEFAULT_ENDPOINT))).replace(/\/$/, "");
293
+ const url = `${endpoint}/v1/browser`;
294
+ const compat = opts.compatCheck !== false;
295
+ if (compat) _chunkARN26OK6cjs.ensureCompatConfigured.call(void 0, endpoint);
135
296
  void fetch(url, {
136
297
  method: "POST",
137
298
  headers: {
@@ -140,15 +301,27 @@ function forward(payload, opts) {
140
301
  },
141
302
  body: JSON.stringify(payload),
142
303
  signal: AbortSignal.timeout(1e4)
304
+ }).then((response) => {
305
+ if (!compat) return;
306
+ const types = new Set(
307
+ (_nullishCoalesce(payload.events, () => ( []))).map((e) => String(e.type))
308
+ );
309
+ _chunkARN26OK6cjs.observeIngesterResponse.call(void 0, { status: response.status, headers: response.headers });
310
+ for (const feature of _chunkARN26OK6cjs.featuresForBrowserEvents.call(void 0, types)) _chunkARN26OK6cjs.noteCompatFeature.call(void 0, feature);
311
+ if ((_nullishCoalesce(payload.events, () => ( []))).some((e) => e.traceId)) {
312
+ _chunkARN26OK6cjs.noteCompatFeature.call(void 0, "browser_trace_propagation");
313
+ }
314
+ _chunkARN26OK6cjs.noteRelayRejection.call(void 0, types, response.status, response.headers);
143
315
  }).catch((err) => {
144
- (opts.onError ?? ((e) => console.warn("autter relay forward failed:", e)))(
316
+ (_nullishCoalesce(opts.onError, () => ( ((e) => console.warn("autter relay forward failed:", e)))))(
145
317
  err
146
318
  );
147
319
  });
148
320
  }
149
321
  function createBrowserRelayFetchHandler(opts) {
150
- const maxBody = opts.maxBodyBytes ?? DEFAULT_MAX_BODY;
151
- const limiter = opts.perIpRateLimit === false ? null : new IpWindow(opts.perIpRateLimit ?? 120);
322
+ const maxBody = _nullishCoalesce(opts.maxBodyBytes, () => ( DEFAULT_MAX_BODY));
323
+ const redactor = opts.redact === void 0 || opts.redact === true ? defaultRelayRedactor : _chunkUKYTXZOQcjs.makeRedactor.call(void 0, opts.redact);
324
+ const limiter = opts.perIpRateLimit === false ? null : new IpWindow(_nullishCoalesce(opts.perIpRateLimit, () => ( 120)));
152
325
  return async (request) => {
153
326
  if (request.method !== "POST") {
154
327
  return new Response(null, { status: 405 });
@@ -161,21 +334,28 @@ function createBrowserRelayFetchHandler(opts) {
161
334
  });
162
335
  }
163
336
  }
164
- const text = await request.text();
165
- if (text.length > maxBody) {
337
+ let bounded;
338
+ try {
339
+ bounded = await readBodyBounded(request, maxBody);
340
+ } catch (e8) {
341
+ return new Response(JSON.stringify({ error: "invalid json" }), {
342
+ status: 400
343
+ });
344
+ }
345
+ if (bounded.tooLarge) {
166
346
  return new Response(JSON.stringify({ error: "payload too large" }), {
167
347
  status: 413
168
348
  });
169
349
  }
170
350
  let raw;
171
351
  try {
172
- raw = JSON.parse(text);
173
- } catch {
352
+ raw = JSON.parse(bounded.text);
353
+ } catch (e9) {
174
354
  return new Response(JSON.stringify({ error: "invalid json" }), {
175
355
  status: 400
176
356
  });
177
357
  }
178
- const payload = sanitizeBrowserPayload(raw);
358
+ const payload = sanitizeBrowserPayload(raw, redactor);
179
359
  if (!payload) {
180
360
  return new Response(JSON.stringify({ error: "invalid payload" }), {
181
361
  status: 400
@@ -186,8 +366,9 @@ function createBrowserRelayFetchHandler(opts) {
186
366
  };
187
367
  }
188
368
  function createBrowserRelayHandler(opts) {
189
- const maxBody = opts.maxBodyBytes ?? DEFAULT_MAX_BODY;
190
- const limiter = opts.perIpRateLimit === false ? null : new IpWindow(opts.perIpRateLimit ?? 120);
369
+ const maxBody = _nullishCoalesce(opts.maxBodyBytes, () => ( DEFAULT_MAX_BODY));
370
+ const redactor = opts.redact === void 0 || opts.redact === true ? defaultRelayRedactor : _chunkUKYTXZOQcjs.makeRedactor.call(void 0, opts.redact);
371
+ const limiter = opts.perIpRateLimit === false ? null : new IpWindow(_nullishCoalesce(opts.perIpRateLimit, () => ( 120)));
191
372
  function respond(res, status, body) {
192
373
  res.statusCode = status;
193
374
  if (body) {
@@ -198,7 +379,7 @@ function createBrowserRelayHandler(opts) {
198
379
  }
199
380
  }
200
381
  function handleParsed(raw, res) {
201
- const payload = sanitizeBrowserPayload(raw);
382
+ const payload = sanitizeBrowserPayload(raw, redactor);
202
383
  if (!payload) {
203
384
  respond(res, 400, { error: "invalid payload" });
204
385
  return;
@@ -212,7 +393,7 @@ function createBrowserRelayHandler(opts) {
212
393
  return;
213
394
  }
214
395
  if (limiter) {
215
- const ip = firstForwardedFor(req.headers["x-forwarded-for"]) || req.socket?.remoteAddress || "unknown";
396
+ const ip = firstForwardedFor(req.headers["x-forwarded-for"]) || _optionalChain([req, 'access', _ => _.socket, 'optionalAccess', _2 => _2.remoteAddress]) || "unknown";
216
397
  if (!limiter.allow(ip)) {
217
398
  respond(res, 429, { error: "rate limit exceeded" });
218
399
  return;
@@ -223,7 +404,7 @@ function createBrowserRelayHandler(opts) {
223
404
  if (typeof raw === "string" || Buffer.isBuffer(raw)) {
224
405
  try {
225
406
  raw = JSON.parse(raw.toString());
226
- } catch {
407
+ } catch (e10) {
227
408
  respond(res, 400, { error: "invalid json" });
228
409
  return;
229
410
  }
@@ -248,7 +429,7 @@ function createBrowserRelayHandler(opts) {
248
429
  if (aborted) return;
249
430
  try {
250
431
  handleParsed(JSON.parse(Buffer.concat(chunks).toString()), res);
251
- } catch {
432
+ } catch (e11) {
252
433
  respond(res, 400, { error: "invalid json" });
253
434
  }
254
435
  });
@@ -259,466 +440,162 @@ function createBrowserRelayHandler(opts) {
259
440
  }
260
441
 
261
442
  // src/server.ts
262
- var import_node_http = require("http");
263
- var import_node_crypto2 = require("crypto");
264
- var import_api3 = require("@opentelemetry/api");
265
- var import_core2 = require("@opentelemetry/core");
266
- var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
267
- var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
268
- var import_instrumentation_http = require("@opentelemetry/instrumentation-http");
269
- var import_resources = require("@opentelemetry/resources");
270
- var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
271
- var import_sdk_node = require("@opentelemetry/sdk-node");
272
- var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
273
- var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
274
-
275
- // src/lifecycle.ts
276
- var import_core = require("@opentelemetry/core");
277
- var debugEnabled = process.env.AUTTER_DEBUG === "1" || process.env.AUTTER_DEBUG === "true";
278
- function setDebugMode(enabled) {
279
- debugEnabled = enabled;
280
- }
281
- function isDebugEnabled() {
282
- return debugEnabled;
283
- }
284
- function debugLog(...args) {
285
- if (debugEnabled) {
286
- console.error("[autter]", ...args);
287
- }
288
- }
289
- var TelemetryStats = class {
290
- /** Captures queued via our APIs and not yet seen leaving an exporter. */
291
- pendingCaptures = 0;
292
- markCaptured(count = 1) {
293
- this.pendingCaptures += count;
294
- }
295
- /** An exporter batch left the process successfully. */
296
- onExported(spanCount) {
297
- this.pendingCaptures = Math.max(0, this.pendingCaptures - spanCount);
298
- if (debugEnabled && spanCount > 0) {
299
- debugLog(`exported ${spanCount} span${spanCount === 1 ? "" : "s"}`);
300
- }
301
- }
302
- markAllFlushed() {
303
- this.pendingCaptures = 0;
304
- }
305
- };
306
- var telemetryStats = new TelemetryStats();
307
- var CountingExporter = class {
308
- constructor(inner) {
443
+ var _http = require('http');
444
+ var _crypto = require('crypto');
445
+
446
+
447
+
448
+
449
+
450
+
451
+ var _api = require('@opentelemetry/api');
452
+ var _core = require('@opentelemetry/core');
453
+
454
+
455
+
456
+ var _exportermetricsotlphttp = require('@opentelemetry/exporter-metrics-otlp-http');
457
+ var _exportertraceotlphttp = require('@opentelemetry/exporter-trace-otlp-http');
458
+ var _instrumentationhttp = require('@opentelemetry/instrumentation-http');
459
+ var _resources = require('@opentelemetry/resources');
460
+ var _sdkmetrics = require('@opentelemetry/sdk-metrics');
461
+ var _sdknode = require('@opentelemetry/sdk-node');
462
+
463
+
464
+
465
+
466
+
467
+
468
+
469
+ var _sdktracebase = require('@opentelemetry/sdk-trace-base');
470
+
471
+
472
+
473
+ var _semanticconventions = require('@opentelemetry/semantic-conventions');
474
+
475
+ // src/redact-exporter.ts
476
+
477
+
478
+
479
+
480
+
481
+ var scrubbedResources = /* @__PURE__ */ new WeakMap();
482
+ function redactResource(resource, redactor) {
483
+ const cached = scrubbedResources.get(resource);
484
+ if (cached) return cached;
485
+ const scrubbed = new (0, _resources.Resource)(redactor.exported(resource.attributes));
486
+ scrubbedResources.set(resource, scrubbed);
487
+ return scrubbed;
488
+ }
489
+ function redactSpan(span, redactor) {
490
+ const status = span.status.message ? { ...span.status, message: redactor.text(span.status.message) } : span.status;
491
+ return {
492
+ name: redactor.text(span.name),
493
+ kind: span.kind,
494
+ spanContext: () => span.spanContext(),
495
+ parentSpanId: span.parentSpanId,
496
+ startTime: span.startTime,
497
+ endTime: span.endTime,
498
+ status,
499
+ attributes: redactor.exported(span.attributes),
500
+ links: span.links.map(
501
+ (link) => link.attributes ? { ...link, attributes: redactor.exported(link.attributes) } : link
502
+ ),
503
+ events: span.events.map((event) => ({
504
+ ...event,
505
+ name: redactor.text(event.name),
506
+ ...event.attributes ? { attributes: redactor.exported(event.attributes) } : {}
507
+ })),
508
+ duration: span.duration,
509
+ ended: span.ended,
510
+ resource: redactResource(span.resource, redactor),
511
+ instrumentationLibrary: span.instrumentationLibrary,
512
+ droppedAttributesCount: span.droppedAttributesCount,
513
+ droppedEventsCount: span.droppedEventsCount,
514
+ droppedLinksCount: span.droppedLinksCount
515
+ };
516
+ }
517
+ var RedactingSpanExporter = class {
518
+ constructor(inner, redactor) {
309
519
  this.inner = inner;
520
+ this.redactor = redactor;
310
521
  }
311
- inner;
522
+
523
+
312
524
  export(spans, resultCallback) {
313
- this.inner.export(spans, (result) => {
314
- if (result.code === import_core.ExportResultCode.SUCCESS) {
315
- telemetryStats.onExported(spans.length);
525
+ const redactor = this.redactor();
526
+ let scrubbed = spans;
527
+ let failed = 0;
528
+ if (redactor.enabled) {
529
+ scrubbed = [];
530
+ for (const span of spans) {
531
+ try {
532
+ scrubbed.push(redactSpan(span, redactor));
533
+ } catch (e12) {
534
+ failed++;
535
+ }
316
536
  }
317
- resultCallback(result);
318
- });
537
+ }
538
+ if (!failed) {
539
+ this.inner.export(scrubbed, resultCallback);
540
+ return;
541
+ }
542
+ const error = new Error(`autter-runtime: ${failed} span(s) could not be redacted and were not exported`);
543
+ const fail = () => resultCallback({ code: _core.ExportResultCode.FAILED, error });
544
+ if (!scrubbed.length) {
545
+ fail();
546
+ return;
547
+ }
548
+ this.inner.export(
549
+ scrubbed,
550
+ (result) => result.code === _core.ExportResultCode.SUCCESS ? fail() : resultCallback(result)
551
+ );
319
552
  }
320
553
  shutdown() {
321
554
  return this.inner.shutdown();
322
555
  }
323
556
  forceFlush() {
324
- return this.inner.forceFlush?.() ?? Promise.resolve();
557
+ return _nullishCoalesce(_optionalChain([this, 'access', _3 => _3.inner, 'access', _4 => _4.forceFlush, 'optionalCall', _5 => _5()]), () => ( Promise.resolve()));
325
558
  }
326
559
  };
327
- var flushTargets = /* @__PURE__ */ new Map();
328
- function registerFlushTarget(key, target) {
329
- flushTargets.set(key, target);
330
- }
331
- function unregisterFlushTargets() {
332
- flushTargets.clear();
333
- }
334
- function activeFlushTargets() {
335
- return [...flushTargets.values()];
336
- }
337
- var DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
338
- var SIGNAL_EXIT_CODES = {
339
- SIGINT: 130,
340
- SIGTERM: 143
341
- };
342
- function installAutterAutoFlush(options = {}) {
343
- const logger = options.logger ?? console;
344
- const log = options.log !== false;
345
- const warnOnUnflushedExit = options.warnOnUnflushedExit !== false;
346
- const timeoutMs = Math.max(100, options.timeoutMs ?? 3e3);
347
- const signals = options.signals ?? DEFAULT_SIGNALS;
348
- const flushOnUncaughtException = options.flushOnUncaughtException !== false;
349
- let disposed = false;
350
- let inFlight2 = null;
351
- const doFlush = async () => {
352
- const targets = options.targets ?? activeFlushTargets();
353
- if (targets.length === 0) return true;
354
- let timer2;
355
- const timedOut = new Promise((resolve) => {
356
- timer2 = setTimeout(() => resolve(false), timeoutMs);
357
- });
358
- const drained = Promise.allSettled(
359
- targets.map(
360
- (target) => Promise.resolve().then(() => target.forceFlush())
361
- )
362
- ).then(
363
- (results) => results.every((result) => result.status === "fulfilled")
364
- );
365
- let ok;
366
- try {
367
- ok = await Promise.race([drained, timedOut]);
368
- } finally {
369
- clearTimeout(timer2);
370
- }
371
- if (ok) {
372
- telemetryStats.markAllFlushed();
373
- if (log) {
374
- logger.log("[autter] telemetry flushed");
375
- }
376
- } else {
377
- logger.error(
378
- `[autter] flush did not finish within ${timeoutMs}ms \u2014 some telemetry may be lost`
379
- );
380
- }
381
- return ok;
382
- };
383
- const flush = (reason = "exit") => {
384
- if (disposed) return Promise.resolve(false);
385
- if (!inFlight2) {
386
- inFlight2 = doFlush().finally(() => {
387
- inFlight2 = null;
388
- });
389
- }
390
- if (isDebugEnabled()) debugLog(`auto-flush requested on ${reason}`);
391
- return inFlight2;
392
- };
393
- const signalCounts = /* @__PURE__ */ new Map();
394
- let handlingUncaughtException = false;
395
- const onUncaughtException = (error) => {
396
- if (process.listenerCount("uncaughtException") > 1) return;
397
- if (handlingUncaughtException) return;
398
- handlingUncaughtException = true;
399
- logger.error(error instanceof Error ? error.stack ?? error.message : String(error));
400
- const keepAlive = setTimeout(() => {
401
- }, timeoutMs + 50);
402
- void flush("uncaughtException").finally(() => {
403
- clearTimeout(keepAlive);
404
- process.exit(1);
405
- });
406
- };
407
- const onSignal = (signal) => {
408
- const count = (signalCounts.get(signal) ?? 0) + 1;
409
- signalCounts.set(signal, count);
410
- const exitCode = SIGNAL_EXIT_CODES[signal] ?? 1;
411
- if (count > 1) {
412
- process.exit(exitCode);
413
- }
414
- const otherHandlers = process.listenerCount(signal) - 1;
415
- if (otherHandlers > 0) {
416
- void flush(signal);
560
+ var RedactingMetricExporter = class {
561
+ constructor(inner, redactor) {
562
+ this.inner = inner;
563
+ this.redactor = redactor;
564
+ }
565
+
566
+
567
+ export(metrics2, resultCallback) {
568
+ const redactor = this.redactor();
569
+ if (!redactor.enabled) {
570
+ this.inner.export(metrics2, resultCallback);
417
571
  return;
418
572
  }
419
- void flush(signal).finally(() => {
420
- process.exit(exitCode);
421
- });
422
- };
423
- const MAX_BEFORE_EXIT_FLUSHES = 10;
424
- let beforeExitFlushes = 0;
425
- const onBeforeExit = () => {
426
- if (disposed) return;
427
- const targets = options.targets ?? activeFlushTargets();
428
- const worthIt = beforeExitFlushes === 0 ? targets.length > 0 : telemetryStats.pendingCaptures > 0;
429
- if (!worthIt || beforeExitFlushes >= MAX_BEFORE_EXIT_FLUSHES) return;
430
- beforeExitFlushes++;
431
- const keepAlive = setTimeout(() => {
432
- }, timeoutMs);
433
- void flush("beforeExit").finally(() => clearTimeout(keepAlive));
434
- };
435
- const onExit = () => {
436
- if (!warnOnUnflushedExit || disposed) return;
437
- const pending = telemetryStats.pendingCaptures;
438
- if (pending > 0) {
439
- logger.error(
440
- `[autter] process exiting with ~${pending} captured item(s) never confirmed exported \u2014 await autter.shutdown() on graceful shutdown`
441
- );
442
- }
443
- };
444
- const signalHandlers = /* @__PURE__ */ new Map();
445
- process.on("beforeExit", onBeforeExit);
446
- if (flushOnUncaughtException) {
447
- process.on("uncaughtException", onUncaughtException);
448
- }
449
- for (const signal of signals) {
450
- const handler = () => onSignal(signal);
451
- signalHandlers.set(signal, handler);
452
- process.on(signal, handler);
453
- }
454
- process.on("exit", onExit);
455
- return {
456
- flush,
457
- dispose() {
458
- disposed = true;
459
- process.removeListener("beforeExit", onBeforeExit);
460
- process.removeListener("uncaughtException", onUncaughtException);
461
- process.removeListener("exit", onExit);
462
- for (const [signal, handler] of signalHandlers) {
463
- process.removeListener(signal, handler);
464
- }
465
- signalHandlers.clear();
466
- }
467
- };
468
- }
469
-
470
- // src/redact.ts
471
- var SENSITIVE_KEY_PATTERNS = [
472
- /e-?mail/,
473
- /pass(word|wd|phrase)|^pass$/,
474
- /token/,
475
- /secret/,
476
- /credential/,
477
- /(api|access|secret|private|consumer|client|signing|encryption)-?[_.]?key/,
478
- /^-?x?-?authorization$|^auth(-|_|$)|bearer/,
479
- /cookie/,
480
- /phone|msisdn/,
481
- /\bssn\b|social[-_ ]?security/,
482
- /cvv|cvc|card([-_. ]?(number|num|no))?$/,
483
- /credit[-_.]?card/,
484
- /connection[-_.]?string/,
485
- /recovery[-_.]?code|\botp\b|magic[-_.]?link/
486
- ];
487
- var PRIVATE_KEY_BLOCK_RE = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g;
488
- var EMAIL_VALUE_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
489
- var JWT_RE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g;
490
- var OPENAI_KEY_RE = /\bsk-[A-Za-z0-9]{20,}\b/g;
491
- var GITHUB_TOKEN_RE = /\bgh[pousr]_[A-Za-z0-9]{20,}\b/g;
492
- var AWS_KEY_RE = /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g;
493
- var SLACK_TOKEN_RE = /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g;
494
- var BEARER_RE = /\bbearer\s+[A-Za-z0-9._~+/=-]{10,}/gi;
495
- var URL_CREDENTIALS_RE = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/:@]+:[^\s/@]+@/gi;
496
- function toCaseInsensitive(pattern) {
497
- return typeof pattern === "string" ? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i") : new RegExp(pattern.source, pattern.flags.includes("i") ? pattern.flags : `${pattern.flags}i`);
498
- }
499
- function compile(options) {
500
- const keyPatterns = [...SENSITIVE_KEY_PATTERNS];
501
- const valuePatterns = [
502
- JWT_RE,
503
- OPENAI_KEY_RE,
504
- GITHUB_TOKEN_RE,
505
- AWS_KEY_RE,
506
- SLACK_TOKEN_RE,
507
- BEARER_RE
508
- ];
509
- if (options?.additionalKeyPatterns) {
510
- for (const p of options.additionalKeyPatterns) {
511
- keyPatterns.push(toCaseInsensitive(p));
512
- }
513
- }
514
- if (options?.additionalValuePatterns) {
515
- for (const p of options.additionalValuePatterns) {
516
- if (!valuePatterns.some((existing) => existing.source === (typeof p === "string" ? p : p.source))) {
517
- valuePatterns.push(typeof p === "string" ? new RegExp(p, "gi") : p);
518
- }
519
- }
520
- }
521
- return {
522
- keyPatterns,
523
- valuePatterns,
524
- urlCredentials: URL_CREDENTIALS_RE,
525
- privateKeyBlock: PRIVATE_KEY_BLOCK_RE,
526
- mask: options?.mask ?? "[redacted]",
527
- scrubEmailValues: options?.scrubEmailValues !== false
528
- };
529
- }
530
- function redactString(value2, r) {
531
- let out = value2.replace(r.privateKeyBlock, r.mask);
532
- for (const re of r.valuePatterns) {
533
- out = out.replace(re, r.mask);
534
- }
535
- out = out.replace(r.urlCredentials, "$1" + r.mask + "@");
536
- if (r.scrubEmailValues) {
537
- out = out.replace(EMAIL_VALUE_RE, r.mask);
538
- }
539
- return out;
540
- }
541
- var MAX_REDACTION_DEPTH = 64;
542
- var MAX_REDACTION_WORK = 1e4;
543
- var MAX_COLLECTION_ENTRIES = 1e3;
544
- function canTraverse(depth, state) {
545
- if (depth > MAX_REDACTION_DEPTH || state.remainingWork <= 0) return false;
546
- state.remainingWork -= 1;
547
- return true;
548
- }
549
- function redactValue(value2, r, state, depth) {
550
- if (typeof value2 === "string") return redactString(value2, r);
551
- let isArray = false;
552
- try {
553
- isArray = Array.isArray(value2);
554
- } catch {
555
- return r.mask;
556
- }
557
- if (isArray) {
558
- return redactArray(value2, r, state, depth);
559
- }
560
- if (typeof value2 === "object" && value2 !== null) {
561
- return redactObject(value2, r, state, depth);
562
- }
563
- return value2;
564
- }
565
- function redactArray(value2, r, state, depth) {
566
- const existing = state.ancestors.get(value2);
567
- if (existing) return r.mask;
568
- if (!canTraverse(depth, state)) return r.mask;
569
- const out = [];
570
- state.ancestors.set(value2, out);
571
- let length;
572
- try {
573
- length = value2.length;
574
- } catch {
575
- state.ancestors.delete(value2);
576
- return r.mask;
577
- }
578
- const limit = Math.min(length, MAX_COLLECTION_ENTRIES);
579
- for (let i = 0; i < limit; i += 1) {
580
- let item;
573
+ let resource;
581
574
  try {
582
- item = value2[i];
583
- } catch {
584
- out.push(r.mask);
585
- continue;
575
+ resource = redactResource(metrics2.resource, redactor);
576
+ } catch (error) {
577
+ resultCallback({ code: _core.ExportResultCode.FAILED, error });
578
+ return;
586
579
  }
587
- out.push(redactValue(item, r, state, depth + 1));
588
- }
589
- if (length > limit) {
590
- out.push(r.mask);
580
+ this.inner.export({ ...metrics2, resource }, resultCallback);
591
581
  }
592
- state.ancestors.delete(value2);
593
- return out;
594
- }
595
- function redactObject(value2, r, state, depth) {
596
- const existing = state.ancestors.get(value2);
597
- if (existing) return r.mask;
598
- if (!canTraverse(depth, state)) return r.mask;
599
- const out = {};
600
- state.ancestors.set(value2, out);
601
- let count = 0;
602
- let truncated = false;
603
- try {
604
- for (const key in value2) {
605
- if (!Object.prototype.propertyIsEnumerable.call(
606
- value2,
607
- key
608
- )) {
609
- continue;
610
- }
611
- if (count >= MAX_COLLECTION_ENTRIES) {
612
- truncated = true;
613
- break;
614
- }
615
- let nestedValue;
616
- try {
617
- nestedValue = value2[key];
618
- } catch {
619
- out[key] = r.mask;
620
- count += 1;
621
- continue;
622
- }
623
- count += 1;
624
- out[key] = isSensitiveKey(key, nestedValue, r) ? r.mask : redactValue(
625
- nestedValue,
626
- r,
627
- state,
628
- depth + 1
629
- );
630
- }
631
- } catch {
632
- truncated = true;
633
- }
634
- if (truncated) {
635
- out.__redaction_truncated__ = r.mask;
636
- }
637
- state.ancestors.delete(value2);
638
- return out;
639
- }
640
- var USAGE_TOKEN_KEYS = /* @__PURE__ */ new Set([
641
- "input_tokens",
642
- "output_tokens",
643
- "prompt_tokens",
644
- "completion_tokens",
645
- "total_tokens",
646
- "token_count",
647
- "gen_ai.usage.input_tokens",
648
- "gen_ai.usage.output_tokens",
649
- "gen_ai.usage.prompt_tokens",
650
- "gen_ai.usage.completion_tokens",
651
- "gen_ai.usage.total_tokens",
652
- "gen_ai.usage.token_count"
653
- ]);
654
- function isSensitiveKey(key, value2, r) {
655
- const lowered = key.toLowerCase();
656
- if (USAGE_TOKEN_KEYS.has(lowered)) {
657
- return !(typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0);
658
- }
659
- return r.keyPatterns.some((re) => re.test(lowered));
660
- }
661
- function redactAttributes(attributes, options) {
662
- const r = compile(options);
663
- return redactWith(attributes, r);
664
- }
665
- function redactWith(attributes, r) {
666
- const out = {};
667
- if (!attributes) return out;
668
- const state = {
669
- ancestors: /* @__PURE__ */ new WeakMap(),
670
- remainingWork: MAX_REDACTION_WORK
671
- };
672
- let count = 0;
673
- let truncated = false;
674
- try {
675
- for (const key in attributes) {
676
- if (!Object.prototype.propertyIsEnumerable.call(
677
- attributes,
678
- key
679
- )) {
680
- continue;
681
- }
682
- if (count >= MAX_COLLECTION_ENTRIES || state.remainingWork <= 0) {
683
- truncated = true;
684
- break;
685
- }
686
- let value2;
687
- try {
688
- value2 = attributes[key];
689
- } catch {
690
- out[key] = r.mask;
691
- count += 1;
692
- state.remainingWork -= 1;
693
- continue;
694
- }
695
- count += 1;
696
- state.remainingWork -= 1;
697
- if (value2 === void 0) continue;
698
- out[key] = isSensitiveKey(key, value2, r) ? r.mask : redactValue(value2, r, state, 0);
699
- }
700
- } catch {
701
- truncated = true;
582
+ forceFlush() {
583
+ return this.inner.forceFlush();
702
584
  }
703
- if (truncated) {
704
- out.__redaction_truncated__ = r.mask;
585
+ shutdown() {
586
+ return this.inner.shutdown();
705
587
  }
706
- return out;
707
- }
708
- function makeRedactor(options) {
709
- if (options === false) {
710
- return (attributes) => ({ ...attributes ?? {} });
588
+ selectAggregationTemporality(instrumentType) {
589
+ return this.inner.selectAggregationTemporality ? this.inner.selectAggregationTemporality(instrumentType) : _sdkmetrics.AggregationTemporality.CUMULATIVE;
711
590
  }
712
- const r = compile(options === true ? void 0 : options);
713
- return (attributes) => redactWith(attributes, r);
714
- }
591
+ };
715
592
 
716
593
  // src/memory.ts
717
- var import_node_perf_hooks = require("perf_hooks");
718
- var import_node_v8 = require("v8");
719
- var import_api = require("@opentelemetry/api");
594
+ var _perf_hooks = require('perf_hooks');
595
+ var _v8 = require('v8');
596
+
720
597
  function startMemoryMetrics() {
721
- const meter = import_api.metrics.getMeter("autter-process-memory");
598
+ const meter = _api.metrics.getMeter("autter-process-memory");
722
599
  const rss = meter.createObservableGauge("autter.process.memory.rss", { unit: "By" });
723
600
  const heapUsed = meter.createObservableGauge("autter.process.memory.heap.used", { unit: "By" });
724
601
  const heapLimit = meter.createObservableGauge("autter.process.memory.heap.limit", { unit: "By" });
@@ -732,9 +609,9 @@ function startMemoryMetrics() {
732
609
  const callbacks = [
733
610
  [rss, (result) => result.observe(process.memoryUsage().rss)],
734
611
  [heapUsed, (result) => result.observe(process.memoryUsage().heapUsed)],
735
- [heapLimit, (result) => result.observe((0, import_node_v8.getHeapStatistics)().heap_size_limit)],
612
+ [heapLimit, (result) => result.observe(_v8.getHeapStatistics.call(void 0, ).heap_size_limit)],
736
613
  [containerLimit, (result) => {
737
- const constrained = process.constrainedMemory?.() ?? 0;
614
+ const constrained = _nullishCoalesce(_optionalChain([process, 'access', _6 => _6.constrainedMemory, 'optionalCall', _7 => _7()]), () => ( 0));
738
615
  if (constrained > 0) result.observe(constrained);
739
616
  }],
740
617
  [afterGc, (result) => {
@@ -744,7 +621,7 @@ function startMemoryMetrics() {
744
621
  [gcDuration, (result) => result.observe(durationMs)]
745
622
  ];
746
623
  for (const [instrument, callback] of callbacks) instrument.addCallback(callback);
747
- const observer = new import_node_perf_hooks.PerformanceObserver((list) => {
624
+ const observer = new (0, _perf_hooks.PerformanceObserver)((list) => {
748
625
  for (const entry of list.getEntries()) {
749
626
  collections++;
750
627
  durationMs += entry.duration;
@@ -758,388 +635,544 @@ function startMemoryMetrics() {
758
635
  };
759
636
  }
760
637
 
761
- // src/logger.ts
762
- var import_node_async_hooks = require("async_hooks");
763
- var import_node_crypto = require("crypto");
764
- var import_api2 = require("@opentelemetry/api");
765
- var local = new import_node_async_hooks.AsyncLocalStorage();
766
- var config = null;
767
- var queue = [];
768
- var queueBytes = 0;
769
- var inFlightBytes = 0;
770
- var timer;
771
- var flushing = null;
772
- var dropped = 0;
773
- var inFlight = 0;
774
- var stopping = false;
775
- var failureStreak = 0;
776
- var severity = { debug: 5, info: 9, warning: 13, error: 17 };
777
- function safe(attributes = {}) {
778
- const redacted = config?.redact(attributes) ?? redactAttributes(attributes);
779
- let budget = 512;
780
- let characters = 16384;
781
- let truncated = false;
782
- const visit = (input, depth) => {
783
- if (--budget < 0 || depth > 6) {
784
- truncated = true;
785
- return "[truncated]";
786
- }
787
- if (typeof input === "string") {
788
- const text = input.replace(/(https?:\/\/[^\s?#]+)[?#][^\s]*/gi, "$1");
789
- const kept = text.slice(0, Math.max(0, characters));
790
- truncated ||= kept.length < text.length;
791
- characters -= kept.length;
792
- return kept;
638
+ // src/requests.ts
639
+ var _async_hooks = require('async_hooks');
640
+
641
+
642
+ var REQUEST_STATE = /* @__PURE__ */ Symbol.for("autter.runtime.request");
643
+ var BOUND = /* @__PURE__ */ Symbol.for("autter.runtime.bound");
644
+ var CAPTURED = /* @__PURE__ */ new WeakSet();
645
+ var capturer = () => {
646
+ };
647
+ function setRequestExceptionCapturer(fn) {
648
+ capturer = fn;
649
+ }
650
+ var annotator = () => {
651
+ };
652
+ function setRequestSpanAnnotator(fn) {
653
+ annotator = fn;
654
+ }
655
+ function markCaptured(error) {
656
+ if (error && typeof error === "object") CAPTURED.add(error);
657
+ }
658
+ function expressRouteOf(req) {
659
+ const props = req;
660
+ const path = _optionalChain([props, 'optionalAccess', _8 => _8.route, 'optionalAccess', _9 => _9.path]);
661
+ if (typeof path !== "string" || path === "") return null;
662
+ const base = typeof _optionalChain([props, 'optionalAccess', _10 => _10.baseUrl]) === "string" ? props.baseUrl : "";
663
+ const route = base + path;
664
+ return route.startsWith("/") ? route : null;
665
+ }
666
+ function defaultShouldCapture(error) {
667
+ return error instanceof _chunkUKYTXZOQcjs.RuntimeError || _chunkUKYTXZOQcjs.errorCodeOf.call(void 0, error) !== void 0 || _chunkUKYTXZOQcjs.responseStatusOf.call(void 0, error) >= 500;
668
+ }
669
+ function onRequestSpan(fn) {
670
+ const active2 = _api.context.active();
671
+ const metadata = _core.getRPCMetadata.call(void 0, active2);
672
+ const span = _optionalChain([metadata, 'optionalAccess', _11 => _11.type]) === _core.RPCType.HTTP ? metadata.span : void 0;
673
+ if (!span || !span.isRecording() || _api.trace.getSpan(active2) === span) {
674
+ fn();
675
+ return;
676
+ }
677
+ _api.context.with(_api.trace.setSpan(active2, span), fn);
678
+ }
679
+ function captureAtBoundary(error, state, rule = void 0, attributes) {
680
+ let wanted;
681
+ try {
682
+ wanted = typeof rule === "function" ? rule(error) : rule === void 0 ? defaultShouldCapture(error) : rule;
683
+ } catch (e13) {
684
+ wanted = false;
685
+ }
686
+ if (!wanted) return;
687
+ if (error && typeof error === "object" && CAPTURED.has(error)) return;
688
+ markCaptured(error);
689
+ try {
690
+ const run = () => onRequestSpan(() => capturer(error, attributes));
691
+ if (state && !state.sealed) _chunkUKYTXZOQcjs.local.run(state, run);
692
+ else run();
693
+ } catch (e14) {
694
+ }
695
+ }
696
+ function requestStateOf(req) {
697
+ if (!req || typeof req !== "object") return void 0;
698
+ return req[REQUEST_STATE];
699
+ }
700
+ function captureRequestError(error, attributes) {
701
+ if (error && typeof error === "object" && CAPTURED.has(error)) {
702
+ if (!attributes) return;
703
+ try {
704
+ onRequestSpan(() => annotator(attributes));
705
+ } catch (e15) {
793
706
  }
794
- if (typeof input === "number")
795
- return Number.isFinite(input) ? input : void 0;
796
- if (typeof input === "boolean" || input === null) return input;
797
- if (Array.isArray(input)) {
798
- truncated ||= input.length > 64;
799
- return input.slice(0, 64).map((item) => visit(item, depth + 1));
707
+ return;
708
+ }
709
+ captureAtBoundary(error, _chunkUKYTXZOQcjs.currentOperation.call(void 0, ), true, attributes);
710
+ }
711
+ function bindEmitter(emitter, state) {
712
+ const target = emitter;
713
+ if (!target || typeof target !== "object" || target[BOUND]) return;
714
+ target[BOUND] = true;
715
+ const wrappers = /* @__PURE__ */ new WeakMap();
716
+ const wrap = (listener) => {
717
+ if (typeof listener !== "function") return listener;
718
+ let wrapped = wrappers.get(listener);
719
+ if (!wrapped) {
720
+ wrapped = function(...args) {
721
+ return _chunkUKYTXZOQcjs.local.run(
722
+ state,
723
+ () => listener.apply(this, args)
724
+ );
725
+ };
726
+ wrappers.set(listener, wrapped);
800
727
  }
801
- if (input && typeof input === "object") {
802
- const entries = Object.entries(input);
803
- if (depth === 0) {
804
- const priority = (key) => /^autter\.(?:operation|event)\./.test(key) ? 2 : /^exception\./.test(key) ? 1 : 0;
805
- entries.sort(([a], [b]) => priority(b) - priority(a));
806
- }
807
- truncated ||= entries.length > 100;
808
- return Object.fromEntries(
809
- entries.slice(0, 100).filter(([key]) => !/^(?:__proto__|constructor|prototype)$/.test(key)).map(([key, item]) => [key.slice(0, 200), visit(item, depth + 1)])
728
+ return wrapped;
729
+ };
730
+ for (const method of [
731
+ "on",
732
+ "addListener",
733
+ "prependListener",
734
+ "once",
735
+ "prependOnceListener"
736
+ ]) {
737
+ const original = target[method];
738
+ if (typeof original !== "function") continue;
739
+ target[method] = function(event, listener) {
740
+ return original.call(this, event, wrap(listener));
741
+ };
742
+ }
743
+ for (const method of ["removeListener", "off"]) {
744
+ const original = target[method];
745
+ if (typeof original !== "function") continue;
746
+ target[method] = function(event, listener) {
747
+ const wrapped = typeof listener === "function" ? _nullishCoalesce(wrappers.get(listener), () => ( listener)) : listener;
748
+ return original.call(this, event, wrapped);
749
+ };
750
+ }
751
+ }
752
+ function exposeHeaderValue(current, header) {
753
+ const text = Array.isArray(current) ? current.join(", ") : String(_nullishCoalesce(current, () => ( "")));
754
+ const names = text.split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
755
+ if (names.includes("*") || names.includes(header)) return null;
756
+ return names.length ? `${text}, ${header}` : header;
757
+ }
758
+ function exposeOnCors(res, header) {
759
+ const original = res.writeHead;
760
+ res.writeHead = function(...args) {
761
+ try {
762
+ const inline = args.slice(1).find(
763
+ (arg) => !!arg && typeof arg === "object" && !Array.isArray(arg)
810
764
  );
765
+ const inlineKey = (name) => inline ? Object.keys(inline).find((key) => key.toLowerCase() === name) : void 0;
766
+ const cors = res.getHeader("access-control-allow-origin") !== void 0 || inlineKey("access-control-allow-origin") !== void 0;
767
+ if (cors) {
768
+ const key = inlineKey("access-control-expose-headers");
769
+ const value = exposeHeaderValue(
770
+ key && inline ? inline[key] : res.getHeader("access-control-expose-headers"),
771
+ header
772
+ );
773
+ if (value && key && inline) inline[key] = value;
774
+ else if (value) res.setHeader("access-control-expose-headers", value);
775
+ }
776
+ } catch (e16) {
811
777
  }
812
- return void 0;
778
+ return original.apply(this, args);
813
779
  };
814
- const result = visit(redacted, 0);
815
- if (truncated) result["autter.context.truncated"] = true;
816
- return result;
817
- }
818
- function operationAttributes(state) {
819
- return state ? {
820
- "autter.operation.id": state.id,
821
- "autter.operation.name": state.name,
822
- ...state.parentId ? { "autter.operation.parent_id": state.parentId } : {},
823
- ...state.attributes
824
- } : {};
825
- }
826
- function userAttributes(attributes = {}) {
827
- return Object.fromEntries(
828
- Object.entries(safe(attributes)).filter(
829
- ([key]) => !/^autter\.(?:operation|event)\./.test(key)
830
- )
780
+ }
781
+ function pathOf(req) {
782
+ const raw = _nullishCoalesce(_nullishCoalesce(req.originalUrl, () => ( req.url)), () => ( "/"));
783
+ return raw.split(/[?#]/)[0] || "/";
784
+ }
785
+ function finishRequest(state, input) {
786
+ if (state.sealed) return;
787
+ state.name = (_nullishCoalesce(input.name, () => ( `${input.method} ${input.route}`))).slice(0, 200);
788
+ state.outcome = _chunkUKYTXZOQcjs.requestOutcome.call(void 0, {
789
+ ...state.explicitOutcome ? { explicit: state.outcome } : {},
790
+ ...state.error !== void 0 ? { error: state.error } : {},
791
+ ...state.errorThrown ? { thrown: true } : {},
792
+ status: input.status,
793
+ aborted: input.aborted
794
+ });
795
+ const span = _api.trace.getActiveSpan();
796
+ if (_optionalChain([span, 'optionalAccess', _12 => _12.isRecording, 'call', _13 => _13()])) span.setAttribute("autter.operation.outcome", state.outcome);
797
+ if (input.span) {
798
+ const remote = _api.trace.wrapSpanContext(input.span);
799
+ _api.context.with(
800
+ _api.trace.setSpan(_api.context.active(), remote),
801
+ () => _chunkUKYTXZOQcjs.reportExplicitFailure.call(void 0, state)
802
+ );
803
+ } else _chunkUKYTXZOQcjs.reportExplicitFailure.call(void 0, state);
804
+ _chunkUKYTXZOQcjs.emitSummary.call(void 0, state, {
805
+ http: {
806
+ "http.request.method": input.method,
807
+ "http.route": input.route,
808
+ "http.response.status_code": input.status,
809
+ "autter.request.aborted": input.aborted
810
+ },
811
+ ...input.span ? { span: input.span } : {}
812
+ });
813
+ }
814
+ function beginNodeRequest(req, res, options, route) {
815
+ const header = (_nullishCoalesce(options.requestIdHeader, () => ( _chunkUKYTXZOQcjs.DEFAULT_REQUEST_ID_HEADER))).toLowerCase();
816
+ const requestId = _chunkUKYTXZOQcjs.resolveRequestId.call(void 0,
817
+ options.trustRequestId === false ? void 0 : req.headers[header]
831
818
  );
819
+ const method = (_nullishCoalesce(req.method, () => ( "GET"))).toUpperCase();
820
+ const path = pathOf(req);
821
+ const state = _chunkUKYTXZOQcjs.createRequestState.call(void 0, {
822
+ name: `${method} ${_chunkUKYTXZOQcjs.normalizeRoutePath.call(void 0, path)}`,
823
+ requestId,
824
+ req,
825
+ res
826
+ });
827
+ req[REQUEST_STATE] = state;
828
+ try {
829
+ if (!res.headersSent) res.setHeader(header, requestId);
830
+ exposeOnCors(res, header);
831
+ } catch (e17) {
832
+ }
833
+ const span = _api.trace.getActiveSpan();
834
+ if (_optionalChain([span, 'optionalAccess', _14 => _14.isRecording, 'call', _15 => _15()]))
835
+ span.setAttributes({
836
+ "autter.request.id": requestId,
837
+ "autter.operation.kind": "request"
838
+ });
839
+ const spanContext = _optionalChain([span, 'optionalAccess', _16 => _16.spanContext, 'call', _17 => _17()]);
840
+ bindEmitter(req, state);
841
+ bindEmitter(res, state);
842
+ let finished = false;
843
+ const done = () => {
844
+ finishRequest(state, {
845
+ method,
846
+ route: _nullishCoalesce(_nullishCoalesce(_optionalChain([route, 'optionalCall', _18 => _18()]), () => ( expressRouteOf(req))), () => ( _chunkUKYTXZOQcjs.normalizeRoutePath.call(void 0, path))),
847
+ status: res.statusCode,
848
+ aborted: !finished,
849
+ ...spanContext ? { span: spanContext } : {}
850
+ });
851
+ };
852
+ res.once("finish", () => {
853
+ finished = true;
854
+ done();
855
+ });
856
+ res.once("close", done);
857
+ return state;
858
+ }
859
+ function autterRequests(options = {}) {
860
+ const ignored = _chunkUKYTXZOQcjs.compileIgnore.call(void 0, options.ignore);
861
+ return function autterRequestsMiddleware(req, res, next) {
862
+ if (req[REQUEST_STATE] || ignored(pathOf(req))) {
863
+ next();
864
+ return;
865
+ }
866
+ const state = beginNodeRequest(req, res, options);
867
+ _chunkUKYTXZOQcjs.local.run(state, () => next());
868
+ };
832
869
  }
833
- function mergeContext(current, next = {}) {
834
- const merge = (left, right, depth) => {
835
- const result = { ...left };
836
- for (const [key, value2] of Object.entries(right)) {
837
- const prior = result[key];
838
- result[key] = depth < 6 && value2 && typeof value2 === "object" && !Array.isArray(value2) && prior && typeof prior === "object" && !Array.isArray(prior) ? merge(prior, value2, depth + 1) : value2;
870
+ function autterErrorResponse(options = {}) {
871
+ return function autterErrorResponseMiddleware(error, req, res, next) {
872
+ const state = req[REQUEST_STATE];
873
+ if (state) _chunkUKYTXZOQcjs.noteOperationError.call(void 0, error, true, state);
874
+ captureAtBoundary(error, state, options.capture);
875
+ if (res.headersSent) {
876
+ next(error);
877
+ return;
839
878
  }
840
- return result;
879
+ const header = (_nullishCoalesce(options.requestIdHeader, () => ( _chunkUKYTXZOQcjs.DEFAULT_REQUEST_ID_HEADER))).toLowerCase();
880
+ const inbound = _optionalChain([req, 'access', _19 => _19.headers, 'optionalAccess', _20 => _20[header]]);
881
+ const requestId = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _21 => _21.requestId]), () => ( (typeof inbound === "string" ? inbound.slice(0, 128) : void 0)));
882
+ res.statusCode = _chunkUKYTXZOQcjs.responseStatusOf.call(void 0, error);
883
+ res.setHeader("content-type", "application/json; charset=utf-8");
884
+ res.end(JSON.stringify(_chunkUKYTXZOQcjs.toClientError.call(void 0, error, requestId)));
841
885
  };
842
- return userAttributes(merge(current, userAttributes(next), 0));
843
- }
844
- function traceAttributes(state) {
845
- return Object.fromEntries(
846
- Object.entries(operationAttributes(state)).filter(([, item]) => item !== null && item !== void 0).map(([key, item]) => [
847
- key,
848
- typeof item === "object" ? JSON.stringify(item) : item
849
- ])
850
- );
851
886
  }
852
- function scheduleFlush() {
853
- if (!timer && config && !stopping && queue.length) {
854
- timer = setTimeout(
855
- () => {
856
- timer = void 0;
857
- void flushRuntimeLogs().catch(() => {
858
- });
859
- },
860
- Math.min(3e4, 2e3 * 2 ** Math.min(failureStreak, 4))
887
+ var RESOURCE = /* @__PURE__ */ Symbol.for("autter.runtime.resource");
888
+ function autterFastify(fastify, options, done) {
889
+ const opts = _nullishCoalesce(options, () => ( {}));
890
+ const header = (_nullishCoalesce(opts.requestIdHeader, () => ( _chunkUKYTXZOQcjs.DEFAULT_REQUEST_ID_HEADER))).toLowerCase();
891
+ const ignored = _chunkUKYTXZOQcjs.compileIgnore.call(void 0, opts.ignore);
892
+ const stateOf = (request) => request[REQUEST_STATE];
893
+ fastify.addHook("onRequest", ((request, reply, next) => {
894
+ if (ignored(request.url) || request.raw[REQUEST_STATE]) {
895
+ next();
896
+ return;
897
+ }
898
+ const requestId = _chunkUKYTXZOQcjs.resolveRequestId.call(void 0,
899
+ opts.trustRequestId === false ? void 0 : request.headers[header]
861
900
  );
862
- timer.unref();
863
- }
864
- }
865
- function value(input) {
866
- if (typeof input === "number") return { doubleValue: input };
867
- if (typeof input === "boolean") return { boolValue: input };
868
- if (Array.isArray(input))
869
- return { arrayValue: { values: input.slice(0, 64).map(value) } };
870
- if (input && typeof input === "object")
871
- return {
872
- kvlistValue: {
873
- values: Object.entries(input).slice(0, 128).map(([key, item]) => ({ key, value: value(item) }))
901
+ const method = String(_nullishCoalesce(request.method, () => ( "GET"))).toUpperCase();
902
+ const state = _chunkUKYTXZOQcjs.createRequestState.call(void 0, {
903
+ name: `${method} ${_chunkUKYTXZOQcjs.normalizeRoutePath.call(void 0, request.url)}`,
904
+ requestId,
905
+ req: request.raw,
906
+ res: reply.raw
907
+ });
908
+ request[REQUEST_STATE] = state;
909
+ request.raw[REQUEST_STATE] = state;
910
+ reply.header(header, requestId);
911
+ const span = _api.trace.getActiveSpan();
912
+ if (_optionalChain([span, 'optionalAccess', _22 => _22.isRecording, 'call', _23 => _23()]))
913
+ span.setAttributes({
914
+ "autter.request.id": requestId,
915
+ "autter.operation.kind": "request"
916
+ });
917
+ const spanContext = _optionalChain([span, 'optionalAccess', _24 => _24.spanContext, 'call', _25 => _25()]);
918
+ bindEmitter(request.raw, state);
919
+ bindEmitter(reply.raw, state);
920
+ let finished = false;
921
+ const finish = (aborted) => finishRequest(state, {
922
+ method,
923
+ route: _nullishCoalesce(_nullishCoalesce(_optionalChain([request, 'access', _26 => _26.routeOptions, 'optionalAccess', _27 => _27.url]), () => ( request.routerPath)), () => ( _chunkUKYTXZOQcjs.normalizeRoutePath.call(void 0, request.url))),
924
+ status: reply.raw.statusCode || reply.statusCode,
925
+ aborted,
926
+ ...spanContext ? { span: spanContext } : {}
927
+ });
928
+ reply.raw.once("finish", () => {
929
+ finished = true;
930
+ finish(false);
931
+ });
932
+ reply.raw.once("close", () => finish(!finished));
933
+ _chunkUKYTXZOQcjs.local.run(state, () => {
934
+ request[RESOURCE] = new (0, _async_hooks.AsyncResource)("autter-request");
935
+ next();
936
+ });
937
+ }));
938
+ fastify.addHook("preHandler", ((request, _reply, next) => {
939
+ const resource = request[RESOURCE];
940
+ if (resource) resource.runInAsyncScope(() => next());
941
+ else next();
942
+ }));
943
+ fastify.addHook("onSend", ((request, reply, payload, next) => {
944
+ try {
945
+ if (stateOf(request) && reply.getHeader("access-control-allow-origin") !== void 0) {
946
+ const value = exposeHeaderValue(reply.getHeader("access-control-expose-headers"), header);
947
+ if (value) reply.header("access-control-expose-headers", value);
874
948
  }
875
- };
876
- return { stringValue: String(input ?? "").slice(0, 32e3) };
877
- }
878
- function emit(level, message, attributes, extra = {}) {
879
- const state = local.getStore();
880
- if (state?.sealed) return;
881
- if (extra["autter.event.type"] !== "operation" && severity[level] < severity[config?.options?.minLevel ?? "debug"])
882
- return;
883
- const span = import_api2.trace.getActiveSpan()?.spanContext();
884
- const user = mergeContext(state?.attributes ?? {}, attributes);
885
- const exceptions = Object.fromEntries(
886
- Object.entries(user).filter(([key]) => key.startsWith("exception."))
887
- );
888
- const attrs = safe({
889
- "autter.event.id": (0, import_node_crypto.randomUUID)(),
890
- ...extra,
891
- ...exceptions,
892
- ...operationAttributes(state),
893
- ...user
894
- });
895
- const record = {
896
- timeUnixNano: String(BigInt(Date.now()) * 1000000n),
897
- severityNumber: severity[level],
898
- severityText: level.toUpperCase(),
899
- body: value(String(safe({ message }).message ?? "").slice(0, 4e3)),
900
- attributes: Object.entries(attrs).map(([key, item]) => ({
901
- key,
902
- value: value(item)
903
- })),
904
- ...span && /^[a-f0-9]{32}$/.test(span.traceId) && !/^0+$/.test(span.traceId) ? { traceId: span.traceId, spanId: span.spanId } : {}
949
+ } catch (e18) {
950
+ }
951
+ next(null, payload);
952
+ }));
953
+ fastify.addHook("onError", ((request, _reply, error, next) => {
954
+ const state = stateOf(request);
955
+ if (state) _chunkUKYTXZOQcjs.noteOperationError.call(void 0, error, true, state);
956
+ captureAtBoundary(error, state);
957
+ next();
958
+ }));
959
+ done();
960
+ }
961
+ autterFastify[/* @__PURE__ */ Symbol.for("skip-override")] = true;
962
+ autterFastify[/* @__PURE__ */ Symbol.for("fastify.display-name")] = "autter-runtime";
963
+ function withHeaders(response, header, requestId) {
964
+ const apply = (target) => {
965
+ target.headers.set(header, requestId);
966
+ if (target.headers.get("access-control-allow-origin") !== null) {
967
+ const value = exposeHeaderValue(
968
+ _nullishCoalesce(target.headers.get("access-control-expose-headers"), () => ( "")),
969
+ header
970
+ );
971
+ if (value) target.headers.set("access-control-expose-headers", value);
972
+ }
973
+ return target;
905
974
  };
906
- if (config?.options?.console !== false)
907
- console.log(
908
- JSON.stringify({ ...attrs, level, message: record.body.stringValue })
909
- );
910
- if (!config) return;
911
- if (stopping) {
912
- dropped++;
913
- return;
975
+ try {
976
+ return apply(response);
977
+ } catch (e19) {
978
+ try {
979
+ return apply(new Response(response.body, response));
980
+ } catch (e20) {
981
+ return response;
982
+ }
914
983
  }
915
- const bytes = Buffer.byteLength(JSON.stringify(record));
916
- if (bytes > 256 * 1024 || queue.length + inFlight >= 1e3 || queueBytes + inFlightBytes + bytes > 4 * 1024 * 1024) {
917
- dropped++;
918
- console.warn(
919
- "[autter-runtime] log buffer or record limit reached; record dropped"
984
+ }
985
+ function withRuntimeRequest(handler, options = {}) {
986
+ const header = (_nullishCoalesce(options.requestIdHeader, () => ( _chunkUKYTXZOQcjs.DEFAULT_REQUEST_ID_HEADER))).toLowerCase();
987
+ const ignored = _chunkUKYTXZOQcjs.compileIgnore.call(void 0, options.ignore);
988
+ return async (request, ...rest) => {
989
+ let pathname = "/";
990
+ try {
991
+ pathname = new URL(request.url, "http://localhost").pathname;
992
+ } catch (e21) {
993
+ }
994
+ if (ignored(pathname)) return handler(request, ...rest);
995
+ const requestId = _chunkUKYTXZOQcjs.resolveRequestId.call(void 0,
996
+ options.trustRequestId === false ? void 0 : request.headers.get(header)
920
997
  );
921
- return;
922
- }
923
- queue.push({ record, bytes });
924
- queueBytes += bytes;
925
- scheduleFlush();
926
- }
927
- function configureRuntimeLogger(next) {
928
- config = next;
929
- stopping = false;
930
- failureStreak = 0;
931
- }
932
- function runtimeLogStats() {
933
- return { buffered: queue.length + inFlight, dropped };
934
- }
935
- async function flushRuntimeLogs() {
936
- if (flushing) return flushing;
937
- if (!config || !queue.length) return;
938
- if (timer) {
939
- clearTimeout(timer);
940
- timer = void 0;
941
- }
942
- const activeConfig = config;
943
- const deadline = Date.now() + 1e4;
944
- flushing = (async () => {
945
- const count = queue.length;
946
- for (let remaining = count; remaining > 0; ) {
947
- const batch = [];
948
- inFlightBytes = 0;
949
- while (batch.length < Math.min(50, remaining) && queue.length) {
950
- const next = queue[0];
951
- if (batch.length && inFlightBytes + next.bytes > 512 * 1024) break;
952
- batch.push(queue.shift());
953
- inFlightBytes += next.bytes;
954
- queueBytes -= next.bytes;
955
- }
956
- remaining -= batch.length;
957
- inFlight = batch.length;
958
- const body = JSON.stringify({
959
- resourceLogs: [
960
- {
961
- resource: {
962
- attributes: Object.entries({
963
- "service.name": activeConfig.service,
964
- "deployment.environment.name": activeConfig.environment,
965
- ...activeConfig.release ? { "service.version": activeConfig.release } : {}
966
- }).map(([key, item]) => ({ key, value: value(item) }))
967
- },
968
- scopeLogs: [
969
- {
970
- scope: { name: "autter-runtime" },
971
- logRecords: batch.map((entry) => entry.record)
972
- }
973
- ]
974
- }
975
- ]
998
+ const method = String(_nullishCoalesce(request.method, () => ( "GET"))).toUpperCase();
999
+ const route = _nullishCoalesce(options.route, () => ( _chunkUKYTXZOQcjs.normalizeRoutePath.call(void 0, pathname)));
1000
+ const state = _chunkUKYTXZOQcjs.createRequestState.call(void 0, {
1001
+ name: `${method} ${_nullishCoalesce(options.name, () => ( route))}`,
1002
+ requestId,
1003
+ req: request
1004
+ });
1005
+ const span = _api.trace.getActiveSpan();
1006
+ if (_optionalChain([span, 'optionalAccess', _28 => _28.isRecording, 'call', _29 => _29()]))
1007
+ span.setAttributes({
1008
+ "autter.request.id": requestId,
1009
+ "autter.operation.kind": "request"
976
1010
  });
977
- let failure;
978
- for (let attempt = 0; attempt < 3; attempt++) {
1011
+ const spanContext = _optionalChain([span, 'optionalAccess', _30 => _30.spanContext, 'call', _31 => _31()]);
1012
+ let status = 500;
1013
+ try {
1014
+ const response = await _chunkUKYTXZOQcjs.local.run(state, async () => {
979
1015
  try {
980
- if (Date.now() >= deadline)
981
- throw new Error("Runtime log flush exceeded 10 seconds");
982
- const response = await fetch(`${activeConfig.endpoint}/v1/logs`, {
983
- method: "POST",
984
- headers: {
985
- "content-type": "application/json",
986
- authorization: `Bearer ${activeConfig.apiKey}`
987
- },
988
- body,
989
- signal: AbortSignal.timeout(
990
- Math.max(1, Math.min(3e3, deadline - Date.now()))
991
- )
992
- });
993
- if (!response.ok)
994
- throw new Error(`Runtime log export failed (${response.status})`);
995
- failure = void 0;
996
- break;
1016
+ return await handler(request, ...rest);
997
1017
  } catch (error) {
998
- failure = error;
1018
+ _chunkUKYTXZOQcjs.noteOperationError.call(void 0, error, true, state);
1019
+ captureAtBoundary(error, state, true);
1020
+ throw error;
1021
+ }
1022
+ });
1023
+ status = response.status;
1024
+ return withHeaders(response, header, requestId);
1025
+ } finally {
1026
+ const aborted = _optionalChain([request, 'access', _32 => _32.signal, 'optionalAccess', _33 => _33.aborted]) === true;
1027
+ finishRequest(state, {
1028
+ method,
1029
+ route,
1030
+ name: `${method} ${_nullishCoalesce(options.name, () => ( route))}`,
1031
+ status,
1032
+ aborted,
1033
+ ...spanContext ? { span: spanContext } : {}
1034
+ });
1035
+ if (options.waitUntil) {
1036
+ try {
1037
+ options.waitUntil(_chunkUKYTXZOQcjs.flushRuntimeLogs.call(void 0, ).catch(() => {
1038
+ }));
1039
+ } catch (e22) {
999
1040
  }
1000
1041
  }
1001
- inFlight = 0;
1002
- if (failure) {
1003
- failureStreak++;
1004
- queue = [...batch, ...queue];
1005
- queueBytes += inFlightBytes;
1006
- inFlightBytes = 0;
1007
- throw failure;
1008
- }
1009
- inFlightBytes = 0;
1010
- failureStreak = 0;
1011
1042
  }
1012
- })().finally(() => {
1013
- flushing = null;
1014
- scheduleFlush();
1015
- });
1016
- return flushing;
1043
+ };
1044
+ }
1045
+ function startHookRequest(res) {
1046
+ const req = res.req;
1047
+ if (!req || req[REQUEST_STATE]) return;
1048
+ const state = beginNodeRequest(req, res, {});
1049
+ _chunkUKYTXZOQcjs.local.enterWith(state);
1017
1050
  }
1018
- async function shutdownRuntimeLogger() {
1019
- stopping = true;
1051
+
1052
+ // src/unhandled-rejections.ts
1053
+ var MODES = /* @__PURE__ */ new Set([
1054
+ "throw",
1055
+ "strict",
1056
+ "warn",
1057
+ "warn-with-error-code",
1058
+ "none"
1059
+ ]);
1060
+ var LISTENER_MARK = /* @__PURE__ */ Symbol.for("autter.runtime.unhandledRejection.listener");
1061
+ var HANDLED_KEY = /* @__PURE__ */ Symbol.for("autter.runtime.unhandledRejection.handled");
1062
+ function handledPromises() {
1063
+ const registry = globalThis;
1064
+ let set = registry[HANDLED_KEY];
1065
+ if (!set) {
1066
+ set = /* @__PURE__ */ new WeakSet();
1067
+ registry[HANDLED_KEY] = set;
1068
+ }
1069
+ return set;
1070
+ }
1071
+ var recorded = /* @__PURE__ */ new WeakSet();
1072
+ function markRecorded(reason) {
1073
+ if (!reason || typeof reason !== "object") return;
1074
+ recorded.add(reason);
1075
+ _optionalChain([setImmediate, 'call', _34 => _34(() => recorded.delete(reason)), 'access', _35 => _35.unref, 'optionalCall', _36 => _36()]);
1076
+ }
1077
+ function recordedAsRejection(error) {
1078
+ return !!error && typeof error === "object" && recorded.has(error);
1079
+ }
1080
+ function splitOptions(value) {
1081
+ return value ? value.split(/\s+/).filter(Boolean) : [];
1082
+ }
1083
+ function unhandledRejectionsMode(execArgv = process.execArgv, nodeOptions = process.env.NODE_OPTIONS) {
1084
+ const args = [...splitOptions(nodeOptions), ...execArgv];
1085
+ let mode = "throw";
1086
+ for (let i = 0; i < args.length; i++) {
1087
+ const arg = _nullishCoalesce(args[i], () => ( ""));
1088
+ if (!arg.startsWith("--")) continue;
1089
+ const eq = arg.indexOf("=");
1090
+ const name = (eq < 0 ? arg : arg.slice(0, eq)).replace(/_/g, "-");
1091
+ if (name !== "--unhandled-rejections") continue;
1092
+ const value = eq < 0 ? args[++i] : arg.slice(eq + 1);
1093
+ if (value && MODES.has(value))
1094
+ mode = value;
1095
+ }
1096
+ return mode;
1097
+ }
1098
+ function isErrorLike(value) {
1020
1099
  try {
1021
- await flushRuntimeLogs();
1022
- } finally {
1023
- if (queue.length) {
1024
- dropped += queue.length;
1025
- console.warn(
1026
- `[autter-runtime] ${queue.length} log records could not be delivered before shutdown`
1027
- );
1100
+ return typeof value === "object" && value !== null && Object.prototype.hasOwnProperty.call(value, "stack");
1101
+ } catch (e23) {
1102
+ return false;
1103
+ }
1104
+ }
1105
+ function describeReason(reason) {
1106
+ if (typeof reason !== "object" && typeof reason !== "function" || reason === null) {
1107
+ try {
1108
+ return String(reason);
1109
+ } catch (e24) {
1110
+ return typeof reason;
1028
1111
  }
1029
- queue = [];
1030
- queueBytes = 0;
1031
- config = null;
1032
- if (timer) clearTimeout(timer);
1033
- timer = void 0;
1034
1112
  }
1113
+ try {
1114
+ const proto = Object.getPrototypeOf(reason);
1115
+ const ctor = _optionalChain([proto, 'optionalAccess', _37 => _37.constructor]);
1116
+ const name = typeof ctor === "function" ? ctor.name : "";
1117
+ return name ? `#<${name}>` : "[object Object]";
1118
+ } catch (e25) {
1119
+ return "[object Object]";
1120
+ }
1121
+ }
1122
+ function toUncaught(reason, from) {
1123
+ if (isErrorLike(reason)) return reason;
1124
+ const error = new Error(
1125
+ `This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). The promise rejected with the reason "${describeReason(reason)}".`
1126
+ );
1127
+ error.name = "UnhandledPromiseRejection";
1128
+ error.code = "ERR_UNHANDLED_REJECTION";
1129
+ _optionalChain([Error, 'access', _38 => _38.captureStackTrace, 'optionalCall', _39 => _39(error, from)]);
1130
+ return error;
1035
1131
  }
1036
- function createRuntimeLogger(attributes = {}) {
1037
- const attrs = userAttributes(attributes);
1038
- return {
1039
- debug: (message, extra) => emit("debug", message, mergeContext(attrs, extra)),
1040
- info: (message, extra) => emit("info", message, mergeContext(attrs, extra)),
1041
- warn: (message, extra) => emit("warning", message, mergeContext(attrs, extra)),
1042
- error: (error, extra) => emit("error", error instanceof Error ? error.message : String(error), {
1043
- ...attrs,
1044
- ...extra,
1045
- ...error instanceof Error ? {
1046
- "exception.type": error.name,
1047
- "exception.stacktrace": error.stack ?? ""
1048
- } : {}
1049
- })
1050
- };
1132
+ var warningId = 0;
1133
+ function emitNodeWarning(reason) {
1134
+ try {
1135
+ const text = isErrorLike(reason) ? String(reason.stack) : describeReason(reason);
1136
+ process.emitWarning(text, "UnhandledPromiseRejectionWarning");
1137
+ process.emitWarning(
1138
+ `Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag \`--unhandled-rejections=strict\` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: ${++warningId})`,
1139
+ "UnhandledPromiseRejectionWarning"
1140
+ );
1141
+ } catch (e26) {
1142
+ }
1051
1143
  }
1052
- var runtimeLogger = createRuntimeLogger();
1053
- function withRuntimeOperation(name, fn, attributes = {}) {
1054
- const parent = local.getStore();
1055
- const state = {
1056
- id: (0, import_node_crypto.randomUUID)(),
1057
- name: String(safe({ name }).name).slice(0, 200),
1058
- parentId: parent?.sealed ? void 0 : parent?.id,
1059
- attributes: mergeContext(
1060
- parent?.sealed ? {} : parent?.attributes ?? {},
1061
- attributes
1062
- ),
1063
- startedAt: Date.now(),
1064
- outcome: "succeeded",
1065
- steps: []
1144
+ function installUnhandledRejectionCapture(capture, mode = unhandledRejectionsMode()) {
1145
+ if (mode === "strict") return () => {
1066
1146
  };
1067
- const operation = {
1068
- id: state.id,
1069
- setContext: (attrs) => {
1070
- if (!state.sealed) {
1071
- state.attributes = mergeContext(state.attributes, attrs);
1072
- import_api2.trace.getActiveSpan()?.setAttributes(traceAttributes(state));
1147
+ const listener = (reason, promise) => {
1148
+ try {
1149
+ if (promise && typeof promise === "object") {
1150
+ const handled = handledPromises();
1151
+ if (handled.has(promise)) return;
1152
+ handled.add(promise);
1073
1153
  }
1074
- },
1075
- outcome: (status, message) => {
1076
- if (state.sealed) return;
1077
- state.outcome = status;
1078
- state.message = message;
1079
- if (status === "failed")
1080
- state.reportingStack = new Error("Operation outcome reported here").stack ?? "";
1081
- },
1082
- step: async (stepName, stepFn) => {
1083
- const started = Date.now();
1084
- let status = "succeeded";
1085
- try {
1086
- return await stepFn();
1087
- } catch (error) {
1088
- status = "failed";
1089
- throw error;
1090
- } finally {
1091
- if (!state.sealed && state.steps.length < 64)
1092
- state.steps.push({
1093
- name: String(safe({ name: stepName }).name).slice(0, 200),
1094
- status,
1095
- durationMs: Date.now() - started
1096
- });
1154
+ const alone = process.listeners("unhandledRejection").every((fn) => fn[LISTENER_MARK] === true);
1155
+ if (alone && mode === "throw") {
1156
+ const error = toUncaught(reason, listener);
1157
+ process.nextTick(() => {
1158
+ throw error;
1159
+ });
1160
+ return;
1097
1161
  }
1162
+ if (alone && mode === "warn-with-error-code") {
1163
+ emitNodeWarning(reason);
1164
+ process.exitCode = 1;
1165
+ }
1166
+ markRecorded(reason);
1167
+ capture(reason);
1168
+ } catch (e27) {
1098
1169
  }
1099
1170
  };
1100
- const run = () => local.run(state, async () => {
1101
- let thrown;
1102
- try {
1103
- return await fn(operation);
1104
- } catch (error) {
1105
- state.outcome = "failed";
1106
- thrown = error;
1107
- throw error;
1108
- } finally {
1109
- import_api2.trace.getActiveSpan()?.setAttributes({
1110
- ...traceAttributes(state),
1111
- "autter.operation.outcome": state.outcome
1112
- });
1113
- if (state.outcome === "failed" && !thrown)
1114
- config?.reportOutcome(
1115
- state.name,
1116
- state.message ?? "Operation failed",
1117
- {
1118
- ...traceAttributes(state),
1119
- "autter.outcome.stack": state.reportingStack ?? ""
1120
- }
1121
- );
1122
- emit(
1123
- state.outcome === "failed" ? "error" : "info",
1124
- state.message ?? `${state.name}: ${state.outcome}`,
1125
- {
1126
- ...operationAttributes(state),
1127
- ...thrown instanceof Error ? {
1128
- "exception.type": thrown.name,
1129
- "exception.stacktrace": thrown.stack ?? ""
1130
- } : {}
1131
- },
1132
- {
1133
- "autter.event.type": "operation",
1134
- "autter.operation.outcome": state.outcome,
1135
- "autter.operation.duration_ms": Date.now() - state.startedAt,
1136
- "autter.operation.steps": state.steps
1137
- }
1138
- );
1139
- state.sealed = true;
1140
- }
1141
- });
1142
- return config ? config.run(state.name, run, traceAttributes(state)) : run();
1171
+ listener[LISTENER_MARK] = true;
1172
+ process.on("unhandledRejection", listener);
1173
+ return () => {
1174
+ process.off("unhandledRejection", listener);
1175
+ };
1143
1176
  }
1144
1177
 
1145
1178
  // src/server.ts
@@ -1158,10 +1191,10 @@ var LlmAwareSampler = class {
1158
1191
  constructor(delegate) {
1159
1192
  this.delegate = delegate;
1160
1193
  }
1161
- delegate;
1194
+
1162
1195
  shouldSample(ctx, traceId, spanName, spanKind, attributes, links) {
1163
1196
  if (isLlmSpan(spanName, attributes)) {
1164
- return { decision: import_sdk_trace_base.SamplingDecision.RECORD_AND_SAMPLED };
1197
+ return { decision: _sdktracebase.SamplingDecision.RECORD_AND_SAMPLED };
1165
1198
  }
1166
1199
  return this.delegate.shouldSample(
1167
1200
  ctx,
@@ -1180,7 +1213,7 @@ var RecordUnsampledSampler = class {
1180
1213
  constructor(delegate) {
1181
1214
  this.delegate = delegate;
1182
1215
  }
1183
- delegate;
1216
+
1184
1217
  shouldSample(ctx, traceId, spanName, spanKind, attributes, links) {
1185
1218
  const result = this.delegate.shouldSample(
1186
1219
  ctx,
@@ -1190,8 +1223,8 @@ var RecordUnsampledSampler = class {
1190
1223
  attributes,
1191
1224
  links
1192
1225
  );
1193
- if (result.decision === import_sdk_trace_base.SamplingDecision.NOT_RECORD) {
1194
- return { ...result, decision: import_sdk_trace_base.SamplingDecision.RECORD };
1226
+ if (result.decision === _sdktracebase.SamplingDecision.NOT_RECORD) {
1227
+ return { ...result, decision: _sdktracebase.SamplingDecision.RECORD };
1195
1228
  }
1196
1229
  return result;
1197
1230
  }
@@ -1204,14 +1237,14 @@ var RETENTION_MAX_BUFFERED_SPANS = 5e3;
1204
1237
  var RETENTION_SWEEP_INTERVAL_MS = 1e4;
1205
1238
  var RETENTION_TRACE_TTL_MS = 3e4;
1206
1239
  function spanIndicatesError(span) {
1207
- if (span.status.code === import_api3.SpanStatusCode.ERROR) return true;
1240
+ if (span.status.code === _api.SpanStatusCode.ERROR) return true;
1208
1241
  return span.events.some((event) => event.name === "exception");
1209
1242
  }
1210
1243
  var TAIL_RETAINED_ATTR = "autter.tail_retained";
1211
1244
  function withSampledFlag(span) {
1212
1245
  const spanContext = {
1213
1246
  ...span.spanContext(),
1214
- traceFlags: span.spanContext().traceFlags | import_api3.TraceFlags.SAMPLED
1247
+ traceFlags: span.spanContext().traceFlags | _api.TraceFlags.SAMPLED
1215
1248
  };
1216
1249
  return {
1217
1250
  name: span.name,
@@ -1233,29 +1266,29 @@ function withSampledFlag(span) {
1233
1266
  droppedLinksCount: span.droppedLinksCount
1234
1267
  };
1235
1268
  }
1236
- var ErrorTraceRetentionProcessor = class {
1237
- constructor(inner, retainErrors = true, slowThresholdMs = 0) {
1269
+ var ErrorTraceRetentionProcessor = (_class2 = class {
1270
+ constructor(inner, retainErrors = true, slowThresholdMs = 0) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);
1238
1271
  this.inner = inner;
1239
1272
  this.retainErrors = retainErrors;
1240
1273
  this.slowThresholdMs = slowThresholdMs;
1241
1274
  this.sweeper = setInterval(() => this.sweep(), RETENTION_SWEEP_INTERVAL_MS);
1242
- this.sweeper.unref?.();
1243
- }
1244
- inner;
1245
- retainErrors;
1246
- slowThresholdMs;
1247
- traces = /* @__PURE__ */ new Map();
1248
- bufferedSpans = 0;
1249
- sweeper;
1275
+ _optionalChain([this, 'access', _40 => _40.sweeper, 'access', _41 => _41.unref, 'optionalCall', _42 => _42()]);
1276
+ }
1277
+
1278
+
1279
+
1280
+ __init2() {this.traces = /* @__PURE__ */ new Map()}
1281
+ __init3() {this.bufferedSpans = 0}
1282
+
1250
1283
  onStart(_span, _parentContext) {
1251
1284
  }
1252
1285
  onEnd(span) {
1253
1286
  const ctx = span.spanContext();
1254
- if ((ctx.traceFlags & import_api3.TraceFlags.SAMPLED) !== 0) return;
1287
+ if ((ctx.traceFlags & _api.TraceFlags.SAMPLED) !== 0) return;
1255
1288
  const entry = this.entryFor(ctx.traceId);
1256
1289
  if (entry.retained) {
1257
1290
  this.forward(span);
1258
- } else if (this.retainErrors && spanIndicatesError(span) || this.slowThresholdMs > 0 && span.kind === import_api3.SpanKind.SERVER && span.duration[0] * 1e3 + span.duration[1] / 1e6 >= this.slowThresholdMs) {
1291
+ } else if (this.retainErrors && spanIndicatesError(span) || this.slowThresholdMs > 0 && span.kind === _api.SpanKind.SERVER && span.duration[0] * 1e3 + span.duration[1] / 1e6 >= this.slowThresholdMs) {
1259
1292
  entry.retained = true;
1260
1293
  this.flush(entry);
1261
1294
  this.forward(span);
@@ -1270,8 +1303,8 @@ var ErrorTraceRetentionProcessor = class {
1270
1303
  }
1271
1304
  /** Promote the active trace, if any — called on captured errors. */
1272
1305
  retainActiveTrace() {
1273
- const active2 = import_api3.trace.getActiveSpan()?.spanContext();
1274
- if (!active2 || (active2.traceFlags & import_api3.TraceFlags.SAMPLED) !== 0) return;
1306
+ const active2 = _optionalChain([_api.trace, 'access', _43 => _43.getActiveSpan, 'call', _44 => _44(), 'optionalAccess', _45 => _45.spanContext, 'call', _46 => _46()]);
1307
+ if (!active2 || (active2.traceFlags & _api.TraceFlags.SAMPLED) !== 0) return;
1275
1308
  const entry = this.entryFor(active2.traceId);
1276
1309
  if (entry.retained) return;
1277
1310
  entry.retained = true;
@@ -1326,10 +1359,10 @@ var ErrorTraceRetentionProcessor = class {
1326
1359
  if (entry.firstSeenAtMs <= cutoff) this.drop(traceId);
1327
1360
  }
1328
1361
  }
1329
- };
1362
+ }, _class2);
1330
1363
  function llmBaseAttributes(info) {
1331
1364
  return {
1332
- "gen_ai.operation.name": info.operation ?? "chat",
1365
+ "gen_ai.operation.name": _nullishCoalesce(info.operation, () => ( "chat")),
1333
1366
  // Both keys: gen_ai.system is the pre-1.37 semconv name and what
1334
1367
  // most tooling still matches on.
1335
1368
  "gen_ai.provider.name": info.provider,
@@ -1359,97 +1392,107 @@ function usageAttributes(usage) {
1359
1392
  return attrs;
1360
1393
  }
1361
1394
  async function runLlmSpan(tracer, info, fn) {
1362
- const span = tracer.startSpan(`${info.operation ?? "chat"} ${info.model}`, {
1363
- kind: import_api3.SpanKind.CLIENT,
1395
+ const span = tracer.startSpan(`${_nullishCoalesce(info.operation, () => ( "chat"))} ${info.model}`, {
1396
+ kind: _api.SpanKind.CLIENT,
1364
1397
  attributes: llmBaseAttributes(info)
1365
1398
  });
1366
- const setResponseModel = (model) => span.setAttribute("gen_ai.response.model", model);
1399
+ const usage = {};
1400
+ let responseModel;
1401
+ const setResponseModel = (model) => {
1402
+ responseModel = model;
1403
+ span.setAttribute("gen_ai.response.model", model);
1404
+ };
1367
1405
  const handle = {
1368
- setUsage: (usage) => span.setAttributes(usageAttributes(usage)),
1369
- setCost: (usd) => span.setAttribute("autter.llm.cost_usd", usd),
1406
+ setUsage: (next) => {
1407
+ Object.assign(usage, next);
1408
+ span.setAttributes(usageAttributes(next));
1409
+ },
1410
+ setCost: (usd) => {
1411
+ usage.costUsd = usd;
1412
+ span.setAttribute("autter.llm.cost_usd", usd);
1413
+ },
1370
1414
  setResponseModel,
1371
1415
  setModel: setResponseModel,
1372
- setAttributes: (attributes) => span.setAttributes(attributes)
1416
+ setAttributes: (attributes) => span.setAttributes(activeRedactor(attributes))
1373
1417
  };
1374
1418
  try {
1375
- const result = await import_api3.context.with(
1376
- import_api3.trace.setSpan(import_api3.context.active(), span),
1419
+ const result = await _api.context.with(
1420
+ _api.trace.setSpan(_api.context.active(), span),
1377
1421
  () => fn(handle)
1378
1422
  );
1379
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1423
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1380
1424
  return result;
1381
1425
  } catch (err) {
1382
- if (err instanceof Error) {
1383
- span.recordException(err);
1384
- span.setAttribute("error.type", err.name);
1385
- }
1386
- span.setStatus({
1387
- code: import_api3.SpanStatusCode.ERROR,
1388
- message: err instanceof Error ? err.message : String(err)
1389
- });
1426
+ recordError(span, err);
1427
+ if (_chunkUKYTXZOQcjs.isError.call(void 0, err)) span.setAttribute("error.type", err.name);
1390
1428
  throw err;
1391
1429
  } finally {
1392
1430
  span.end();
1431
+ _chunkUKYTXZOQcjs.recordOperationAiUsage.call(void 0, { ...usage, model: _nullishCoalesce(responseModel, () => ( info.model)) });
1393
1432
  }
1394
1433
  }
1395
1434
  function recordLlmCall(tracer, call) {
1396
- const durationMs = Math.max(0, call.durationMs ?? 0);
1435
+ _chunkUKYTXZOQcjs.recordOperationAiUsage.call(void 0, { ...call, model: call.model });
1436
+ const durationMs = Math.max(0, _nullishCoalesce(call.durationMs, () => ( 0)));
1397
1437
  const endTime = /* @__PURE__ */ new Date();
1398
1438
  const startTime = new Date(endTime.getTime() - durationMs);
1399
1439
  const span = tracer.startSpan(
1400
- `${call.operation ?? "chat"} ${call.model}`,
1440
+ `${_nullishCoalesce(call.operation, () => ( "chat"))} ${call.model}`,
1401
1441
  {
1402
- kind: import_api3.SpanKind.CLIENT,
1442
+ kind: _api.SpanKind.CLIENT,
1403
1443
  startTime,
1404
1444
  attributes: { ...llmBaseAttributes(call), ...usageAttributes(call) }
1405
1445
  }
1406
1446
  );
1407
1447
  if (call.error !== void 0 && call.error !== null) {
1408
- if (call.error instanceof Error) {
1409
- span.recordException(call.error);
1448
+ recordError(span, call.error);
1449
+ if (_chunkUKYTXZOQcjs.isError.call(void 0, call.error)) {
1410
1450
  span.setAttribute("error.type", call.error.name);
1411
1451
  }
1412
- span.setStatus({
1413
- code: import_api3.SpanStatusCode.ERROR,
1414
- message: call.error instanceof Error ? call.error.message : String(call.error)
1415
- });
1416
1452
  } else {
1417
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1453
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1418
1454
  }
1419
1455
  span.end(endTime);
1420
1456
  }
1421
- async function runWithSpan(tracer, name, fn, attributes) {
1422
- const span = tracer.startSpan(name, { attributes });
1457
+ async function runWithSpan(tracer, name, fn, attributes, links) {
1458
+ const span = tracer.startSpan(name, {
1459
+ attributes,
1460
+ ..._optionalChain([links, 'optionalAccess', _47 => _47.length]) ? { links } : {}
1461
+ });
1423
1462
  try {
1424
- const result = await import_api3.context.with(
1425
- import_api3.trace.setSpan(import_api3.context.active(), span),
1463
+ const result = await _api.context.with(
1464
+ _api.trace.setSpan(_api.context.active(), span),
1426
1465
  fn
1427
1466
  );
1428
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1467
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1429
1468
  return result;
1430
1469
  } catch (err) {
1431
- if (err instanceof Error) span.recordException(err);
1432
- span.setStatus({
1433
- code: import_api3.SpanStatusCode.ERROR,
1434
- message: err instanceof Error ? err.message : String(err)
1435
- });
1470
+ recordError(span, err);
1436
1471
  throw err;
1437
1472
  } finally {
1438
1473
  span.end();
1439
1474
  }
1440
1475
  }
1441
- function expressRouteOf(req) {
1442
- const props = req;
1443
- const path = props?.route?.path;
1444
- if (typeof path !== "string" || path === "") return null;
1445
- const base = typeof props?.baseUrl === "string" ? props.baseUrl : "";
1446
- const route = base + path;
1447
- return route.startsWith("/") ? route : null;
1476
+ function recordError(span, err) {
1477
+ const isErr = _chunkUKYTXZOQcjs.isError.call(void 0, err);
1478
+ const message = activeRedactor.text(isErr ? err.message : String(err));
1479
+ if (isErr) {
1480
+ span.addEvent("exception", {
1481
+ "exception.type": err.name,
1482
+ "exception.message": message,
1483
+ ...err.stack ? { "exception.stacktrace": activeRedactor.text(err.stack) } : {},
1484
+ ..._chunkUKYTXZOQcjs.breadcrumbEventAttributes.call(void 0, activeRedactor.text, err)
1485
+ });
1486
+ }
1487
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message });
1488
+ }
1489
+ function redactWithActive(attributes) {
1490
+ return activeRedactor(attributes);
1448
1491
  }
1449
1492
  function captureExpressRoute(_span, response) {
1450
- if (!(response instanceof import_node_http.ServerResponse)) return;
1451
- const rpcMetadata = (0, import_core2.getRPCMetadata)(import_api3.context.active());
1452
- if (rpcMetadata?.type !== import_core2.RPCType.HTTP) return;
1493
+ if (!(response instanceof _http.ServerResponse)) return;
1494
+ const rpcMetadata = _core.getRPCMetadata.call(void 0, _api.context.active());
1495
+ if (_optionalChain([rpcMetadata, 'optionalAccess', _48 => _48.type]) !== _core.RPCType.HTTP) return;
1453
1496
  const setRoute = () => {
1454
1497
  if (rpcMetadata.route) return;
1455
1498
  const route = expressRouteOf(response.req);
@@ -1457,33 +1500,67 @@ function captureExpressRoute(_span, response) {
1457
1500
  };
1458
1501
  response.prependListener("finish", setRoute);
1459
1502
  response.prependListener("close", setRoute);
1503
+ if (hookRequests) startHookRequest(response);
1504
+ }
1505
+ var hookRequests = false;
1506
+ function structuredErrorAttributes(error) {
1507
+ const attrs = { ..._chunkUKYTXZOQcjs.errorAttributes.call(void 0, error, { causes: false }) };
1508
+ const internal = _chunkUKYTXZOQcjs.errorInternal.call(void 0, error);
1509
+ if (internal) {
1510
+ try {
1511
+ attrs["autter.error.internal"] = JSON.stringify(
1512
+ activeRedactor(internal)
1513
+ ).slice(0, 4e3);
1514
+ } catch (e28) {
1515
+ }
1516
+ }
1517
+ return attrs;
1460
1518
  }
1461
1519
  var active = null;
1462
1520
  var activeAlwaysOnProvider = null;
1463
- var activeRedactor = makeRedactor(true);
1521
+ var activeRedactor = _chunkUKYTXZOQcjs.makeRedactor.call(void 0, true);
1464
1522
  function initAutterServer(options) {
1465
1523
  if (active) return active;
1466
- const endpoint = (options.endpoint ?? "https://otlp.autter.dev").replace(
1524
+ const endpoint = (_nullishCoalesce(options.endpoint, () => ( "https://otlp.autter.dev"))).replace(
1467
1525
  /\/$/,
1468
1526
  ""
1469
1527
  );
1470
1528
  const headers = { authorization: `Bearer ${options.apiKey}` };
1471
- const environment = options.environment ?? process.env.NODE_ENV ?? "production";
1472
- if (isDebugEnabled() || options.debug === true) setDebugMode(true);
1473
- debugLog(`initialising service=${options.service} endpoint=${endpoint}`);
1474
- activeRedactor = makeRedactor(options.redactAttributes ?? true);
1475
- const resource = new import_resources.Resource({
1476
- [import_semantic_conventions.ATTR_SERVICE_NAME]: options.service,
1477
- "service.instance.id": (options.instanceId || process.env.AUTTER_RUNTIME_INSTANCE_ID || (0, import_node_crypto2.randomUUID)()).slice(0, 128),
1478
- ...options.release ? { [import_semantic_conventions.ATTR_SERVICE_VERSION]: options.release } : {},
1529
+ const traceExporter = () => new (0, _chunkARN26OK6cjs.CountingExporter)(
1530
+ new RedactingSpanExporter(
1531
+ new (0, _exportertraceotlphttp.OTLPTraceExporter)({ url: `${endpoint}/v1/traces`, headers }),
1532
+ () => activeRedactor
1533
+ )
1534
+ );
1535
+ const environment = _nullishCoalesce(_nullishCoalesce(options.environment, () => ( process.env.NODE_ENV)), () => ( "production"));
1536
+ if (_chunkARN26OK6cjs.isDebugEnabled.call(void 0, ) || options.debug === true) _chunkARN26OK6cjs.setDebugMode.call(void 0, true);
1537
+ _chunkARN26OK6cjs.debugLog.call(void 0, `initialising service=${options.service} endpoint=${endpoint}`);
1538
+ activeRedactor = _chunkUKYTXZOQcjs.makeRedactor.call(void 0, _nullishCoalesce(options.redactAttributes, () => ( true)));
1539
+ const distro = _nullishCoalesce(options.distro, () => ( _chunkARN26OK6cjs.SDK_IDENTITY));
1540
+ _chunkARN26OK6cjs.configureCompatCheck.call(void 0, { endpoint, enabled: options.compatCheck !== false, sdk: distro });
1541
+ const resource = new (0, _resources.Resource)({
1542
+ [_semanticconventions.ATTR_SERVICE_NAME]: options.service,
1543
+ "service.instance.id": (options.instanceId || process.env.AUTTER_RUNTIME_INSTANCE_ID || _crypto.randomUUID.call(void 0, )).slice(0, 128),
1544
+ ...options.release ? { [_semanticconventions.ATTR_SERVICE_VERSION]: options.release } : {},
1479
1545
  "deployment.environment": environment,
1546
+ // OTel semconv for SDK distributions: the ingester records which
1547
+ // Autter SDK version each service runs (version compatibility checks).
1548
+ "telemetry.distro.name": distro.name,
1549
+ "telemetry.distro.version": distro.version,
1480
1550
  // Tells the ingester request metrics arrive on the metrics pipe, so
1481
1551
  // it must not also fold our server spans into usage rollups (that
1482
1552
  // would double-count every sampled request).
1483
1553
  "autter.metrics_wired": true
1484
1554
  });
1485
- const headSampler = new import_sdk_trace_base.ParentBasedSampler({
1486
- root: new import_sdk_trace_base.TraceIdRatioBasedSampler(options.traceSampleRate ?? 0.01)
1555
+ const rootSampler = new (0, _sdktracebase.TraceIdRatioBasedSampler)(_nullishCoalesce(options.traceSampleRate, () => ( 0.01)));
1556
+ const headSampler = new (0, _sdktracebase.ParentBasedSampler)({
1557
+ root: rootSampler,
1558
+ // Browsers (runtime-browser's traceparent) send unsampled parents: they
1559
+ // make no sampling decision. Apply this service's own rate to such
1560
+ // requests instead of never head-sampling them. The ratio sampler is
1561
+ // deterministic by trace id, so services sharing a rate still agree
1562
+ // with an upstream service that chose not to sample.
1563
+ remoteParentNotSampled: rootSampler
1487
1564
  });
1488
1565
  const retainOnError = options.retainTracesOnError !== false;
1489
1566
  const slowThresholdMs = Number.isFinite(options.retainTracesAboveMs) ? Math.max(0, options.retainTracesAboveMs) : 0;
@@ -1491,33 +1568,27 @@ function initAutterServer(options) {
1491
1568
  let sampler = retainTraces ? new RecordUnsampledSampler(headSampler) : headSampler;
1492
1569
  if (options.llmTracing !== false) sampler = new LlmAwareSampler(sampler);
1493
1570
  const errorTraceBuffer = retainTraces ? new ErrorTraceRetentionProcessor(
1494
- new import_sdk_trace_base.BatchSpanProcessor(
1495
- new CountingExporter(
1496
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1497
- ),
1498
- { scheduledDelayMillis: 2e3 }
1499
- ),
1571
+ new (0, _sdktracebase.BatchSpanProcessor)(traceExporter(), { scheduledDelayMillis: 2e3 }),
1500
1572
  retainOnError,
1501
1573
  slowThresholdMs
1502
1574
  ) : null;
1503
- const mainSpanProcessor = new import_sdk_trace_base.BatchSpanProcessor(
1504
- new CountingExporter(
1505
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1506
- )
1507
- );
1508
- const metricReader = new import_sdk_metrics.PeriodicExportingMetricReader({
1509
- exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
1510
- url: `${endpoint}/v1/metrics`,
1511
- headers,
1512
- // Deltas, not lifetime totals: the ingester SUMs data points
1513
- // into runtime_metrics_1m, and the default (cumulative)
1514
- // temporality would re-count every past request on each
1515
- // 60 s export.
1516
- temporalityPreference: import_exporter_metrics_otlp_http.AggregationTemporalityPreference.DELTA
1517
- }),
1518
- exportIntervalMillis: options.metricIntervalMs ?? 6e4
1575
+ const mainSpanProcessor = new (0, _sdktracebase.BatchSpanProcessor)(traceExporter());
1576
+ const metricReader = new (0, _sdkmetrics.PeriodicExportingMetricReader)({
1577
+ exporter: new RedactingMetricExporter(
1578
+ new (0, _exportermetricsotlphttp.OTLPMetricExporter)({
1579
+ url: `${endpoint}/v1/metrics`,
1580
+ headers,
1581
+ // Deltas, not lifetime totals: the ingester SUMs data points
1582
+ // into runtime_metrics_1m, and the default (cumulative)
1583
+ // temporality would re-count every past request on each
1584
+ // 60 s export.
1585
+ temporalityPreference: _exportermetricsotlphttp.AggregationTemporalityPreference.DELTA
1586
+ }),
1587
+ () => activeRedactor
1588
+ ),
1589
+ exportIntervalMillis: _nullishCoalesce(options.metricIntervalMs, () => ( 6e4))
1519
1590
  });
1520
- const sdk = new import_sdk_node.NodeSDK({
1591
+ const sdk = new (0, _sdknode.NodeSDK)({
1521
1592
  resource,
1522
1593
  sampler,
1523
1594
  spanProcessors: [
@@ -1526,127 +1597,156 @@ function initAutterServer(options) {
1526
1597
  ],
1527
1598
  metricReader,
1528
1599
  views: [
1529
- new import_sdk_metrics.View({ instrumentName: "http.server.duration", aggregation: new import_sdk_metrics.ExplicitBucketHistogramAggregation(
1600
+ new (0, _sdkmetrics.View)({ instrumentName: "http.server.duration", aggregation: new (0, _sdkmetrics.ExplicitBucketHistogramAggregation)(
1530
1601
  [5, 10, 25, 50, 100, 250, 500, 750, 1e3, 1500, 2e3, 3e3, 5e3, 7500, 1e4, 15e3, 2e4, 3e4, 6e4, 12e4]
1531
1602
  ) }),
1532
- new import_sdk_metrics.View({ instrumentName: "http.server.request.duration", aggregation: new import_sdk_metrics.ExplicitBucketHistogramAggregation(
1603
+ new (0, _sdkmetrics.View)({ instrumentName: "http.server.request.duration", aggregation: new (0, _sdkmetrics.ExplicitBucketHistogramAggregation)(
1533
1604
  [5e-3, 0.01, 0.025, 0.05, 0.1, 0.25, 0.5, 0.75, 1, 1.5, 2, 3, 5, 7.5, 10, 15, 20, 30, 60, 120]
1534
1605
  ) })
1535
1606
  ],
1536
1607
  instrumentations: [
1537
- new import_instrumentation_http.HttpInstrumentation({ responseHook: captureExpressRoute }),
1538
- ...options.instrumentations ?? []
1608
+ new (0, _instrumentationhttp.HttpInstrumentation)({ responseHook: captureExpressRoute }),
1609
+ ..._nullishCoalesce(options.instrumentations, () => ( []))
1539
1610
  ]
1540
1611
  });
1541
1612
  sdk.start();
1542
1613
  const stopMemoryMetrics = options.memoryMetrics === false ? null : startMemoryMetrics();
1543
- const alwaysOnProvider = new import_sdk_trace_base.BasicTracerProvider({
1614
+ _chunkARN26OK6cjs.noteCompatFeature.call(void 0, "endpoint_latency");
1615
+ if (stopMemoryMetrics) _chunkARN26OK6cjs.noteCompatFeature.call(void 0, "memory_metrics");
1616
+ if (options.llmTracing !== false) _chunkARN26OK6cjs.noteCompatFeature.call(void 0, "llm_calls");
1617
+ const alwaysOnProvider = new (0, _sdktracebase.BasicTracerProvider)({
1544
1618
  resource,
1545
- sampler: new import_sdk_trace_base.AlwaysOnSampler(),
1619
+ sampler: new (0, _sdktracebase.AlwaysOnSampler)(),
1546
1620
  spanProcessors: [
1547
- new import_sdk_trace_base.BatchSpanProcessor(
1548
- new CountingExporter(
1549
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1550
- ),
1551
- { scheduledDelayMillis: 2e3 }
1552
- )
1621
+ new (0, _sdktracebase.BatchSpanProcessor)(traceExporter(), { scheduledDelayMillis: 2e3 })
1553
1622
  ]
1554
1623
  });
1555
1624
  const errorTracer = alwaysOnProvider.getTracer("autter-errors");
1556
1625
  const processTracer = alwaysOnProvider.getTracer("autter-processes");
1557
1626
  const llmTracer = alwaysOnProvider.getTracer("autter-llm");
1558
1627
  function captureException2(error, attributes) {
1559
- errorTraceBuffer?.retainActiveTrace();
1560
- telemetryStats.markCaptured();
1561
- const isError = error instanceof Error;
1562
- const message = isError ? error.message : String(error);
1563
- const redacted = activeRedactor(attributes);
1564
- const activeSpan = import_api3.trace.getActiveSpan();
1565
- const reuseActive = activeSpan?.isRecording() === true;
1566
- const span = reuseActive ? activeSpan : errorTracer.startSpan(isError ? error.name : "Error");
1567
- span.setAttributes({ "autter.severity": "error", ...redacted });
1568
- if (isError && error.stack) {
1569
- if (redacted["autter.handled"] === true) {
1570
- span.addEvent("exception", {
1571
- "exception.type": error.name,
1572
- "exception.message": message,
1573
- "exception.stacktrace": error.stack,
1574
- "autter.handled": true,
1575
- "autter.sampled": redacted["autter.sampled"] === true
1576
- });
1577
- } else {
1578
- span.recordException(error);
1579
- }
1628
+ _optionalChain([errorTraceBuffer, 'optionalAccess', _49 => _49.retainActiveTrace, 'call', _50 => _50()]);
1629
+ _chunkARN26OK6cjs.telemetryStats.markCaptured();
1630
+ const isErr = _chunkUKYTXZOQcjs.isError.call(void 0, error);
1631
+ const message = activeRedactor.text(isErr ? error.message : String(error));
1632
+ const stackText = isErr && error.stack ? activeRedactor.text(error.stack) : "";
1633
+ const split = _chunkUKYTXZOQcjs.splitFingerprint.call(void 0, attributes);
1634
+ const fingerprint = _chunkUKYTXZOQcjs.fingerprintEventAttributes.call(void 0, split.fingerprint, activeRedactor.text);
1635
+ if (fingerprint["autter.fingerprint"]) _chunkARN26OK6cjs.noteCompatFeature.call(void 0, "fingerprint_override");
1636
+ const redacted = activeRedactor(split.attributes);
1637
+ const activeSpan = _api.trace.getActiveSpan();
1638
+ const reuseActive = _optionalChain([activeSpan, 'optionalAccess', _51 => _51.isRecording, 'call', _52 => _52()]) === true;
1639
+ const span = reuseActive ? activeSpan : errorTracer.startSpan(isErr ? error.name : "Error");
1640
+ const structured = structuredErrorAttributes(error);
1641
+ const causes = _chunkUKYTXZOQcjs.errorAttributes.call(void 0, error);
1642
+ const declared = {
1643
+ ...Object.fromEntries(Object.entries(causes).filter(([key]) => key !== "autter.error.internal")),
1644
+ ...fingerprint
1645
+ };
1646
+ const requestId = _optionalChain([_chunkUKYTXZOQcjs.currentOperation.call(void 0, ), 'optionalAccess', _53 => _53.requestId]);
1647
+ span.setAttributes({
1648
+ "autter.severity": "error",
1649
+ ...redacted,
1650
+ ...structured,
1651
+ ...requestId ? { "autter.request.id": requestId } : {}
1652
+ });
1653
+ markCaptured(error);
1654
+ _chunkUKYTXZOQcjs.noteOperationError.call(void 0, error);
1655
+ _chunkUKYTXZOQcjs.notifyException.call(void 0, error, { ...redacted, ...fingerprint });
1656
+ if (isErr && stackText) {
1657
+ span.addEvent("exception", {
1658
+ "exception.type": error.name,
1659
+ "exception.message": message,
1660
+ "exception.stacktrace": stackText,
1661
+ ...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
1662
+ ...declared,
1663
+ ..._chunkUKYTXZOQcjs.breadcrumbEventAttributes.call(void 0, activeRedactor.text, error)
1664
+ });
1580
1665
  } else {
1581
- const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureException")).join("\n");
1666
+ const stack = _optionalChain([new Error(), 'access', _54 => _54.stack, 'optionalAccess', _55 => _55.split, 'call', _56 => _56("\n"), 'access', _57 => _57.filter, 'call', _58 => _58((line, i) => i === 0 || !line.includes("captureException")), 'access', _59 => _59.join, 'call', _60 => _60("\n")]);
1582
1667
  span.addEvent("exception", {
1583
- "exception.type": isError ? error.name : "Error",
1668
+ "exception.type": isErr ? error.name : "Error",
1584
1669
  "exception.message": message,
1585
- ...stack ? { "exception.stacktrace": stack } : {},
1586
- ...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {}
1670
+ ...stack ? { "exception.stacktrace": activeRedactor.text(stack) } : {},
1671
+ ...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
1672
+ ...declared,
1673
+ ..._chunkUKYTXZOQcjs.breadcrumbEventAttributes.call(void 0, activeRedactor.text, error)
1587
1674
  });
1588
1675
  }
1589
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message });
1676
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message });
1590
1677
  if (!reuseActive) span.end();
1591
1678
  }
1592
- function captureMessage2(message, severity2 = "warning", attributes) {
1593
- if (severity2 === "error" || severity2 === "fatal") {
1594
- errorTraceBuffer?.retainActiveTrace();
1679
+ function captureMessage2(message, severity = "warning", attributes) {
1680
+ if (severity === "error" || severity === "fatal") {
1681
+ _optionalChain([errorTraceBuffer, 'optionalAccess', _61 => _61.retainActiveTrace, 'call', _62 => _62()]);
1595
1682
  }
1596
- telemetryStats.markCaptured();
1597
- const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureMessage")).join("\n");
1683
+ _chunkARN26OK6cjs.telemetryStats.markCaptured();
1684
+ const stack = _optionalChain([new Error(), 'access', _63 => _63.stack, 'optionalAccess', _64 => _64.split, 'call', _65 => _65("\n"), 'access', _66 => _66.filter, 'call', _67 => _67((line, i) => i === 0 || !line.includes("captureMessage")), 'access', _68 => _68.join, 'call', _69 => _69("\n")]);
1685
+ const safeMessage = activeRedactor.text(message);
1598
1686
  const span = errorTracer.startSpan("Message", {
1599
- attributes: { "autter.severity": severity2, ...activeRedactor(attributes) }
1687
+ attributes: { "autter.severity": severity, ...activeRedactor(attributes) }
1600
1688
  });
1601
1689
  span.addEvent("exception", {
1602
1690
  "exception.type": "Message",
1603
- "exception.message": message,
1604
- ...stack ? { "exception.stacktrace": stack } : {},
1605
- "autter.severity": severity2
1691
+ "exception.message": safeMessage,
1692
+ ...stack ? { "exception.stacktrace": activeRedactor.text(stack) } : {},
1693
+ "autter.severity": severity,
1694
+ ..._chunkUKYTXZOQcjs.breadcrumbEventAttributes.call(void 0, activeRedactor.text)
1606
1695
  });
1607
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message });
1696
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1608
1697
  span.end();
1609
1698
  }
1610
1699
  function reportOutcome2(name, message, attributes) {
1611
- errorTraceBuffer?.retainActiveTrace();
1612
- telemetryStats.markCaptured();
1613
- const activeSpan = import_api3.trace.getActiveSpan();
1614
- const reuseActive = activeSpan?.isRecording() === true;
1700
+ _optionalChain([errorTraceBuffer, 'optionalAccess', _70 => _70.retainActiveTrace, 'call', _71 => _71()]);
1701
+ _chunkARN26OK6cjs.telemetryStats.markCaptured();
1702
+ const activeSpan = _api.trace.getActiveSpan();
1703
+ const reuseActive = _optionalChain([activeSpan, 'optionalAccess', _72 => _72.isRecording, 'call', _73 => _73()]) === true;
1615
1704
  const span = reuseActive ? activeSpan : errorTracer.startSpan("OutcomeFailure");
1616
1705
  const safeOutcome = activeRedactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1617
- const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
1618
- const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
1706
+ const safeName = String(_nullishCoalesce(safeOutcome["autter.outcome.name"], () => ( "operation")));
1707
+ const safeMessage = String(_nullishCoalesce(safeOutcome["autter.outcome.message"], () => ( "failed")));
1619
1708
  span.addEvent("autter.outcome", {
1620
1709
  ...activeRedactor(attributes),
1621
1710
  "autter.outcome.status": "error",
1622
1711
  "autter.outcome.name": safeName,
1623
1712
  "autter.outcome.message": safeMessage
1624
1713
  });
1625
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: safeMessage });
1714
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1626
1715
  if (!reuseActive) span.end();
1627
1716
  }
1628
- configureRuntimeLogger({
1717
+ _chunkUKYTXZOQcjs.configureRuntimeLogger.call(void 0, {
1629
1718
  endpoint,
1630
1719
  apiKey: options.apiKey,
1631
1720
  service: options.service,
1632
1721
  environment,
1722
+ distro,
1633
1723
  release: options.release,
1634
1724
  options: options.logging,
1635
1725
  redact: activeRedactor,
1636
- run: (name, fn, attributes) => runWithSpan(processTracer, name, fn, activeRedactor(attributes)),
1726
+ run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn, activeRedactor(attributes), links),
1637
1727
  reportOutcome: reportOutcome2
1638
1728
  });
1729
+ hookRequests = _optionalChain([options, 'access', _74 => _74.logging, 'optionalAccess', _75 => _75.requests]) === true;
1730
+ let onCrash = null;
1731
+ let uninstallRejections = null;
1639
1732
  if (options.captureGlobalErrors !== false) {
1640
- process.on("uncaughtExceptionMonitor", (err) => {
1733
+ onCrash = (err) => {
1734
+ if (recordedAsRejection(err)) return;
1641
1735
  captureException2(err, { "autter.unhandled": true });
1642
1736
  if (options.autoFlush === false) void Promise.resolve(flushTarget.forceFlush()).catch(() => {
1643
1737
  });
1644
- });
1738
+ };
1739
+ process.on("uncaughtExceptionMonitor", onCrash);
1740
+ if (options.captureUnhandledRejections !== false) {
1741
+ uninstallRejections = installUnhandledRejectionCapture(
1742
+ (reason) => captureException2(reason, { "autter.unhandled_rejection": true })
1743
+ );
1744
+ }
1645
1745
  }
1646
1746
  const flushTarget = {
1647
1747
  forceFlush: async () => {
1648
1748
  const results = await Promise.allSettled([
1649
- flushRuntimeLogs(),
1749
+ _chunkUKYTXZOQcjs.flushRuntimeLogs.call(void 0, ),
1650
1750
  Promise.resolve().then(() => alwaysOnProvider.forceFlush()),
1651
1751
  Promise.resolve().then(() => mainSpanProcessor.forceFlush()),
1652
1752
  ...errorTraceBuffer ? [Promise.resolve().then(() => errorTraceBuffer.forceFlush())] : [],
@@ -1660,10 +1760,10 @@ function initAutterServer(options) {
1660
1760
  }
1661
1761
  }
1662
1762
  };
1663
- registerFlushTarget("active-server", flushTarget);
1763
+ _chunkARN26OK6cjs.registerFlushTarget.call(void 0, "active-server", flushTarget);
1664
1764
  let autoFlushHandle = null;
1665
1765
  if (options.autoFlush !== false) {
1666
- autoFlushHandle = installAutterAutoFlush();
1766
+ autoFlushHandle = _chunkARN26OK6cjs.installAutterAutoFlush.call(void 0, );
1667
1767
  }
1668
1768
  const server = {
1669
1769
  captureException: captureException2,
@@ -1673,16 +1773,19 @@ function initAutterServer(options) {
1673
1773
  withLlmCall: (info, fn) => runLlmSpan(llmTracer, info, fn),
1674
1774
  trackLlmCall: (call) => recordLlmCall(llmTracer, call),
1675
1775
  shutdown: async () => {
1676
- const logShutdown = await Promise.allSettled([shutdownRuntimeLogger()]);
1677
- stopMemoryMetrics?.();
1776
+ const logShutdown = await Promise.allSettled([_chunkUKYTXZOQcjs.shutdownRuntimeLogger.call(void 0, )]);
1777
+ hookRequests = false;
1778
+ if (onCrash) process.off("uncaughtExceptionMonitor", onCrash);
1779
+ _optionalChain([uninstallRejections, 'optionalCall', _76 => _76()]);
1780
+ _optionalChain([stopMemoryMetrics, 'optionalCall', _77 => _77()]);
1678
1781
  active = null;
1679
1782
  activeAlwaysOnProvider = null;
1680
- autoFlushHandle?.dispose();
1783
+ _optionalChain([autoFlushHandle, 'optionalAccess', _78 => _78.dispose, 'call', _79 => _79()]);
1681
1784
  autoFlushHandle = null;
1682
- unregisterFlushTargets();
1683
- telemetryStats.markAllFlushed();
1785
+ _chunkARN26OK6cjs.unregisterFlushTargets.call(void 0, );
1786
+ _chunkARN26OK6cjs.telemetryStats.markAllFlushed();
1684
1787
  await Promise.allSettled([alwaysOnProvider.shutdown(), sdk.shutdown()]);
1685
- if (logShutdown[0]?.status === "rejected") throw logShutdown[0].reason;
1788
+ if (_optionalChain([logShutdown, 'access', _80 => _80[0], 'optionalAccess', _81 => _81.status]) === "rejected") throw logShutdown[0].reason;
1686
1789
  }
1687
1790
  };
1688
1791
  active = server;
@@ -1694,69 +1797,95 @@ function captureException(error, attributes) {
1694
1797
  active.captureException(error, attributes);
1695
1798
  return;
1696
1799
  }
1697
- const span = import_api3.trace.getTracer("autter-errors").startSpan(error instanceof Error ? error.name : "Error", { attributes });
1698
- if (error instanceof Error) span.recordException(error);
1699
- span.setStatus({
1700
- code: import_api3.SpanStatusCode.ERROR,
1701
- message: error instanceof Error ? error.message : String(error)
1800
+ if (loggerOnlyCapture) {
1801
+ loggerOnlyCapture(error, attributes);
1802
+ return;
1803
+ }
1804
+ markCaptured(error);
1805
+ _chunkUKYTXZOQcjs.noteOperationError.call(void 0, error);
1806
+ const split = _chunkUKYTXZOQcjs.splitFingerprint.call(void 0, attributes);
1807
+ const fingerprint = _chunkUKYTXZOQcjs.fingerprintEventAttributes.call(void 0, split.fingerprint, activeRedactor.text);
1808
+ _chunkUKYTXZOQcjs.notifyException.call(void 0, error, { ...split.attributes, ...fingerprint });
1809
+ const span = _api.trace.getTracer("autter-errors").startSpan(_chunkUKYTXZOQcjs.isError.call(void 0, error) ? error.name : "Error", {
1810
+ attributes: { ...activeRedactor(split.attributes), ...fingerprint }
1702
1811
  });
1812
+ recordError(span, error);
1703
1813
  span.end();
1704
1814
  }
1815
+ var loggerOnlyCapture = null;
1816
+ function setLoggerOnlyCapture(fn) {
1817
+ loggerOnlyCapture = fn;
1818
+ }
1819
+ function serverActive() {
1820
+ return active !== null;
1821
+ }
1822
+ setRequestExceptionCapturer((error, attributes) => captureException(error, attributes));
1823
+ setRequestSpanAnnotator((attributes) => {
1824
+ const span = _api.trace.getActiveSpan();
1825
+ if (_optionalChain([span, 'optionalAccess', _82 => _82.isRecording, 'call', _83 => _83()])) span.setAttributes(activeRedactor(_chunkUKYTXZOQcjs.splitFingerprint.call(void 0, attributes).attributes));
1826
+ });
1705
1827
  function withProcessSpan(name, fn, attributes) {
1706
1828
  if (active) return active.withProcessSpan(name, fn, attributes);
1707
- return runWithSpan(import_api3.trace.getTracer("autter-processes"), name, fn, attributes);
1829
+ return runWithSpan(
1830
+ _api.trace.getTracer("autter-processes"),
1831
+ name,
1832
+ fn,
1833
+ activeRedactor(attributes)
1834
+ );
1708
1835
  }
1709
1836
  function withLlmCall(info, fn) {
1710
1837
  if (active) return active.withLlmCall(info, fn);
1711
- return runLlmSpan(import_api3.trace.getTracer("autter-llm"), info, fn);
1838
+ return runLlmSpan(_api.trace.getTracer("autter-llm"), info, fn);
1712
1839
  }
1713
1840
  function trackLlmCall(call) {
1714
1841
  if (active) {
1715
1842
  active.trackLlmCall(call);
1716
1843
  return;
1717
1844
  }
1718
- recordLlmCall(import_api3.trace.getTracer("autter-llm"), call);
1845
+ recordLlmCall(_api.trace.getTracer("autter-llm"), call);
1719
1846
  }
1720
- function captureMessage(message, severity2 = "warning", attributes) {
1847
+ function captureMessage(message, severity = "warning", attributes) {
1721
1848
  if (active) {
1722
- active.captureMessage(message, severity2, attributes);
1849
+ active.captureMessage(message, severity, attributes);
1723
1850
  return;
1724
1851
  }
1725
- const span = import_api3.trace.getTracer("autter-errors").startSpan("Message", {
1726
- attributes: { "autter.severity": severity2, ...attributes }
1852
+ const safeMessage = activeRedactor.text(message);
1853
+ const span = _api.trace.getTracer("autter-errors").startSpan("Message", {
1854
+ attributes: { "autter.severity": severity, ...activeRedactor(attributes) }
1727
1855
  });
1728
1856
  span.addEvent("exception", {
1729
1857
  "exception.type": "Message",
1730
- "exception.message": message,
1731
- "autter.severity": severity2
1858
+ "exception.message": safeMessage,
1859
+ "autter.severity": severity,
1860
+ ..._chunkUKYTXZOQcjs.breadcrumbEventAttributes.call(void 0, activeRedactor.text)
1732
1861
  });
1733
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message });
1862
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1734
1863
  span.end();
1735
1864
  }
1736
1865
  function reportOutcome(name, message, attributes) {
1737
1866
  if (active) return active.reportOutcome(name, message, attributes);
1738
- const span = import_api3.trace.getTracer("autter-outcomes").startSpan("OutcomeFailure");
1739
- const safeOutcome = redactAttributes({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1740
- const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
1741
- const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
1867
+ const span = _api.trace.getTracer("autter-outcomes").startSpan("OutcomeFailure");
1868
+ const safeOutcome = _chunkUKYTXZOQcjs.redactAttributes.call(void 0, { "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1869
+ const safeName = String(_nullishCoalesce(safeOutcome["autter.outcome.name"], () => ( "operation")));
1870
+ const safeMessage = String(_nullishCoalesce(safeOutcome["autter.outcome.message"], () => ( "failed")));
1742
1871
  span.addEvent("autter.outcome", {
1743
- ...redactAttributes(attributes),
1872
+ ..._chunkUKYTXZOQcjs.redactAttributes.call(void 0, attributes),
1744
1873
  "autter.outcome.status": "error",
1745
1874
  "autter.outcome.name": safeName,
1746
1875
  "autter.outcome.message": safeMessage
1747
1876
  });
1748
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: safeMessage });
1877
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1749
1878
  span.end();
1750
1879
  }
1751
1880
  function makeSafeCapture(options) {
1752
- const clean = (attributes) => attributes ? { ...redactAttributes(attributes, options) } : void 0;
1881
+ const clean = (attributes) => attributes ? { ..._chunkUKYTXZOQcjs.redactAttributes.call(void 0, attributes, options) } : void 0;
1753
1882
  return {
1754
1883
  captureException: (error, attributes) => captureException(error, clean(attributes)),
1755
- captureMessage: (message, severity2, attributes) => captureMessage(message, severity2 ?? "warning", clean(attributes))
1884
+ captureMessage: (message, severity, attributes) => captureMessage(message, _nullishCoalesce(severity, () => ( "warning")), clean(attributes))
1756
1885
  };
1757
1886
  }
1758
1887
  function alwaysOnTracer(name) {
1759
- return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) : import_api3.trace.getTracer(name);
1888
+ return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) : _api.trace.getTracer(name);
1760
1889
  }
1761
1890
  function autterLlmTracer() {
1762
1891
  return alwaysOnTracer("autter-llm");
@@ -1776,7 +1905,7 @@ async function emitLlmSelftestTrace() {
1776
1905
  attributes: { "autter.selftest": true }
1777
1906
  },
1778
1907
  (llm) => {
1779
- traceId = import_api3.trace.getActiveSpan()?.spanContext().traceId ?? "";
1908
+ traceId = _nullishCoalesce(_optionalChain([_api.trace, 'access', _84 => _84.getActiveSpan, 'call', _85 => _85(), 'optionalAccess', _86 => _86.spanContext, 'call', _87 => _87(), 'access', _88 => _88.traceId]), () => ( ""));
1780
1909
  llm.setUsage({ inputTokens: 1, outputTokens: 1 });
1781
1910
  llm.setCost(0);
1782
1911
  }
@@ -1786,7 +1915,10 @@ async function emitLlmSelftestTrace() {
1786
1915
  }
1787
1916
 
1788
1917
  // src/llm-instrument.ts
1789
- var import_api4 = require("@opentelemetry/api");
1918
+
1919
+
1920
+
1921
+
1790
1922
  var CALL_METHODS = /* @__PURE__ */ new Set([
1791
1923
  "create",
1792
1924
  // openai chat/completions/embeddings/responses, anthropic messages
@@ -1801,15 +1933,15 @@ var CALL_METHODS = /* @__PURE__ */ new Set([
1801
1933
  // openai beta structured outputs
1802
1934
  ]);
1803
1935
  function detectProvider(client) {
1804
- const name = client.constructor?.name?.toLowerCase() ?? "";
1936
+ const name = _nullishCoalesce(_optionalChain([client, 'access', _89 => _89.constructor, 'optionalAccess', _90 => _90.name, 'optionalAccess', _91 => _91.toLowerCase, 'call', _92 => _92()]), () => ( ""));
1805
1937
  for (const known of ["openai", "anthropic", "mistral", "groq", "cohere"]) {
1806
1938
  if (name.includes(known)) return known;
1807
1939
  }
1808
1940
  if (name.includes("google") || name.includes("genai")) return "google";
1809
1941
  const baseUrl = String(
1810
- client.baseURL ?? client.baseUrl ?? ""
1942
+ _nullishCoalesce(_nullishCoalesce(client.baseURL, () => ( client.baseUrl)), () => ( ""))
1811
1943
  );
1812
- const host = baseUrl.match(/https?:\/\/([^/]+)/)?.[1] ?? "";
1944
+ const host = _nullishCoalesce(_optionalChain([baseUrl, 'access', _93 => _93.match, 'call', _94 => _94(/https?:\/\/([^/]+)/), 'optionalAccess', _95 => _95[1]]), () => ( ""));
1813
1945
  if (host.includes("openai")) return "openai";
1814
1946
  if (host.includes("anthropic")) return "anthropic";
1815
1947
  if (host.includes("googleapis")) return "google";
@@ -1819,17 +1951,28 @@ function detectProvider(client) {
1819
1951
  }
1820
1952
  function extractUsage(result) {
1821
1953
  const r = result;
1822
- const usage = r?.usage ?? r?.message?.usage;
1823
- const meta = r?.usageMetadata;
1824
- const input = usage?.prompt_tokens ?? usage?.input_tokens ?? meta?.promptTokenCount ?? void 0;
1825
- const output = usage?.completion_tokens ?? usage?.output_tokens ?? meta?.candidatesTokenCount ?? void 0;
1826
- const responseModel = r?.model ?? r?.modelVersion;
1954
+ const usage = _nullishCoalesce(_optionalChain([r, 'optionalAccess', _96 => _96.usage]), () => ( _optionalChain([r, 'optionalAccess', _97 => _97.message, 'optionalAccess', _98 => _98.usage])));
1955
+ const meta = _optionalChain([r, 'optionalAccess', _99 => _99.usageMetadata]);
1956
+ const details = _optionalChain([usage, 'optionalAccess', _100 => _100.prompt_tokens_details]);
1957
+ const cached = _nullishCoalesce(_nullishCoalesce(_optionalChain([usage, 'optionalAccess', _101 => _101.cache_read_input_tokens]), () => ( (typeof _optionalChain([details, 'optionalAccess', _102 => _102.cached_tokens]) === "number" ? details.cached_tokens : void 0))), () => ( _optionalChain([meta, 'optionalAccess', _103 => _103.cachedContentTokenCount])));
1958
+ const input = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([usage, 'optionalAccess', _104 => _104.prompt_tokens]), () => ( _optionalChain([usage, 'optionalAccess', _105 => _105.input_tokens]))), () => ( _optionalChain([meta, 'optionalAccess', _106 => _106.promptTokenCount]))), () => ( void 0));
1959
+ const output = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([usage, 'optionalAccess', _107 => _107.completion_tokens]), () => ( _optionalChain([usage, 'optionalAccess', _108 => _108.output_tokens]))), () => ( _optionalChain([meta, 'optionalAccess', _109 => _109.candidatesTokenCount]))), () => ( void 0));
1960
+ const responseModel = _nullishCoalesce(_optionalChain([r, 'optionalAccess', _110 => _110.model]), () => ( _optionalChain([r, 'optionalAccess', _111 => _111.modelVersion])));
1827
1961
  return {
1828
1962
  inputTokens: typeof input === "number" ? input : void 0,
1829
1963
  outputTokens: typeof output === "number" ? output : void 0,
1964
+ cacheReadTokens: typeof cached === "number" ? cached : void 0,
1830
1965
  responseModel: typeof responseModel === "string" ? responseModel : void 0
1831
1966
  };
1832
1967
  }
1968
+ function rollUp(model, usage) {
1969
+ _chunkUKYTXZOQcjs.recordOperationAiUsage.call(void 0, {
1970
+ model: _nullishCoalesce(usage.responseModel, () => ( model)),
1971
+ ...usage.inputTokens !== void 0 ? { inputTokens: usage.inputTokens } : {},
1972
+ ...usage.outputTokens !== void 0 ? { outputTokens: usage.outputTokens } : {},
1973
+ ...usage.cacheReadTokens !== void 0 ? { cacheReadTokens: usage.cacheReadTokens } : {}
1974
+ });
1975
+ }
1833
1976
  function applyUsage(span, usage) {
1834
1977
  if (usage.inputTokens !== void 0) {
1835
1978
  span.setAttribute("gen_ai.usage.input_tokens", usage.inputTokens);
@@ -1842,14 +1985,10 @@ function applyUsage(span, usage) {
1842
1985
  }
1843
1986
  }
1844
1987
  function endWithError(span, err) {
1845
- if (err instanceof Error) span.recordException(err);
1846
- span.setStatus({
1847
- code: import_api4.SpanStatusCode.ERROR,
1848
- message: err instanceof Error ? err.message : String(err)
1849
- });
1988
+ recordError(span, err);
1850
1989
  span.end();
1851
1990
  }
1852
- function wrapStream(stream, span) {
1991
+ function wrapStream(stream, span, model) {
1853
1992
  let ended = false;
1854
1993
  const seen = {
1855
1994
  inputTokens: void 0,
@@ -1860,11 +1999,12 @@ function wrapStream(stream, span) {
1860
1999
  if (ended) return;
1861
2000
  ended = true;
1862
2001
  applyUsage(span, seen);
2002
+ rollUp(model, seen);
1863
2003
  span.setAttribute("autter.llm.streamed", true);
1864
2004
  if (err !== void 0) {
1865
2005
  endWithError(span, err);
1866
2006
  } else {
1867
- span.setStatus({ code: import_api4.SpanStatusCode.OK });
2007
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1868
2008
  span.end();
1869
2009
  }
1870
2010
  };
@@ -1881,6 +2021,7 @@ function wrapStream(stream, span) {
1881
2021
  const usage = extractUsage(step.value);
1882
2022
  if (usage.inputTokens !== void 0) seen.inputTokens = usage.inputTokens;
1883
2023
  if (usage.outputTokens !== void 0) seen.outputTokens = usage.outputTokens;
2024
+ if (usage.cacheReadTokens !== void 0) seen.cacheReadTokens = usage.cacheReadTokens;
1884
2025
  if (usage.responseModel) seen.responseModel = usage.responseModel;
1885
2026
  } else {
1886
2027
  finish();
@@ -1891,9 +2032,9 @@ function wrapStream(stream, span) {
1891
2032
  throw err;
1892
2033
  }
1893
2034
  },
1894
- async return(value3) {
2035
+ async return(value2) {
1895
2036
  finish();
1896
- return inner.return ? inner.return(value3) : { done: true, value: void 0 };
2037
+ return inner.return ? inner.return(value2) : { done: true, value: void 0 };
1897
2038
  },
1898
2039
  async throw(err) {
1899
2040
  finish(err);
@@ -1903,30 +2044,30 @@ function wrapStream(stream, span) {
1903
2044
  };
1904
2045
  };
1905
2046
  }
1906
- const value2 = Reflect.get(target, prop, receiver);
1907
- return typeof value2 === "function" ? value2.bind(target) : value2;
2047
+ const value = Reflect.get(target, prop, receiver);
2048
+ return typeof value === "function" ? value.bind(target) : value;
1908
2049
  }
1909
2050
  });
1910
2051
  }
1911
2052
  function instrumentLlmClient(client, options) {
1912
- const provider = (options?.provider ?? detectProvider(client)).toLowerCase();
2053
+ const provider = (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _112 => _112.provider]), () => ( detectProvider(client)))).toLowerCase();
1913
2054
  const proxied = /* @__PURE__ */ new WeakMap();
1914
2055
  function resolveUserId() {
1915
- return typeof options?.userId === "function" ? options.userId() : options?.userId;
2056
+ return typeof _optionalChain([options, 'optionalAccess', _113 => _113.userId]) === "function" ? options.userId() : _optionalChain([options, 'optionalAccess', _114 => _114.userId]);
1916
2057
  }
1917
2058
  function traceCall(fn, self, callPath, args) {
1918
2059
  const request = args[0];
1919
2060
  const operation = /embed/i.test(callPath) ? "embeddings" : "chat";
1920
2061
  const userId = resolveUserId();
1921
2062
  const span = autterLlmTracer().startSpan(`${operation} ${request.model}`, {
1922
- kind: import_api4.SpanKind.CLIENT,
2063
+ kind: _api.SpanKind.CLIENT,
1923
2064
  attributes: {
1924
2065
  "gen_ai.operation.name": operation,
1925
2066
  "gen_ai.provider.name": provider,
1926
2067
  "gen_ai.system": provider,
1927
2068
  "gen_ai.request.model": request.model,
1928
2069
  ...userId ? { "autter.user_id": userId } : {},
1929
- ...options?.attributes
2070
+ ...redactWithActive(_optionalChain([options, 'optionalAccess', _115 => _115.attributes]))
1930
2071
  }
1931
2072
  });
1932
2073
  let result;
@@ -1938,20 +2079,24 @@ function instrumentLlmClient(client, options) {
1938
2079
  }
1939
2080
  if (!(result instanceof Promise)) {
1940
2081
  if (result && typeof result === "object" && Symbol.asyncIterator in result) {
1941
- return wrapStream(result, span);
2082
+ return wrapStream(result, span, request.model);
1942
2083
  }
1943
- applyUsage(span, extractUsage(result));
1944
- span.setStatus({ code: import_api4.SpanStatusCode.OK });
2084
+ const usage = extractUsage(result);
2085
+ applyUsage(span, usage);
2086
+ rollUp(request.model, usage);
2087
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1945
2088
  span.end();
1946
2089
  return result;
1947
2090
  }
1948
2091
  return result.then(
1949
2092
  (resolved) => {
1950
2093
  if (resolved && typeof resolved === "object" && Symbol.asyncIterator in resolved) {
1951
- return wrapStream(resolved, span);
2094
+ return wrapStream(resolved, span, request.model);
1952
2095
  }
1953
- applyUsage(span, extractUsage(resolved));
1954
- span.setStatus({ code: import_api4.SpanStatusCode.OK });
2096
+ const usage = extractUsage(resolved);
2097
+ applyUsage(span, usage);
2098
+ rollUp(request.model, usage);
2099
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1955
2100
  span.end();
1956
2101
  return resolved;
1957
2102
  },
@@ -1966,30 +2111,30 @@ function instrumentLlmClient(client, options) {
1966
2111
  if (cached) return cached;
1967
2112
  const proxy = new Proxy(target, {
1968
2113
  get(t, prop, receiver) {
1969
- const value2 = Reflect.get(t, prop, receiver);
1970
- if (typeof prop === "symbol") return value2;
2114
+ const value = Reflect.get(t, prop, receiver);
2115
+ if (typeof prop === "symbol") return value;
1971
2116
  const propPath = path ? `${path}.${prop}` : prop;
1972
- if (typeof value2 === "function") {
2117
+ if (typeof value === "function") {
1973
2118
  if (CALL_METHODS.has(prop)) {
1974
2119
  return (...args) => {
1975
2120
  const first = args[0];
1976
2121
  if (first && typeof first === "object" && typeof first.model === "string") {
1977
2122
  return traceCall(
1978
- value2,
2123
+ value,
1979
2124
  t,
1980
2125
  propPath,
1981
2126
  args
1982
2127
  );
1983
2128
  }
1984
- return value2.apply(t, args);
2129
+ return value.apply(t, args);
1985
2130
  };
1986
2131
  }
1987
- return value2.bind(t);
2132
+ return value.bind(t);
1988
2133
  }
1989
- if (value2 !== null && typeof value2 === "object" && !(value2 instanceof Promise)) {
1990
- return deepProxy(value2, propPath);
2134
+ if (value !== null && typeof value === "object" && !(value instanceof Promise)) {
2135
+ return deepProxy(value, propPath);
1991
2136
  }
1992
- return value2;
2137
+ return value;
1993
2138
  }
1994
2139
  });
1995
2140
  proxied.set(target, proxy);
@@ -1999,11 +2144,11 @@ function instrumentLlmClient(client, options) {
1999
2144
  }
2000
2145
 
2001
2146
  // src/caught-exceptions.ts
2002
- var import_node_inspector = __toESM(require("inspector"), 1);
2147
+ var _inspector = require('inspector'); var _inspector2 = _interopRequireDefault(_inspector);
2003
2148
  function startCaughtExceptionSampler(options = {}) {
2004
- const rate = Math.max(0, Math.min(1, options.sampleRate ?? 0.01));
2005
- const cap = Math.max(1, Math.min(100, options.maxPerMinute ?? 10));
2006
- const session = new import_node_inspector.default.Session();
2149
+ const rate = Math.max(0, Math.min(1, _nullishCoalesce(options.sampleRate, () => ( 0.01))));
2150
+ const cap = Math.max(1, Math.min(100, _nullishCoalesce(options.maxPerMinute, () => ( 10))));
2151
+ const session = new _inspector2.default.Session();
2007
2152
  let active2 = true;
2008
2153
  let minute = 0;
2009
2154
  let sent = 0;
@@ -2019,7 +2164,7 @@ function startCaughtExceptionSampler(options = {}) {
2019
2164
  }
2020
2165
  if (sent >= cap || Math.random() >= rate) return;
2021
2166
  sent++;
2022
- const frames = message.params.callFrames.slice(0, 8).filter((frame) => frame.url && !frame.url.startsWith("node:")).map((frame) => ` at ${frame.functionName || "anonymous"} (${frame.url.split("?")[0]}:${frame.location.lineNumber + 1}:${(frame.location.columnNumber ?? 0) + 1})`);
2167
+ const frames = message.params.callFrames.slice(0, 8).filter((frame) => frame.url && !frame.url.startsWith("node:")).map((frame) => ` at ${frame.functionName || "anonymous"} (${frame.url.split("?")[0]}:${frame.location.lineNumber + 1}:${(_nullishCoalesce(frame.location.columnNumber, () => ( 0))) + 1})`);
2023
2168
  if (!frames.length) return;
2024
2169
  const error = new Error("Sampled caught exception");
2025
2170
  error.name = "CaughtException";
@@ -2041,27 +2186,300 @@ ${frames.join("\n")}`;
2041
2186
  });
2042
2187
  } };
2043
2188
  }
2044
- // Annotate the CommonJS export names for ESM import in node:
2045
- 0 && (module.exports = {
2046
- captureException,
2047
- captureMessage,
2048
- createBrowserRelayFetchHandler,
2049
- createBrowserRelayHandler,
2050
- createRuntimeLogger,
2051
- emitLlmSelftestTrace,
2052
- flushRuntimeLogs,
2053
- initAutterServer,
2054
- installAutterAutoFlush,
2055
- instrumentLlmClient,
2056
- makeSafeCapture,
2057
- redactAttributes,
2058
- reportOutcome,
2059
- runtimeLogStats,
2060
- runtimeLogger,
2061
- sanitizeBrowserPayload,
2062
- startCaughtExceptionSampler,
2063
- trackLlmCall,
2064
- withLlmCall,
2065
- withProcessSpan,
2066
- withRuntimeOperation
2067
- });
2189
+
2190
+ // src/framework-errors.ts
2191
+ function recordBoundaryError(error, req, rule) {
2192
+ try {
2193
+ const state = requestStateOf(req);
2194
+ if (state) _chunkUKYTXZOQcjs.noteOperationError.call(void 0, error, false, state);
2195
+ captureAtBoundary(error, state, rule);
2196
+ } catch (e29) {
2197
+ }
2198
+ }
2199
+ function autterErrorHandler(options = {}) {
2200
+ return function autterErrorHandlerMiddleware(error, req, _res, next) {
2201
+ recordBoundaryError(error, req, options.capture);
2202
+ next(error);
2203
+ };
2204
+ }
2205
+ function autterFastifyErrors(fastify, options, done) {
2206
+ const rule = _optionalChain([options, 'optionalAccess', _116 => _116.capture]);
2207
+ fastify.addHook("onError", ((request, _reply, error, next) => {
2208
+ recordBoundaryError(error, _optionalChain([request, 'optionalAccess', _117 => _117.raw]), rule);
2209
+ next();
2210
+ }));
2211
+ _optionalChain([done, 'optionalCall', _118 => _118()]);
2212
+ }
2213
+ autterFastifyErrors[/* @__PURE__ */ Symbol.for("skip-override")] = true;
2214
+ autterFastifyErrors[/* @__PURE__ */ Symbol.for("fastify.display-name")] = "autter-runtime-errors";
2215
+ function autterKoa(options = {}) {
2216
+ return async function autterKoaMiddleware(ctx, next) {
2217
+ try {
2218
+ await next();
2219
+ } catch (error) {
2220
+ recordBoundaryError(error, _optionalChain([ctx, 'optionalAccess', _119 => _119.req]), options.capture);
2221
+ throw error;
2222
+ }
2223
+ };
2224
+ }
2225
+
2226
+ // src/logging-only.ts
2227
+
2228
+
2229
+
2230
+
2231
+ var activeLogging = null;
2232
+ function initAutterLogging(options) {
2233
+ if (activeLogging) return activeLogging;
2234
+ if (serverActive()) {
2235
+ console.warn(
2236
+ "[autter-runtime] initAutterLogging() ignored: initAutterServer() is already active and includes logging"
2237
+ );
2238
+ return {
2239
+ captureException,
2240
+ flush: _chunkUKYTXZOQcjs.flushRuntimeLogs,
2241
+ shutdown: async () => {
2242
+ }
2243
+ };
2244
+ }
2245
+ if (_chunkARN26OK6cjs.isDebugEnabled.call(void 0, ) || options.debug === true) _chunkARN26OK6cjs.setDebugMode.call(void 0, true);
2246
+ const endpoint = (_nullishCoalesce(options.endpoint, () => ( "https://otlp.autter.dev"))).replace(/\/$/, "");
2247
+ const environment = _nullishCoalesce(_nullishCoalesce(options.environment, () => ( process.env.NODE_ENV)), () => ( "production"));
2248
+ const redact = _chunkUKYTXZOQcjs.makeRedactor.call(void 0, _nullishCoalesce(options.redactAttributes, () => ( true)));
2249
+ const mode = _nullishCoalesce(options.exceptions, () => ( "auto"));
2250
+ _chunkARN26OK6cjs.debugLog.call(void 0, `initialising logger-only service=${options.service} endpoint=${endpoint}`);
2251
+ function captureException2(error, attributes) {
2252
+ markCaptured(error);
2253
+ const split = _chunkUKYTXZOQcjs.splitFingerprint.call(void 0, attributes);
2254
+ const fingerprint = _chunkUKYTXZOQcjs.fingerprintEventAttributes.call(void 0, split.fingerprint, redact.text);
2255
+ const redacted = redact(split.attributes);
2256
+ const span = _api.trace.getActiveSpan();
2257
+ if (mode === "auto" && _optionalChain([span, 'optionalAccess', _120 => _120.isRecording, 'call', _121 => _121()])) {
2258
+ _chunkUKYTXZOQcjs.noteOperationError.call(void 0, error);
2259
+ _chunkUKYTXZOQcjs.notifyException.call(void 0, error, { ...redacted, ...fingerprint });
2260
+ span.setAttributes({ "autter.severity": "error", ...redacted, ...structuredErrorAttributes(error) });
2261
+ const declared = { ..._chunkUKYTXZOQcjs.errorAttributes.call(void 0, error), ...fingerprint };
2262
+ if (_chunkUKYTXZOQcjs.isError.call(void 0, error)) {
2263
+ span.addEvent("exception", {
2264
+ "exception.type": error.name,
2265
+ "exception.message": error.message,
2266
+ ...error.stack ? { "exception.stacktrace": error.stack } : {},
2267
+ ...declared
2268
+ });
2269
+ } else {
2270
+ span.addEvent("exception", {
2271
+ "exception.type": "Error",
2272
+ "exception.message": String(error),
2273
+ ...declared
2274
+ });
2275
+ }
2276
+ span.setStatus({
2277
+ code: _api.SpanStatusCode.ERROR,
2278
+ message: _chunkUKYTXZOQcjs.isError.call(void 0, error) ? error.message : String(error)
2279
+ });
2280
+ return;
2281
+ }
2282
+ _chunkUKYTXZOQcjs.notifyException.call(void 0, error, { ...redacted, ...fingerprint });
2283
+ _chunkUKYTXZOQcjs.captureExceptionAsLog.call(void 0, error, { ...redacted, ...fingerprint });
2284
+ }
2285
+ const captured = /* @__PURE__ */ new WeakSet();
2286
+ _chunkUKYTXZOQcjs.configureRuntimeLogger.call(void 0, {
2287
+ endpoint,
2288
+ apiKey: _nullishCoalesce(options.apiKey, () => ( "")),
2289
+ service: options.service,
2290
+ environment,
2291
+ ...options.release ? { release: options.release } : {},
2292
+ ...options.logging ? { options: options.logging } : {},
2293
+ redact,
2294
+ reportOutcome: (name, message, attributes) => {
2295
+ _chunkUKYTXZOQcjs.runtimeLogger.error(message, {
2296
+ ...attributes,
2297
+ "autter.outcome.name": name.slice(0, 200),
2298
+ "autter.outcome.message": message.slice(0, 1e3)
2299
+ });
2300
+ },
2301
+ captureThrown: (error) => {
2302
+ if (error && typeof error === "object") {
2303
+ if (captured.has(error)) return;
2304
+ captured.add(error);
2305
+ }
2306
+ captureException2(error);
2307
+ }
2308
+ });
2309
+ setLoggerOnlyCapture(captureException2);
2310
+ const onCrash = (error) => {
2311
+ if (recordedAsRejection(error)) return;
2312
+ captureException2(error, { "autter.unhandled": true });
2313
+ };
2314
+ let uninstallRejections = null;
2315
+ if (options.captureGlobalErrors !== false) {
2316
+ process.on("uncaughtExceptionMonitor", onCrash);
2317
+ if (options.captureUnhandledRejections !== false)
2318
+ uninstallRejections = installUnhandledRejectionCapture(
2319
+ (reason) => captureException2(reason, { "autter.unhandled_rejection": true })
2320
+ );
2321
+ }
2322
+ _chunkARN26OK6cjs.registerFlushTarget.call(void 0, "logging", { forceFlush: () => _chunkUKYTXZOQcjs.flushRuntimeLogs.call(void 0, ) });
2323
+ let autoFlushHandle = options.autoFlush === false ? null : _chunkARN26OK6cjs.installAutterAutoFlush.call(void 0, );
2324
+ const handle = {
2325
+ captureException: captureException2,
2326
+ flush: _chunkUKYTXZOQcjs.flushRuntimeLogs,
2327
+ shutdown: async () => {
2328
+ process.off("uncaughtExceptionMonitor", onCrash);
2329
+ _optionalChain([uninstallRejections, 'optionalCall', _122 => _122()]);
2330
+ uninstallRejections = null;
2331
+ setLoggerOnlyCapture(null);
2332
+ _optionalChain([autoFlushHandle, 'optionalAccess', _123 => _123.dispose, 'call', _124 => _124()]);
2333
+ autoFlushHandle = null;
2334
+ _chunkARN26OK6cjs.unregisterFlushTargets.call(void 0, );
2335
+ activeLogging = null;
2336
+ await _chunkUKYTXZOQcjs.shutdownRuntimeLogger.call(void 0, );
2337
+ }
2338
+ };
2339
+ activeLogging = handle;
2340
+ return handle;
2341
+ }
2342
+
2343
+ // src/enrichers.ts
2344
+ function headerOf(req, name) {
2345
+ const headers = _optionalChain([req, 'optionalAccess', _125 => _125.headers]);
2346
+ if (!headers) return void 0;
2347
+ if (typeof headers.get === "function") {
2348
+ return _nullishCoalesce(headers.get(name), () => ( void 0));
2349
+ }
2350
+ const value = headers[name.toLowerCase()];
2351
+ if (Array.isArray(value)) return value[0] === void 0 ? void 0 : String(value[0]);
2352
+ return value === void 0 || value === null ? void 0 : String(value);
2353
+ }
2354
+ function enrichUserAgent() {
2355
+ return (event, { req }) => {
2356
+ const ua = headerOf(req, "user-agent");
2357
+ if (!ua) return;
2358
+ const info = _chunkUKYTXZOQcjs.parseUserAgent.call(void 0, ua);
2359
+ if (info.browser) event.attributes["user_agent.browser"] = info.browser;
2360
+ if (info.os) event.attributes["user_agent.os"] = info.os;
2361
+ event.attributes["user_agent.device"] = info.device;
2362
+ event.attributes["user_agent.bot"] = info.bot;
2363
+ };
2364
+ }
2365
+ function enrichRequestSize() {
2366
+ return (event, { req, res }) => {
2367
+ const request = Number(headerOf(req, "content-length"));
2368
+ if (Number.isFinite(request) && request >= 0)
2369
+ event.attributes["http.request.body.size"] = request;
2370
+ const raw = _optionalChain([res, 'optionalAccess', _126 => _126.getHeader, 'optionalCall', _127 => _127(
2371
+ "content-length"
2372
+ )]);
2373
+ const response = Number(raw);
2374
+ if (raw !== void 0 && Number.isFinite(response) && response >= 0)
2375
+ event.attributes["http.response.body.size"] = response;
2376
+ };
2377
+ }
2378
+ var COUNTRY_HEADERS = [
2379
+ "cf-ipcountry",
2380
+ "x-vercel-ip-country",
2381
+ "cloudfront-viewer-country",
2382
+ "x-country-code",
2383
+ "fastly-geo-country-code"
2384
+ ];
2385
+ function enrichEdgeGeo() {
2386
+ return (event, { req }) => {
2387
+ for (const name of COUNTRY_HEADERS) {
2388
+ const value = _optionalChain([headerOf, 'call', _128 => _128(req, name), 'optionalAccess', _129 => _129.trim, 'call', _130 => _130(), 'access', _131 => _131.toUpperCase, 'call', _132 => _132()]);
2389
+ if (value && /^[A-Z]{2}$/.test(value) && value !== "XX" && value !== "T1") {
2390
+ event.attributes["geo.country.iso_code"] = value;
2391
+ return;
2392
+ }
2393
+ }
2394
+ };
2395
+ }
2396
+ var REGION_VARS = [
2397
+ "AUTTER_REGION",
2398
+ "AWS_REGION",
2399
+ "VERCEL_REGION",
2400
+ "FLY_REGION",
2401
+ "RAILWAY_REPLICA_REGION",
2402
+ "GOOGLE_CLOUD_REGION",
2403
+ "CLOUD_RUN_REGION",
2404
+ "RENDER_REGION",
2405
+ "AZURE_REGION"
2406
+ ];
2407
+ var COMMIT_VARS = [
2408
+ "AUTTER_COMMIT",
2409
+ "GIT_SHA",
2410
+ "GIT_COMMIT",
2411
+ "COMMIT_SHA",
2412
+ "SOURCE_COMMIT",
2413
+ "VERCEL_GIT_COMMIT_SHA",
2414
+ "GITHUB_SHA",
2415
+ "RENDER_GIT_COMMIT",
2416
+ "RAILWAY_GIT_COMMIT_SHA",
2417
+ "CF_PAGES_COMMIT_SHA",
2418
+ "HEROKU_SLUG_COMMIT",
2419
+ "SOURCE_VERSION"
2420
+ ];
2421
+ function enrichDeployment(env = process.env) {
2422
+ const pick = (names) => names.map((name) => _optionalChain([env, 'access', _133 => _133[name], 'optionalAccess', _134 => _134.trim, 'call', _135 => _135()])).find((value) => value);
2423
+ const region = _optionalChain([pick, 'call', _136 => _136(REGION_VARS), 'optionalAccess', _137 => _137.slice, 'call', _138 => _138(0, 64)]);
2424
+ const commit = _optionalChain([pick, 'call', _139 => _139(COMMIT_VARS), 'optionalAccess', _140 => _140.slice, 'call', _141 => _141(0, 64)]);
2425
+ return (event) => {
2426
+ if (region) event.attributes["deployment.region"] = region;
2427
+ if (commit) event.attributes["deployment.commit"] = commit;
2428
+ };
2429
+ }
2430
+
2431
+
2432
+
2433
+
2434
+
2435
+
2436
+
2437
+
2438
+
2439
+
2440
+
2441
+
2442
+
2443
+
2444
+
2445
+
2446
+
2447
+
2448
+
2449
+
2450
+
2451
+
2452
+
2453
+
2454
+
2455
+
2456
+
2457
+
2458
+
2459
+
2460
+
2461
+
2462
+
2463
+
2464
+
2465
+
2466
+
2467
+
2468
+
2469
+
2470
+
2471
+
2472
+
2473
+
2474
+
2475
+
2476
+
2477
+
2478
+
2479
+
2480
+
2481
+
2482
+
2483
+
2484
+
2485
+ exports.CODE_PATTERN = _chunkUKYTXZOQcjs.CODE_PATTERN; exports.COMPAT_MANIFEST = _chunkARN26OK6cjs.COMPAT_MANIFEST; exports.INGESTER_VERSION_HEADER = _chunkARN26OK6cjs.INGESTER_VERSION_HEADER; exports.RuntimeError = _chunkUKYTXZOQcjs.RuntimeError; exports.SDK_IDENTITY = _chunkARN26OK6cjs.SDK_IDENTITY; exports.addBreadcrumb = _chunkUKYTXZOQcjs.addBreadcrumb; exports.autterErrorHandler = autterErrorHandler; exports.autterErrorResponse = autterErrorResponse; exports.autterFastify = autterFastify; exports.autterFastifyErrors = autterFastifyErrors; exports.autterKoa = autterKoa; exports.autterRequests = autterRequests; exports.captureException = captureException; exports.captureMessage = captureMessage; exports.captureRequestError = captureRequestError; exports.consoleSink = _chunkUKYTXZOQcjs.consoleSink; exports.createBrowserRelayFetchHandler = createBrowserRelayFetchHandler; exports.createBrowserRelayHandler = createBrowserRelayHandler; exports.createRuntimeLogger = _chunkUKYTXZOQcjs.createRuntimeLogger; exports.defineRuntimeErrors = _chunkUKYTXZOQcjs.defineRuntimeErrors; exports.emitLlmSelftestTrace = emitLlmSelftestTrace; exports.enrichDeployment = enrichDeployment; exports.enrichEdgeGeo = enrichEdgeGeo; exports.enrichRequestSize = enrichRequestSize; exports.enrichUserAgent = enrichUserAgent; exports.errorAttributes = _chunkUKYTXZOQcjs.errorAttributes; exports.evaluateCompat = _chunkARN26OK6cjs.evaluateCompat; exports.fetchIngesterCompat = _chunkARN26OK6cjs.fetchIngesterCompat; exports.fileSink = _chunkUKYTXZOQcjs.fileSink; exports.flushRuntimeLogs = _chunkUKYTXZOQcjs.flushRuntimeLogs; exports.initAutterLogging = initAutterLogging; exports.initAutterServer = initAutterServer; exports.installAutterAutoFlush = _chunkARN26OK6cjs.installAutterAutoFlush; exports.instrumentLlmClient = instrumentLlmClient; exports.isRuntimeErrorLike = _chunkUKYTXZOQcjs.isRuntimeErrorLike; exports.makeSafeCapture = makeSafeCapture; exports.otlpSink = _chunkUKYTXZOQcjs.otlpSink; exports.redactAttributes = _chunkUKYTXZOQcjs.redactAttributes; exports.redactText = _chunkUKYTXZOQcjs.redactText; exports.reportOutcome = reportOutcome; exports.runDoctor = _chunkUGNPCOIWcjs.runDoctor; exports.runInBackground = _chunkUKYTXZOQcjs.runInBackground; exports.runtimeContext = _chunkUKYTXZOQcjs.runtimeContext; exports.runtimeLogStats = _chunkUKYTXZOQcjs.runtimeLogStats; exports.runtimeLogger = _chunkUKYTXZOQcjs.runtimeLogger; exports.sanitizeBrowserPayload = sanitizeBrowserPayload; exports.startCaughtExceptionSampler = startCaughtExceptionSampler; exports.toClientError = _chunkUKYTXZOQcjs.toClientError; exports.trackLlmCall = trackLlmCall; exports.unhandledRejectionsMode = unhandledRejectionsMode; exports.withLlmCall = withLlmCall; exports.withProcessSpan = withProcessSpan; exports.withRuntimeOperation = _chunkUKYTXZOQcjs.withRuntimeOperation; exports.withRuntimeRequest = withRuntimeRequest;