@autter/runtime-node 1.3.4 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -1,61 +1,76 @@
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
- emitLlmSelftestTrace: () => emitLlmSelftestTrace,
38
- initAutterServer: () => initAutterServer,
39
- installAutterAutoFlush: () => installAutterAutoFlush,
40
- instrumentLlmClient: () => instrumentLlmClient,
41
- makeSafeCapture: () => makeSafeCapture,
42
- redactAttributes: () => redactAttributes,
43
- reportOutcome: () => reportOutcome,
44
- sanitizeBrowserPayload: () => sanitizeBrowserPayload,
45
- startCaughtExceptionSampler: () => startCaughtExceptionSampler,
46
- trackLlmCall: () => trackLlmCall,
47
- withLlmCall: () => withLlmCall,
48
- withProcessSpan: () => withProcessSpan
49
- });
50
- 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
+ var _chunkP4VRTFAVcjs = require('./chunk-P4VRTFAV.cjs');
42
+
43
+
44
+ var _chunkL6SRL65Jcjs = require('./chunk-L6SRL65J.cjs');
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+
59
+
60
+
61
+
62
+
63
+
64
+
65
+ var _chunkGI47WGRRcjs = require('./chunk-GI47WGRR.cjs');
51
66
 
52
67
  // src/relay.ts
53
- var IpWindow = class {
54
- constructor(limitPerMinute) {
68
+ var IpWindow = (_class = class {
69
+ constructor(limitPerMinute) {;_class.prototype.__init.call(this);
55
70
  this.limitPerMinute = limitPerMinute;
56
71
  }
57
- limitPerMinute;
58
- windows = /* @__PURE__ */ new Map();
72
+
73
+ __init() {this.windows = /* @__PURE__ */ new Map()}
59
74
  allow(ip) {
60
75
  const start = Math.floor(Date.now() / 6e4) * 6e4;
61
76
  const entry = this.windows.get(ip);
@@ -67,10 +82,10 @@ var IpWindow = class {
67
82
  entry.count += 1;
68
83
  return entry.count <= this.limitPerMinute;
69
84
  }
70
- };
85
+ }, _class);
71
86
  function firstForwardedFor(value) {
72
87
  const raw = Array.isArray(value) ? value[0] : value;
73
- return raw ? (raw.split(",")[0] ?? "").trim() : "";
88
+ return raw ? (_nullishCoalesce(raw.split(",")[0], () => ( ""))).trim() : "";
74
89
  }
75
90
  var DEFAULT_ENDPOINT = "https://otlp.autter.dev";
76
91
  var DEFAULT_MAX_BODY = 64 * 1024;
@@ -87,7 +102,120 @@ var EVENT_TYPES = /* @__PURE__ */ new Set([
87
102
  "timing"
88
103
  ]);
89
104
  var SEVERITIES = /* @__PURE__ */ new Set(["fatal", "error", "warning", "info"]);
90
- function sanitizeBrowserPayload(raw) {
105
+ var CONTEXT_MAX_DEPTH = 6;
106
+ var CONTEXT_MAX_NODES = 256;
107
+ var CONTEXT_MAX_STRING = 4e3;
108
+ var CONTEXT_MAX_ARRAY = 100;
109
+ var CONTEXT_MAX_KEYS = 100;
110
+ function byteLength(text) {
111
+ return new TextEncoder().encode(text).length;
112
+ }
113
+ function boundContext(value) {
114
+ let nodes = 0;
115
+ const seen = /* @__PURE__ */ new WeakSet();
116
+ const walk = (v, depth) => {
117
+ if (v === null) return null;
118
+ const t = typeof v;
119
+ if (t === "string") return v.slice(0, CONTEXT_MAX_STRING);
120
+ if (t === "number" || t === "boolean") return v;
121
+ if (t !== "object") return void 0;
122
+ if (depth >= CONTEXT_MAX_DEPTH || nodes >= CONTEXT_MAX_NODES) return void 0;
123
+ const obj = v;
124
+ if (seen.has(obj)) return void 0;
125
+ seen.add(obj);
126
+ let isArr = false;
127
+ try {
128
+ isArr = Array.isArray(v);
129
+ } catch (e2) {
130
+ return void 0;
131
+ }
132
+ if (isArr) {
133
+ const arr = v;
134
+ const out2 = [];
135
+ let len = 0;
136
+ try {
137
+ len = arr.length;
138
+ } catch (e3) {
139
+ return out2;
140
+ }
141
+ for (let i = 0; i < len && i < CONTEXT_MAX_ARRAY; i++) {
142
+ if (nodes >= CONTEXT_MAX_NODES) break;
143
+ nodes++;
144
+ let el;
145
+ try {
146
+ el = walk(arr[i], depth + 1);
147
+ } catch (e4) {
148
+ el = void 0;
149
+ }
150
+ if (el !== void 0) out2.push(el);
151
+ }
152
+ return out2;
153
+ }
154
+ let keys;
155
+ try {
156
+ keys = Object.keys(obj);
157
+ } catch (e5) {
158
+ return void 0;
159
+ }
160
+ const out = {};
161
+ for (let i = 0; i < keys.length && i < CONTEXT_MAX_KEYS; i++) {
162
+ if (nodes >= CONTEXT_MAX_NODES) break;
163
+ const key = keys[i];
164
+ if (key === void 0) continue;
165
+ nodes++;
166
+ let child;
167
+ try {
168
+ child = walk(obj[key], depth + 1);
169
+ } catch (e6) {
170
+ child = void 0;
171
+ }
172
+ if (child !== void 0) out[key] = child;
173
+ }
174
+ return out;
175
+ };
176
+ let result;
177
+ try {
178
+ result = walk(value, 0);
179
+ } catch (e7) {
180
+ result = void 0;
181
+ }
182
+ return result && typeof result === "object" ? result : {};
183
+ }
184
+ async function readBodyBounded(request, maxBody) {
185
+ const body = request.body;
186
+ if (!body) {
187
+ const text = await request.text();
188
+ return byteLength(text) > maxBody ? { tooLarge: true } : { tooLarge: false, text };
189
+ }
190
+ const reader = body.getReader();
191
+ const chunks = [];
192
+ let total = 0;
193
+ for (; ; ) {
194
+ const { done, value } = await reader.read();
195
+ if (done) break;
196
+ if (!value) continue;
197
+ total += value.byteLength;
198
+ if (total > maxBody) {
199
+ void Promise.resolve().then(() => reader.cancel()).catch(() => {
200
+ });
201
+ return { tooLarge: true };
202
+ }
203
+ chunks.push(value);
204
+ }
205
+ const buf = new Uint8Array(total);
206
+ let offset = 0;
207
+ for (const chunk of chunks) {
208
+ buf.set(chunk, offset);
209
+ offset += chunk.byteLength;
210
+ }
211
+ return { tooLarge: false, text: new TextDecoder().decode(buf) };
212
+ }
213
+ function relayContext(raw, redactor) {
214
+ const bounded = boundContext(raw);
215
+ return Array.isArray(bounded) ? {} : { context: redactor(bounded) };
216
+ }
217
+ var defaultRelayRedactor = _chunkP4VRTFAVcjs.makeRedactor.call(void 0, true);
218
+ function sanitizeBrowserPayload(raw, redactor = defaultRelayRedactor) {
91
219
  if (typeof raw !== "object" || raw === null) return null;
92
220
  const p = raw;
93
221
  if (p.version !== 1) return null;
@@ -104,16 +232,16 @@ function sanitizeBrowserPayload(raw) {
104
232
  type: e.type,
105
233
  timestamp: e.timestamp,
106
234
  ...typeof e.severity === "string" && SEVERITIES.has(e.severity) ? { severity: e.severity } : {},
107
- message: typeof e.message === "string" ? e.message.slice(0, 4e3) : "",
108
- ...typeof e.name === "string" ? { name: e.name.slice(0, 200) } : {},
235
+ message: typeof e.message === "string" ? redactor.text(e.message.slice(0, 4512)).slice(0, 4e3) : "",
236
+ ...typeof e.name === "string" ? { name: redactor.text(e.name.slice(0, 712)).slice(0, 200) } : {},
109
237
  ...typeof e.durationMs === "number" && Number.isFinite(e.durationMs) ? { durationMs: Math.max(0, Math.min(12e4, e.durationMs)) } : {},
110
- ...typeof e.stack === "string" ? { stack: e.stack.slice(0, 32e3) } : {},
238
+ ...typeof e.stack === "string" ? { stack: redactor.text(e.stack.slice(0, 32512)).slice(0, 32e3) } : {},
111
239
  ...typeof e.errorType === "string" ? { errorType: e.errorType.slice(0, 200) } : {},
112
240
  ...typeof e.filename === "string" ? { filename: e.filename.split("?")[0].slice(0, 1e3) } : {},
113
241
  ...typeof e.line === "number" ? { line: e.line } : {},
114
242
  ...typeof e.column === "number" ? { column: e.column } : {},
115
243
  ...typeof e.route === "string" ? { route: e.route.split("?")[0].slice(0, 1e3) } : {},
116
- ...typeof e.context === "object" && e.context !== null ? { context: e.context } : {}
244
+ ...typeof e.context === "object" && e.context !== null ? relayContext(e.context, redactor) : {}
117
245
  });
118
246
  }
119
247
  return {
@@ -122,11 +250,16 @@ function sanitizeBrowserPayload(raw) {
122
250
  service: p.service.slice(0, 200),
123
251
  environment: p.environment.slice(0, 100),
124
252
  ...typeof p.release === "string" ? { release: p.release.slice(0, 200) } : {},
253
+ // @autter/runtime-browser version, for the ingester's compat records.
254
+ ...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 } : {},
125
255
  events
126
256
  };
127
257
  }
128
258
  function forward(payload, opts) {
129
- const url = `${(opts.endpoint ?? DEFAULT_ENDPOINT).replace(/\/$/, "")}/v1/browser`;
259
+ const endpoint = (_nullishCoalesce(opts.endpoint, () => ( DEFAULT_ENDPOINT))).replace(/\/$/, "");
260
+ const url = `${endpoint}/v1/browser`;
261
+ const compat = opts.compatCheck !== false;
262
+ if (compat) _chunkGI47WGRRcjs.ensureCompatConfigured.call(void 0, endpoint);
130
263
  void fetch(url, {
131
264
  method: "POST",
132
265
  headers: {
@@ -135,15 +268,24 @@ function forward(payload, opts) {
135
268
  },
136
269
  body: JSON.stringify(payload),
137
270
  signal: AbortSignal.timeout(1e4)
271
+ }).then((response) => {
272
+ if (!compat) return;
273
+ const types = new Set(
274
+ (_nullishCoalesce(payload.events, () => ( []))).map((e) => String(e.type))
275
+ );
276
+ _chunkGI47WGRRcjs.observeIngesterResponse.call(void 0, { status: response.status, headers: response.headers });
277
+ for (const feature of _chunkGI47WGRRcjs.featuresForBrowserEvents.call(void 0, types)) _chunkGI47WGRRcjs.noteCompatFeature.call(void 0, feature);
278
+ _chunkGI47WGRRcjs.noteRelayRejection.call(void 0, types, response.status, response.headers);
138
279
  }).catch((err) => {
139
- (opts.onError ?? ((e) => console.warn("autter relay forward failed:", e)))(
280
+ (_nullishCoalesce(opts.onError, () => ( ((e) => console.warn("autter relay forward failed:", e)))))(
140
281
  err
141
282
  );
142
283
  });
143
284
  }
144
285
  function createBrowserRelayFetchHandler(opts) {
145
- const maxBody = opts.maxBodyBytes ?? DEFAULT_MAX_BODY;
146
- const limiter = opts.perIpRateLimit === false ? null : new IpWindow(opts.perIpRateLimit ?? 120);
286
+ const maxBody = _nullishCoalesce(opts.maxBodyBytes, () => ( DEFAULT_MAX_BODY));
287
+ const redactor = opts.redact === void 0 || opts.redact === true ? defaultRelayRedactor : _chunkP4VRTFAVcjs.makeRedactor.call(void 0, opts.redact);
288
+ const limiter = opts.perIpRateLimit === false ? null : new IpWindow(_nullishCoalesce(opts.perIpRateLimit, () => ( 120)));
147
289
  return async (request) => {
148
290
  if (request.method !== "POST") {
149
291
  return new Response(null, { status: 405 });
@@ -156,21 +298,28 @@ function createBrowserRelayFetchHandler(opts) {
156
298
  });
157
299
  }
158
300
  }
159
- const text = await request.text();
160
- if (text.length > maxBody) {
301
+ let bounded;
302
+ try {
303
+ bounded = await readBodyBounded(request, maxBody);
304
+ } catch (e8) {
305
+ return new Response(JSON.stringify({ error: "invalid json" }), {
306
+ status: 400
307
+ });
308
+ }
309
+ if (bounded.tooLarge) {
161
310
  return new Response(JSON.stringify({ error: "payload too large" }), {
162
311
  status: 413
163
312
  });
164
313
  }
165
314
  let raw;
166
315
  try {
167
- raw = JSON.parse(text);
168
- } catch {
316
+ raw = JSON.parse(bounded.text);
317
+ } catch (e9) {
169
318
  return new Response(JSON.stringify({ error: "invalid json" }), {
170
319
  status: 400
171
320
  });
172
321
  }
173
- const payload = sanitizeBrowserPayload(raw);
322
+ const payload = sanitizeBrowserPayload(raw, redactor);
174
323
  if (!payload) {
175
324
  return new Response(JSON.stringify({ error: "invalid payload" }), {
176
325
  status: 400
@@ -181,8 +330,9 @@ function createBrowserRelayFetchHandler(opts) {
181
330
  };
182
331
  }
183
332
  function createBrowserRelayHandler(opts) {
184
- const maxBody = opts.maxBodyBytes ?? DEFAULT_MAX_BODY;
185
- const limiter = opts.perIpRateLimit === false ? null : new IpWindow(opts.perIpRateLimit ?? 120);
333
+ const maxBody = _nullishCoalesce(opts.maxBodyBytes, () => ( DEFAULT_MAX_BODY));
334
+ const redactor = opts.redact === void 0 || opts.redact === true ? defaultRelayRedactor : _chunkP4VRTFAVcjs.makeRedactor.call(void 0, opts.redact);
335
+ const limiter = opts.perIpRateLimit === false ? null : new IpWindow(_nullishCoalesce(opts.perIpRateLimit, () => ( 120)));
186
336
  function respond(res, status, body) {
187
337
  res.statusCode = status;
188
338
  if (body) {
@@ -193,7 +343,7 @@ function createBrowserRelayHandler(opts) {
193
343
  }
194
344
  }
195
345
  function handleParsed(raw, res) {
196
- const payload = sanitizeBrowserPayload(raw);
346
+ const payload = sanitizeBrowserPayload(raw, redactor);
197
347
  if (!payload) {
198
348
  respond(res, 400, { error: "invalid payload" });
199
349
  return;
@@ -207,7 +357,7 @@ function createBrowserRelayHandler(opts) {
207
357
  return;
208
358
  }
209
359
  if (limiter) {
210
- const ip = firstForwardedFor(req.headers["x-forwarded-for"]) || req.socket?.remoteAddress || "unknown";
360
+ const ip = firstForwardedFor(req.headers["x-forwarded-for"]) || _optionalChain([req, 'access', _ => _.socket, 'optionalAccess', _2 => _2.remoteAddress]) || "unknown";
211
361
  if (!limiter.allow(ip)) {
212
362
  respond(res, 429, { error: "rate limit exceeded" });
213
363
  return;
@@ -218,7 +368,7 @@ function createBrowserRelayHandler(opts) {
218
368
  if (typeof raw === "string" || Buffer.isBuffer(raw)) {
219
369
  try {
220
370
  raw = JSON.parse(raw.toString());
221
- } catch {
371
+ } catch (e10) {
222
372
  respond(res, 400, { error: "invalid json" });
223
373
  return;
224
374
  }
@@ -243,7 +393,7 @@ function createBrowserRelayHandler(opts) {
243
393
  if (aborted) return;
244
394
  try {
245
395
  handleParsed(JSON.parse(Buffer.concat(chunks).toString()), res);
246
- } catch {
396
+ } catch (e11) {
247
397
  respond(res, 400, { error: "invalid json" });
248
398
  }
249
399
  });
@@ -254,466 +404,162 @@ function createBrowserRelayHandler(opts) {
254
404
  }
255
405
 
256
406
  // src/server.ts
257
- var import_node_http = require("http");
258
- var import_node_crypto = require("crypto");
259
- var import_api2 = require("@opentelemetry/api");
260
- var import_core2 = require("@opentelemetry/core");
261
- var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
262
- var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
263
- var import_instrumentation_http = require("@opentelemetry/instrumentation-http");
264
- var import_resources = require("@opentelemetry/resources");
265
- var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
266
- var import_sdk_node = require("@opentelemetry/sdk-node");
267
- var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
268
- var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
269
-
270
- // src/lifecycle.ts
271
- var import_core = require("@opentelemetry/core");
272
- var debugEnabled = process.env.AUTTER_DEBUG === "1" || process.env.AUTTER_DEBUG === "true";
273
- function setDebugMode(enabled) {
274
- debugEnabled = enabled;
275
- }
276
- function isDebugEnabled() {
277
- return debugEnabled;
278
- }
279
- function debugLog(...args) {
280
- if (debugEnabled) {
281
- console.error("[autter]", ...args);
282
- }
283
- }
284
- var TelemetryStats = class {
285
- /** Captures queued via our APIs and not yet seen leaving an exporter. */
286
- pendingCaptures = 0;
287
- markCaptured(count = 1) {
288
- this.pendingCaptures += count;
289
- }
290
- /** An exporter batch left the process successfully. */
291
- onExported(spanCount) {
292
- this.pendingCaptures = Math.max(0, this.pendingCaptures - spanCount);
293
- if (debugEnabled && spanCount > 0) {
294
- debugLog(`exported ${spanCount} span${spanCount === 1 ? "" : "s"}`);
295
- }
296
- }
297
- markAllFlushed() {
298
- this.pendingCaptures = 0;
299
- }
300
- };
301
- var telemetryStats = new TelemetryStats();
302
- var CountingExporter = class {
303
- constructor(inner) {
407
+ var _http = require('http');
408
+ var _crypto = require('crypto');
409
+
410
+
411
+
412
+
413
+
414
+
415
+ var _api = require('@opentelemetry/api');
416
+ var _core = require('@opentelemetry/core');
417
+
418
+
419
+
420
+ var _exportermetricsotlphttp = require('@opentelemetry/exporter-metrics-otlp-http');
421
+ var _exportertraceotlphttp = require('@opentelemetry/exporter-trace-otlp-http');
422
+ var _instrumentationhttp = require('@opentelemetry/instrumentation-http');
423
+ var _resources = require('@opentelemetry/resources');
424
+ var _sdkmetrics = require('@opentelemetry/sdk-metrics');
425
+ var _sdknode = require('@opentelemetry/sdk-node');
426
+
427
+
428
+
429
+
430
+
431
+
432
+
433
+ var _sdktracebase = require('@opentelemetry/sdk-trace-base');
434
+
435
+
436
+
437
+ var _semanticconventions = require('@opentelemetry/semantic-conventions');
438
+
439
+ // src/redact-exporter.ts
440
+
441
+
442
+
443
+
444
+
445
+ var scrubbedResources = /* @__PURE__ */ new WeakMap();
446
+ function redactResource(resource, redactor) {
447
+ const cached = scrubbedResources.get(resource);
448
+ if (cached) return cached;
449
+ const scrubbed = new (0, _resources.Resource)(redactor.exported(resource.attributes));
450
+ scrubbedResources.set(resource, scrubbed);
451
+ return scrubbed;
452
+ }
453
+ function redactSpan(span, redactor) {
454
+ const status = span.status.message ? { ...span.status, message: redactor.text(span.status.message) } : span.status;
455
+ return {
456
+ name: redactor.text(span.name),
457
+ kind: span.kind,
458
+ spanContext: () => span.spanContext(),
459
+ parentSpanId: span.parentSpanId,
460
+ startTime: span.startTime,
461
+ endTime: span.endTime,
462
+ status,
463
+ attributes: redactor.exported(span.attributes),
464
+ links: span.links.map(
465
+ (link) => link.attributes ? { ...link, attributes: redactor.exported(link.attributes) } : link
466
+ ),
467
+ events: span.events.map((event) => ({
468
+ ...event,
469
+ name: redactor.text(event.name),
470
+ ...event.attributes ? { attributes: redactor.exported(event.attributes) } : {}
471
+ })),
472
+ duration: span.duration,
473
+ ended: span.ended,
474
+ resource: redactResource(span.resource, redactor),
475
+ instrumentationLibrary: span.instrumentationLibrary,
476
+ droppedAttributesCount: span.droppedAttributesCount,
477
+ droppedEventsCount: span.droppedEventsCount,
478
+ droppedLinksCount: span.droppedLinksCount
479
+ };
480
+ }
481
+ var RedactingSpanExporter = class {
482
+ constructor(inner, redactor) {
304
483
  this.inner = inner;
484
+ this.redactor = redactor;
305
485
  }
306
- inner;
486
+
487
+
307
488
  export(spans, resultCallback) {
308
- this.inner.export(spans, (result) => {
309
- if (result.code === import_core.ExportResultCode.SUCCESS) {
310
- telemetryStats.onExported(spans.length);
489
+ const redactor = this.redactor();
490
+ let scrubbed = spans;
491
+ let failed = 0;
492
+ if (redactor.enabled) {
493
+ scrubbed = [];
494
+ for (const span of spans) {
495
+ try {
496
+ scrubbed.push(redactSpan(span, redactor));
497
+ } catch (e12) {
498
+ failed++;
499
+ }
311
500
  }
312
- resultCallback(result);
313
- });
501
+ }
502
+ if (!failed) {
503
+ this.inner.export(scrubbed, resultCallback);
504
+ return;
505
+ }
506
+ const error = new Error(`autter-runtime: ${failed} span(s) could not be redacted and were not exported`);
507
+ const fail = () => resultCallback({ code: _core.ExportResultCode.FAILED, error });
508
+ if (!scrubbed.length) {
509
+ fail();
510
+ return;
511
+ }
512
+ this.inner.export(
513
+ scrubbed,
514
+ (result) => result.code === _core.ExportResultCode.SUCCESS ? fail() : resultCallback(result)
515
+ );
314
516
  }
315
517
  shutdown() {
316
518
  return this.inner.shutdown();
317
519
  }
318
520
  forceFlush() {
319
- return this.inner.forceFlush?.() ?? Promise.resolve();
521
+ return _nullishCoalesce(_optionalChain([this, 'access', _3 => _3.inner, 'access', _4 => _4.forceFlush, 'optionalCall', _5 => _5()]), () => ( Promise.resolve()));
320
522
  }
321
523
  };
322
- var flushTargets = /* @__PURE__ */ new Map();
323
- function registerFlushTarget(key, target) {
324
- flushTargets.set(key, target);
325
- }
326
- function unregisterFlushTargets() {
327
- flushTargets.clear();
328
- }
329
- function activeFlushTargets() {
330
- return [...flushTargets.values()];
331
- }
332
- var DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
333
- var SIGNAL_EXIT_CODES = {
334
- SIGINT: 130,
335
- SIGTERM: 143
336
- };
337
- function installAutterAutoFlush(options = {}) {
338
- const logger = options.logger ?? console;
339
- const log = options.log !== false;
340
- const warnOnUnflushedExit = options.warnOnUnflushedExit !== false;
341
- const timeoutMs = Math.max(100, options.timeoutMs ?? 3e3);
342
- const signals = options.signals ?? DEFAULT_SIGNALS;
343
- const flushOnUncaughtException = options.flushOnUncaughtException !== false;
344
- let disposed = false;
345
- let inFlight = null;
346
- const doFlush = async () => {
347
- const targets = options.targets ?? activeFlushTargets();
348
- if (targets.length === 0) return true;
349
- let timer;
350
- const timedOut = new Promise((resolve) => {
351
- timer = setTimeout(() => resolve(false), timeoutMs);
352
- });
353
- const drained = Promise.allSettled(
354
- targets.map(
355
- (target) => Promise.resolve().then(() => target.forceFlush())
356
- )
357
- ).then(
358
- (results) => results.every((result) => result.status === "fulfilled")
359
- );
360
- let ok;
361
- try {
362
- ok = await Promise.race([drained, timedOut]);
363
- } finally {
364
- clearTimeout(timer);
365
- }
366
- if (ok) {
367
- telemetryStats.markAllFlushed();
368
- if (log) {
369
- logger.log("[autter] telemetry flushed");
370
- }
371
- } else {
372
- logger.error(
373
- `[autter] flush did not finish within ${timeoutMs}ms \u2014 some telemetry may be lost`
374
- );
375
- }
376
- return ok;
377
- };
378
- const flush = (reason = "exit") => {
379
- if (disposed) return Promise.resolve(false);
380
- if (!inFlight) {
381
- inFlight = doFlush().finally(() => {
382
- inFlight = null;
383
- });
384
- }
385
- if (isDebugEnabled()) debugLog(`auto-flush requested on ${reason}`);
386
- return inFlight;
387
- };
388
- const signalCounts = /* @__PURE__ */ new Map();
389
- let handlingUncaughtException = false;
390
- const onUncaughtException = (error) => {
391
- if (process.listenerCount("uncaughtException") > 1) return;
392
- if (handlingUncaughtException) return;
393
- handlingUncaughtException = true;
394
- logger.error(error instanceof Error ? error.stack ?? error.message : String(error));
395
- const keepAlive = setTimeout(() => {
396
- }, timeoutMs + 50);
397
- void flush("uncaughtException").finally(() => {
398
- clearTimeout(keepAlive);
399
- process.exit(1);
400
- });
401
- };
402
- const onSignal = (signal) => {
403
- const count = (signalCounts.get(signal) ?? 0) + 1;
404
- signalCounts.set(signal, count);
405
- const exitCode = SIGNAL_EXIT_CODES[signal] ?? 1;
406
- if (count > 1) {
407
- process.exit(exitCode);
408
- }
409
- const otherHandlers = process.listenerCount(signal) - 1;
410
- if (otherHandlers > 0) {
411
- void flush(signal);
524
+ var RedactingMetricExporter = class {
525
+ constructor(inner, redactor) {
526
+ this.inner = inner;
527
+ this.redactor = redactor;
528
+ }
529
+
530
+
531
+ export(metrics2, resultCallback) {
532
+ const redactor = this.redactor();
533
+ if (!redactor.enabled) {
534
+ this.inner.export(metrics2, resultCallback);
412
535
  return;
413
536
  }
414
- void flush(signal).finally(() => {
415
- process.exit(exitCode);
416
- });
417
- };
418
- const MAX_BEFORE_EXIT_FLUSHES = 10;
419
- let beforeExitFlushes = 0;
420
- const onBeforeExit = () => {
421
- if (disposed) return;
422
- const targets = options.targets ?? activeFlushTargets();
423
- const worthIt = beforeExitFlushes === 0 ? targets.length > 0 : telemetryStats.pendingCaptures > 0;
424
- if (!worthIt || beforeExitFlushes >= MAX_BEFORE_EXIT_FLUSHES) return;
425
- beforeExitFlushes++;
426
- const keepAlive = setTimeout(() => {
427
- }, timeoutMs);
428
- void flush("beforeExit").finally(() => clearTimeout(keepAlive));
429
- };
430
- const onExit = () => {
431
- if (!warnOnUnflushedExit || disposed) return;
432
- const pending = telemetryStats.pendingCaptures;
433
- if (pending > 0) {
434
- logger.error(
435
- `[autter] process exiting with ~${pending} captured item(s) never confirmed exported \u2014 await autter.shutdown() on graceful shutdown`
436
- );
437
- }
438
- };
439
- const signalHandlers = /* @__PURE__ */ new Map();
440
- process.on("beforeExit", onBeforeExit);
441
- if (flushOnUncaughtException) {
442
- process.on("uncaughtException", onUncaughtException);
443
- }
444
- for (const signal of signals) {
445
- const handler = () => onSignal(signal);
446
- signalHandlers.set(signal, handler);
447
- process.on(signal, handler);
448
- }
449
- process.on("exit", onExit);
450
- return {
451
- flush,
452
- dispose() {
453
- disposed = true;
454
- process.removeListener("beforeExit", onBeforeExit);
455
- process.removeListener("uncaughtException", onUncaughtException);
456
- process.removeListener("exit", onExit);
457
- for (const [signal, handler] of signalHandlers) {
458
- process.removeListener(signal, handler);
459
- }
460
- signalHandlers.clear();
461
- }
462
- };
463
- }
464
-
465
- // src/redact.ts
466
- var SENSITIVE_KEY_PATTERNS = [
467
- /e-?mail/,
468
- /pass(word|wd|phrase)|^pass$/,
469
- /token/,
470
- /secret/,
471
- /credential/,
472
- /(api|access|secret|private|consumer|client|signing|encryption)-?[_.]?key/,
473
- /^-?x?-?authorization$|^auth(-|_|$)|bearer/,
474
- /cookie/,
475
- /phone|msisdn/,
476
- /\bssn\b|social[-_ ]?security/,
477
- /cvv|cvc|card([-_. ]?(number|num|no))?$/,
478
- /credit[-_.]?card/,
479
- /connection[-_.]?string/,
480
- /recovery[-_.]?code|\botp\b|magic[-_.]?link/
481
- ];
482
- var PRIVATE_KEY_BLOCK_RE = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g;
483
- var EMAIL_VALUE_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
484
- var JWT_RE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g;
485
- var OPENAI_KEY_RE = /\bsk-[A-Za-z0-9]{20,}\b/g;
486
- var GITHUB_TOKEN_RE = /\bgh[pousr]_[A-Za-z0-9]{20,}\b/g;
487
- var AWS_KEY_RE = /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g;
488
- var SLACK_TOKEN_RE = /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g;
489
- var BEARER_RE = /\bbearer\s+[A-Za-z0-9._~+/=-]{10,}/gi;
490
- var URL_CREDENTIALS_RE = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/:@]+:[^\s/@]+@/gi;
491
- function toCaseInsensitive(pattern) {
492
- return typeof pattern === "string" ? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i") : new RegExp(pattern.source, pattern.flags.includes("i") ? pattern.flags : `${pattern.flags}i`);
493
- }
494
- function compile(options) {
495
- const keyPatterns = [...SENSITIVE_KEY_PATTERNS];
496
- const valuePatterns = [
497
- JWT_RE,
498
- OPENAI_KEY_RE,
499
- GITHUB_TOKEN_RE,
500
- AWS_KEY_RE,
501
- SLACK_TOKEN_RE,
502
- BEARER_RE
503
- ];
504
- if (options?.additionalKeyPatterns) {
505
- for (const p of options.additionalKeyPatterns) {
506
- keyPatterns.push(toCaseInsensitive(p));
507
- }
508
- }
509
- if (options?.additionalValuePatterns) {
510
- for (const p of options.additionalValuePatterns) {
511
- if (!valuePatterns.some((existing) => existing.source === (typeof p === "string" ? p : p.source))) {
512
- valuePatterns.push(typeof p === "string" ? new RegExp(p, "gi") : p);
513
- }
514
- }
515
- }
516
- return {
517
- keyPatterns,
518
- valuePatterns,
519
- urlCredentials: URL_CREDENTIALS_RE,
520
- privateKeyBlock: PRIVATE_KEY_BLOCK_RE,
521
- mask: options?.mask ?? "[redacted]",
522
- scrubEmailValues: options?.scrubEmailValues !== false
523
- };
524
- }
525
- function redactString(value, r) {
526
- let out = value.replace(r.privateKeyBlock, r.mask);
527
- for (const re of r.valuePatterns) {
528
- out = out.replace(re, r.mask);
529
- }
530
- out = out.replace(r.urlCredentials, "$1" + r.mask + "@");
531
- if (r.scrubEmailValues) {
532
- out = out.replace(EMAIL_VALUE_RE, r.mask);
533
- }
534
- return out;
535
- }
536
- var MAX_REDACTION_DEPTH = 64;
537
- var MAX_REDACTION_WORK = 1e4;
538
- var MAX_COLLECTION_ENTRIES = 1e3;
539
- function canTraverse(depth, state) {
540
- if (depth > MAX_REDACTION_DEPTH || state.remainingWork <= 0) return false;
541
- state.remainingWork -= 1;
542
- return true;
543
- }
544
- function redactValue(value, r, state, depth) {
545
- if (typeof value === "string") return redactString(value, r);
546
- let isArray = false;
547
- try {
548
- isArray = Array.isArray(value);
549
- } catch {
550
- return r.mask;
551
- }
552
- if (isArray) {
553
- return redactArray(value, r, state, depth);
554
- }
555
- if (typeof value === "object" && value !== null) {
556
- return redactObject(value, r, state, depth);
557
- }
558
- return value;
559
- }
560
- function redactArray(value, r, state, depth) {
561
- const existing = state.ancestors.get(value);
562
- if (existing) return r.mask;
563
- if (!canTraverse(depth, state)) return r.mask;
564
- const out = [];
565
- state.ancestors.set(value, out);
566
- let length;
567
- try {
568
- length = value.length;
569
- } catch {
570
- state.ancestors.delete(value);
571
- return r.mask;
572
- }
573
- const limit = Math.min(length, MAX_COLLECTION_ENTRIES);
574
- for (let i = 0; i < limit; i += 1) {
575
- let item;
537
+ let resource;
576
538
  try {
577
- item = value[i];
578
- } catch {
579
- out.push(r.mask);
580
- continue;
581
- }
582
- out.push(redactValue(item, r, state, depth + 1));
583
- }
584
- if (length > limit) {
585
- out.push(r.mask);
586
- }
587
- state.ancestors.delete(value);
588
- return out;
589
- }
590
- function redactObject(value, r, state, depth) {
591
- const existing = state.ancestors.get(value);
592
- if (existing) return r.mask;
593
- if (!canTraverse(depth, state)) return r.mask;
594
- const out = {};
595
- state.ancestors.set(value, out);
596
- let count = 0;
597
- let truncated = false;
598
- try {
599
- for (const key in value) {
600
- if (!Object.prototype.propertyIsEnumerable.call(
601
- value,
602
- key
603
- )) {
604
- continue;
605
- }
606
- if (count >= MAX_COLLECTION_ENTRIES) {
607
- truncated = true;
608
- break;
609
- }
610
- let nestedValue;
611
- try {
612
- nestedValue = value[key];
613
- } catch {
614
- out[key] = r.mask;
615
- count += 1;
616
- continue;
617
- }
618
- count += 1;
619
- out[key] = isSensitiveKey(key, nestedValue, r) ? r.mask : redactValue(
620
- nestedValue,
621
- r,
622
- state,
623
- depth + 1
624
- );
625
- }
626
- } catch {
627
- truncated = true;
628
- }
629
- if (truncated) {
630
- out.__redaction_truncated__ = r.mask;
631
- }
632
- state.ancestors.delete(value);
633
- return out;
634
- }
635
- var USAGE_TOKEN_KEYS = /* @__PURE__ */ new Set([
636
- "input_tokens",
637
- "output_tokens",
638
- "prompt_tokens",
639
- "completion_tokens",
640
- "total_tokens",
641
- "token_count",
642
- "gen_ai.usage.input_tokens",
643
- "gen_ai.usage.output_tokens",
644
- "gen_ai.usage.prompt_tokens",
645
- "gen_ai.usage.completion_tokens",
646
- "gen_ai.usage.total_tokens",
647
- "gen_ai.usage.token_count"
648
- ]);
649
- function isSensitiveKey(key, value, r) {
650
- const lowered = key.toLowerCase();
651
- if (USAGE_TOKEN_KEYS.has(lowered)) {
652
- return !(typeof value === "number" && Number.isFinite(value) && value >= 0);
653
- }
654
- return r.keyPatterns.some((re) => re.test(lowered));
655
- }
656
- function redactAttributes(attributes, options) {
657
- const r = compile(options);
658
- return redactWith(attributes, r);
659
- }
660
- function redactWith(attributes, r) {
661
- const out = {};
662
- if (!attributes) return out;
663
- const state = {
664
- ancestors: /* @__PURE__ */ new WeakMap(),
665
- remainingWork: MAX_REDACTION_WORK
666
- };
667
- let count = 0;
668
- let truncated = false;
669
- try {
670
- for (const key in attributes) {
671
- if (!Object.prototype.propertyIsEnumerable.call(
672
- attributes,
673
- key
674
- )) {
675
- continue;
676
- }
677
- if (count >= MAX_COLLECTION_ENTRIES || state.remainingWork <= 0) {
678
- truncated = true;
679
- break;
680
- }
681
- let value;
682
- try {
683
- value = attributes[key];
684
- } catch {
685
- out[key] = r.mask;
686
- count += 1;
687
- state.remainingWork -= 1;
688
- continue;
689
- }
690
- count += 1;
691
- state.remainingWork -= 1;
692
- if (value === void 0) continue;
693
- out[key] = isSensitiveKey(key, value, r) ? r.mask : redactValue(value, r, state, 0);
539
+ resource = redactResource(metrics2.resource, redactor);
540
+ } catch (error) {
541
+ resultCallback({ code: _core.ExportResultCode.FAILED, error });
542
+ return;
694
543
  }
695
- } catch {
696
- truncated = true;
544
+ this.inner.export({ ...metrics2, resource }, resultCallback);
697
545
  }
698
- if (truncated) {
699
- out.__redaction_truncated__ = r.mask;
546
+ forceFlush() {
547
+ return this.inner.forceFlush();
700
548
  }
701
- return out;
702
- }
703
- function makeRedactor(options) {
704
- if (options === false) {
705
- return (attributes) => ({ ...attributes ?? {} });
549
+ shutdown() {
550
+ return this.inner.shutdown();
706
551
  }
707
- const r = compile(options === true ? void 0 : options);
708
- return (attributes) => redactWith(attributes, r);
709
- }
552
+ selectAggregationTemporality(instrumentType) {
553
+ return this.inner.selectAggregationTemporality ? this.inner.selectAggregationTemporality(instrumentType) : _sdkmetrics.AggregationTemporality.CUMULATIVE;
554
+ }
555
+ };
710
556
 
711
557
  // src/memory.ts
712
- var import_node_perf_hooks = require("perf_hooks");
713
- var import_node_v8 = require("v8");
714
- var import_api = require("@opentelemetry/api");
558
+ var _perf_hooks = require('perf_hooks');
559
+ var _v8 = require('v8');
560
+
715
561
  function startMemoryMetrics() {
716
- const meter = import_api.metrics.getMeter("autter-process-memory");
562
+ const meter = _api.metrics.getMeter("autter-process-memory");
717
563
  const rss = meter.createObservableGauge("autter.process.memory.rss", { unit: "By" });
718
564
  const heapUsed = meter.createObservableGauge("autter.process.memory.heap.used", { unit: "By" });
719
565
  const heapLimit = meter.createObservableGauge("autter.process.memory.heap.limit", { unit: "By" });
@@ -727,9 +573,9 @@ function startMemoryMetrics() {
727
573
  const callbacks = [
728
574
  [rss, (result) => result.observe(process.memoryUsage().rss)],
729
575
  [heapUsed, (result) => result.observe(process.memoryUsage().heapUsed)],
730
- [heapLimit, (result) => result.observe((0, import_node_v8.getHeapStatistics)().heap_size_limit)],
576
+ [heapLimit, (result) => result.observe(_v8.getHeapStatistics.call(void 0, ).heap_size_limit)],
731
577
  [containerLimit, (result) => {
732
- const constrained = process.constrainedMemory?.() ?? 0;
578
+ const constrained = _nullishCoalesce(_optionalChain([process, 'access', _6 => _6.constrainedMemory, 'optionalCall', _7 => _7()]), () => ( 0));
733
579
  if (constrained > 0) result.observe(constrained);
734
580
  }],
735
581
  [afterGc, (result) => {
@@ -739,7 +585,7 @@ function startMemoryMetrics() {
739
585
  [gcDuration, (result) => result.observe(durationMs)]
740
586
  ];
741
587
  for (const [instrument, callback] of callbacks) instrument.addCallback(callback);
742
- const observer = new import_node_perf_hooks.PerformanceObserver((list) => {
588
+ const observer = new (0, _perf_hooks.PerformanceObserver)((list) => {
743
589
  for (const entry of list.getEntries()) {
744
590
  collections++;
745
591
  durationMs += entry.duration;
@@ -753,6 +599,383 @@ function startMemoryMetrics() {
753
599
  };
754
600
  }
755
601
 
602
+ // src/requests.ts
603
+ var _async_hooks = require('async_hooks');
604
+
605
+ var REQUEST_STATE = /* @__PURE__ */ Symbol.for("autter.runtime.request");
606
+ var BOUND = /* @__PURE__ */ Symbol.for("autter.runtime.bound");
607
+ var CAPTURED = /* @__PURE__ */ new WeakSet();
608
+ var capturer = () => {
609
+ };
610
+ function setRequestExceptionCapturer(fn) {
611
+ capturer = fn;
612
+ }
613
+ function markCaptured(error) {
614
+ if (error && typeof error === "object") CAPTURED.add(error);
615
+ }
616
+ function expressRouteOf(req) {
617
+ const props = req;
618
+ const path = _optionalChain([props, 'optionalAccess', _8 => _8.route, 'optionalAccess', _9 => _9.path]);
619
+ if (typeof path !== "string" || path === "") return null;
620
+ const base = typeof _optionalChain([props, 'optionalAccess', _10 => _10.baseUrl]) === "string" ? props.baseUrl : "";
621
+ const route = base + path;
622
+ return route.startsWith("/") ? route : null;
623
+ }
624
+ function defaultShouldCapture(error) {
625
+ return error instanceof _chunkP4VRTFAVcjs.RuntimeError || _chunkP4VRTFAVcjs.errorCodeOf.call(void 0, error) !== void 0 || _chunkP4VRTFAVcjs.responseStatusOf.call(void 0, error) >= 500;
626
+ }
627
+ function captureAtBoundary(error, state, rule = void 0) {
628
+ const wanted = typeof rule === "function" ? rule(error) : rule === void 0 ? defaultShouldCapture(error) : rule;
629
+ if (!wanted) return;
630
+ if (error && typeof error === "object" && CAPTURED.has(error)) return;
631
+ markCaptured(error);
632
+ try {
633
+ if (state && !state.sealed) _chunkP4VRTFAVcjs.local.run(state, () => capturer(error));
634
+ else capturer(error);
635
+ } catch (e13) {
636
+ }
637
+ }
638
+ function bindEmitter(emitter, state) {
639
+ const target = emitter;
640
+ if (!target || typeof target !== "object" || target[BOUND]) return;
641
+ target[BOUND] = true;
642
+ const wrappers = /* @__PURE__ */ new WeakMap();
643
+ const wrap = (listener) => {
644
+ if (typeof listener !== "function") return listener;
645
+ let wrapped = wrappers.get(listener);
646
+ if (!wrapped) {
647
+ wrapped = function(...args) {
648
+ return _chunkP4VRTFAVcjs.local.run(
649
+ state,
650
+ () => listener.apply(this, args)
651
+ );
652
+ };
653
+ wrappers.set(listener, wrapped);
654
+ }
655
+ return wrapped;
656
+ };
657
+ for (const method of [
658
+ "on",
659
+ "addListener",
660
+ "prependListener",
661
+ "once",
662
+ "prependOnceListener"
663
+ ]) {
664
+ const original = target[method];
665
+ if (typeof original !== "function") continue;
666
+ target[method] = function(event, listener) {
667
+ return original.call(this, event, wrap(listener));
668
+ };
669
+ }
670
+ for (const method of ["removeListener", "off"]) {
671
+ const original = target[method];
672
+ if (typeof original !== "function") continue;
673
+ target[method] = function(event, listener) {
674
+ const wrapped = typeof listener === "function" ? _nullishCoalesce(wrappers.get(listener), () => ( listener)) : listener;
675
+ return original.call(this, event, wrapped);
676
+ };
677
+ }
678
+ }
679
+ function exposeHeaderValue(current, header) {
680
+ const text = Array.isArray(current) ? current.join(", ") : String(_nullishCoalesce(current, () => ( "")));
681
+ const names = text.split(",").map((item) => item.trim().toLowerCase()).filter(Boolean);
682
+ if (names.includes("*") || names.includes(header)) return null;
683
+ return names.length ? `${text}, ${header}` : header;
684
+ }
685
+ function exposeOnCors(res, header) {
686
+ const original = res.writeHead;
687
+ res.writeHead = function(...args) {
688
+ try {
689
+ const inline = args.slice(1).find(
690
+ (arg) => !!arg && typeof arg === "object" && !Array.isArray(arg)
691
+ );
692
+ const inlineKey = (name) => inline ? Object.keys(inline).find((key) => key.toLowerCase() === name) : void 0;
693
+ const cors = res.getHeader("access-control-allow-origin") !== void 0 || inlineKey("access-control-allow-origin") !== void 0;
694
+ if (cors) {
695
+ const key = inlineKey("access-control-expose-headers");
696
+ const value = exposeHeaderValue(
697
+ key && inline ? inline[key] : res.getHeader("access-control-expose-headers"),
698
+ header
699
+ );
700
+ if (value && key && inline) inline[key] = value;
701
+ else if (value) res.setHeader("access-control-expose-headers", value);
702
+ }
703
+ } catch (e14) {
704
+ }
705
+ return original.apply(this, args);
706
+ };
707
+ }
708
+ function pathOf(req) {
709
+ const raw = _nullishCoalesce(_nullishCoalesce(req.originalUrl, () => ( req.url)), () => ( "/"));
710
+ return raw.split(/[?#]/)[0] || "/";
711
+ }
712
+ function finishRequest(state, input) {
713
+ if (state.sealed) return;
714
+ state.name = (_nullishCoalesce(input.name, () => ( `${input.method} ${input.route}`))).slice(0, 200);
715
+ state.outcome = _chunkP4VRTFAVcjs.requestOutcome.call(void 0, {
716
+ ...state.explicitOutcome ? { explicit: state.outcome } : {},
717
+ ...state.error !== void 0 ? { error: state.error } : {},
718
+ ...state.errorThrown ? { thrown: true } : {},
719
+ status: input.status,
720
+ aborted: input.aborted
721
+ });
722
+ const span = _api.trace.getActiveSpan();
723
+ if (_optionalChain([span, 'optionalAccess', _11 => _11.isRecording, 'call', _12 => _12()])) span.setAttribute("autter.operation.outcome", state.outcome);
724
+ if (input.span) {
725
+ const remote = _api.trace.wrapSpanContext(input.span);
726
+ _api.context.with(
727
+ _api.trace.setSpan(_api.context.active(), remote),
728
+ () => _chunkP4VRTFAVcjs.reportExplicitFailure.call(void 0, state)
729
+ );
730
+ } else _chunkP4VRTFAVcjs.reportExplicitFailure.call(void 0, state);
731
+ _chunkP4VRTFAVcjs.emitSummary.call(void 0, state, {
732
+ http: {
733
+ "http.request.method": input.method,
734
+ "http.route": input.route,
735
+ "http.response.status_code": input.status,
736
+ "autter.request.aborted": input.aborted
737
+ },
738
+ ...input.span ? { span: input.span } : {}
739
+ });
740
+ }
741
+ function beginNodeRequest(req, res, options, route) {
742
+ const header = (_nullishCoalesce(options.requestIdHeader, () => ( _chunkP4VRTFAVcjs.DEFAULT_REQUEST_ID_HEADER))).toLowerCase();
743
+ const requestId = _chunkP4VRTFAVcjs.resolveRequestId.call(void 0,
744
+ options.trustRequestId === false ? void 0 : req.headers[header]
745
+ );
746
+ const method = (_nullishCoalesce(req.method, () => ( "GET"))).toUpperCase();
747
+ const path = pathOf(req);
748
+ const state = _chunkP4VRTFAVcjs.createRequestState.call(void 0, {
749
+ name: `${method} ${_chunkP4VRTFAVcjs.normalizeRoutePath.call(void 0, path)}`,
750
+ requestId,
751
+ req,
752
+ res
753
+ });
754
+ req[REQUEST_STATE] = state;
755
+ try {
756
+ if (!res.headersSent) res.setHeader(header, requestId);
757
+ exposeOnCors(res, header);
758
+ } catch (e15) {
759
+ }
760
+ const span = _api.trace.getActiveSpan();
761
+ if (_optionalChain([span, 'optionalAccess', _13 => _13.isRecording, 'call', _14 => _14()]))
762
+ span.setAttributes({
763
+ "autter.request.id": requestId,
764
+ "autter.operation.kind": "request"
765
+ });
766
+ const spanContext = _optionalChain([span, 'optionalAccess', _15 => _15.spanContext, 'call', _16 => _16()]);
767
+ bindEmitter(req, state);
768
+ bindEmitter(res, state);
769
+ let finished = false;
770
+ const done = () => {
771
+ finishRequest(state, {
772
+ method,
773
+ route: _nullishCoalesce(_nullishCoalesce(_optionalChain([route, 'optionalCall', _17 => _17()]), () => ( expressRouteOf(req))), () => ( _chunkP4VRTFAVcjs.normalizeRoutePath.call(void 0, path))),
774
+ status: res.statusCode,
775
+ aborted: !finished,
776
+ ...spanContext ? { span: spanContext } : {}
777
+ });
778
+ };
779
+ res.once("finish", () => {
780
+ finished = true;
781
+ done();
782
+ });
783
+ res.once("close", done);
784
+ return state;
785
+ }
786
+ function autterRequests(options = {}) {
787
+ const ignored = _chunkP4VRTFAVcjs.compileIgnore.call(void 0, options.ignore);
788
+ return function autterRequestsMiddleware(req, res, next) {
789
+ if (req[REQUEST_STATE] || ignored(pathOf(req))) {
790
+ next();
791
+ return;
792
+ }
793
+ const state = beginNodeRequest(req, res, options);
794
+ _chunkP4VRTFAVcjs.local.run(state, () => next());
795
+ };
796
+ }
797
+ function autterErrorResponse(options = {}) {
798
+ return function autterErrorResponseMiddleware(error, req, res, next) {
799
+ const state = req[REQUEST_STATE];
800
+ if (state) _chunkP4VRTFAVcjs.noteOperationError.call(void 0, error, true, state);
801
+ captureAtBoundary(error, state, options.capture);
802
+ if (res.headersSent) {
803
+ next(error);
804
+ return;
805
+ }
806
+ const header = (_nullishCoalesce(options.requestIdHeader, () => ( _chunkP4VRTFAVcjs.DEFAULT_REQUEST_ID_HEADER))).toLowerCase();
807
+ const inbound = _optionalChain([req, 'access', _18 => _18.headers, 'optionalAccess', _19 => _19[header]]);
808
+ const requestId = _nullishCoalesce(_optionalChain([state, 'optionalAccess', _20 => _20.requestId]), () => ( (typeof inbound === "string" ? inbound.slice(0, 128) : void 0)));
809
+ res.statusCode = _chunkP4VRTFAVcjs.responseStatusOf.call(void 0, error);
810
+ res.setHeader("content-type", "application/json; charset=utf-8");
811
+ res.end(JSON.stringify(_chunkP4VRTFAVcjs.toClientError.call(void 0, error, requestId)));
812
+ };
813
+ }
814
+ var RESOURCE = /* @__PURE__ */ Symbol.for("autter.runtime.resource");
815
+ function autterFastify(fastify, options, done) {
816
+ const opts = _nullishCoalesce(options, () => ( {}));
817
+ const header = (_nullishCoalesce(opts.requestIdHeader, () => ( _chunkP4VRTFAVcjs.DEFAULT_REQUEST_ID_HEADER))).toLowerCase();
818
+ const ignored = _chunkP4VRTFAVcjs.compileIgnore.call(void 0, opts.ignore);
819
+ const stateOf = (request) => request[REQUEST_STATE];
820
+ fastify.addHook("onRequest", ((request, reply, next) => {
821
+ if (ignored(request.url) || request.raw[REQUEST_STATE]) {
822
+ next();
823
+ return;
824
+ }
825
+ const requestId = _chunkP4VRTFAVcjs.resolveRequestId.call(void 0,
826
+ opts.trustRequestId === false ? void 0 : request.headers[header]
827
+ );
828
+ const method = String(_nullishCoalesce(request.method, () => ( "GET"))).toUpperCase();
829
+ const state = _chunkP4VRTFAVcjs.createRequestState.call(void 0, {
830
+ name: `${method} ${_chunkP4VRTFAVcjs.normalizeRoutePath.call(void 0, request.url)}`,
831
+ requestId,
832
+ req: request.raw,
833
+ res: reply.raw
834
+ });
835
+ request[REQUEST_STATE] = state;
836
+ request.raw[REQUEST_STATE] = state;
837
+ reply.header(header, requestId);
838
+ const span = _api.trace.getActiveSpan();
839
+ if (_optionalChain([span, 'optionalAccess', _21 => _21.isRecording, 'call', _22 => _22()]))
840
+ span.setAttributes({
841
+ "autter.request.id": requestId,
842
+ "autter.operation.kind": "request"
843
+ });
844
+ const spanContext = _optionalChain([span, 'optionalAccess', _23 => _23.spanContext, 'call', _24 => _24()]);
845
+ bindEmitter(request.raw, state);
846
+ bindEmitter(reply.raw, state);
847
+ let finished = false;
848
+ const finish = (aborted) => finishRequest(state, {
849
+ method,
850
+ route: _nullishCoalesce(_nullishCoalesce(_optionalChain([request, 'access', _25 => _25.routeOptions, 'optionalAccess', _26 => _26.url]), () => ( request.routerPath)), () => ( _chunkP4VRTFAVcjs.normalizeRoutePath.call(void 0, request.url))),
851
+ status: reply.raw.statusCode || reply.statusCode,
852
+ aborted,
853
+ ...spanContext ? { span: spanContext } : {}
854
+ });
855
+ reply.raw.once("finish", () => {
856
+ finished = true;
857
+ finish(false);
858
+ });
859
+ reply.raw.once("close", () => finish(!finished));
860
+ _chunkP4VRTFAVcjs.local.run(state, () => {
861
+ request[RESOURCE] = new (0, _async_hooks.AsyncResource)("autter-request");
862
+ next();
863
+ });
864
+ }));
865
+ fastify.addHook("preHandler", ((request, _reply, next) => {
866
+ const resource = request[RESOURCE];
867
+ if (resource) resource.runInAsyncScope(() => next());
868
+ else next();
869
+ }));
870
+ fastify.addHook("onSend", ((request, reply, payload, next) => {
871
+ try {
872
+ if (stateOf(request) && reply.getHeader("access-control-allow-origin") !== void 0) {
873
+ const value = exposeHeaderValue(reply.getHeader("access-control-expose-headers"), header);
874
+ if (value) reply.header("access-control-expose-headers", value);
875
+ }
876
+ } catch (e16) {
877
+ }
878
+ next(null, payload);
879
+ }));
880
+ fastify.addHook("onError", ((request, _reply, error, next) => {
881
+ const state = stateOf(request);
882
+ if (state) _chunkP4VRTFAVcjs.noteOperationError.call(void 0, error, true, state);
883
+ captureAtBoundary(error, state);
884
+ next();
885
+ }));
886
+ done();
887
+ }
888
+ autterFastify[/* @__PURE__ */ Symbol.for("skip-override")] = true;
889
+ autterFastify[/* @__PURE__ */ Symbol.for("fastify.display-name")] = "autter-runtime";
890
+ function withHeaders(response, header, requestId) {
891
+ const apply = (target) => {
892
+ target.headers.set(header, requestId);
893
+ if (target.headers.get("access-control-allow-origin") !== null) {
894
+ const value = exposeHeaderValue(
895
+ _nullishCoalesce(target.headers.get("access-control-expose-headers"), () => ( "")),
896
+ header
897
+ );
898
+ if (value) target.headers.set("access-control-expose-headers", value);
899
+ }
900
+ return target;
901
+ };
902
+ try {
903
+ return apply(response);
904
+ } catch (e17) {
905
+ try {
906
+ return apply(new Response(response.body, response));
907
+ } catch (e18) {
908
+ return response;
909
+ }
910
+ }
911
+ }
912
+ function withRuntimeRequest(handler, options = {}) {
913
+ const header = (_nullishCoalesce(options.requestIdHeader, () => ( _chunkP4VRTFAVcjs.DEFAULT_REQUEST_ID_HEADER))).toLowerCase();
914
+ const ignored = _chunkP4VRTFAVcjs.compileIgnore.call(void 0, options.ignore);
915
+ return async (request, ...rest) => {
916
+ let pathname = "/";
917
+ try {
918
+ pathname = new URL(request.url, "http://localhost").pathname;
919
+ } catch (e19) {
920
+ }
921
+ if (ignored(pathname)) return handler(request, ...rest);
922
+ const requestId = _chunkP4VRTFAVcjs.resolveRequestId.call(void 0,
923
+ options.trustRequestId === false ? void 0 : request.headers.get(header)
924
+ );
925
+ const method = String(_nullishCoalesce(request.method, () => ( "GET"))).toUpperCase();
926
+ const route = _nullishCoalesce(options.route, () => ( _chunkP4VRTFAVcjs.normalizeRoutePath.call(void 0, pathname)));
927
+ const state = _chunkP4VRTFAVcjs.createRequestState.call(void 0, {
928
+ name: `${method} ${_nullishCoalesce(options.name, () => ( route))}`,
929
+ requestId,
930
+ req: request
931
+ });
932
+ const span = _api.trace.getActiveSpan();
933
+ if (_optionalChain([span, 'optionalAccess', _27 => _27.isRecording, 'call', _28 => _28()]))
934
+ span.setAttributes({
935
+ "autter.request.id": requestId,
936
+ "autter.operation.kind": "request"
937
+ });
938
+ const spanContext = _optionalChain([span, 'optionalAccess', _29 => _29.spanContext, 'call', _30 => _30()]);
939
+ let status = 500;
940
+ try {
941
+ const response = await _chunkP4VRTFAVcjs.local.run(state, async () => {
942
+ try {
943
+ return await handler(request, ...rest);
944
+ } catch (error) {
945
+ _chunkP4VRTFAVcjs.noteOperationError.call(void 0, error, true, state);
946
+ captureAtBoundary(error, state, true);
947
+ throw error;
948
+ }
949
+ });
950
+ status = response.status;
951
+ return withHeaders(response, header, requestId);
952
+ } finally {
953
+ const aborted = _optionalChain([request, 'access', _31 => _31.signal, 'optionalAccess', _32 => _32.aborted]) === true;
954
+ finishRequest(state, {
955
+ method,
956
+ route,
957
+ name: `${method} ${_nullishCoalesce(options.name, () => ( route))}`,
958
+ status,
959
+ aborted,
960
+ ...spanContext ? { span: spanContext } : {}
961
+ });
962
+ if (options.waitUntil) {
963
+ try {
964
+ options.waitUntil(_chunkP4VRTFAVcjs.flushRuntimeLogs.call(void 0, ).catch(() => {
965
+ }));
966
+ } catch (e20) {
967
+ }
968
+ }
969
+ }
970
+ };
971
+ }
972
+ function startHookRequest(res) {
973
+ const req = res.req;
974
+ if (!req || req[REQUEST_STATE]) return;
975
+ const state = beginNodeRequest(req, res, {});
976
+ _chunkP4VRTFAVcjs.local.enterWith(state);
977
+ }
978
+
756
979
  // src/server.ts
757
980
  var LLM_MARKER_ATTRIBUTES = [
758
981
  "gen_ai.operation.name",
@@ -769,10 +992,10 @@ var LlmAwareSampler = class {
769
992
  constructor(delegate) {
770
993
  this.delegate = delegate;
771
994
  }
772
- delegate;
995
+
773
996
  shouldSample(ctx, traceId, spanName, spanKind, attributes, links) {
774
997
  if (isLlmSpan(spanName, attributes)) {
775
- return { decision: import_sdk_trace_base.SamplingDecision.RECORD_AND_SAMPLED };
998
+ return { decision: _sdktracebase.SamplingDecision.RECORD_AND_SAMPLED };
776
999
  }
777
1000
  return this.delegate.shouldSample(
778
1001
  ctx,
@@ -791,7 +1014,7 @@ var RecordUnsampledSampler = class {
791
1014
  constructor(delegate) {
792
1015
  this.delegate = delegate;
793
1016
  }
794
- delegate;
1017
+
795
1018
  shouldSample(ctx, traceId, spanName, spanKind, attributes, links) {
796
1019
  const result = this.delegate.shouldSample(
797
1020
  ctx,
@@ -801,8 +1024,8 @@ var RecordUnsampledSampler = class {
801
1024
  attributes,
802
1025
  links
803
1026
  );
804
- if (result.decision === import_sdk_trace_base.SamplingDecision.NOT_RECORD) {
805
- return { ...result, decision: import_sdk_trace_base.SamplingDecision.RECORD };
1027
+ if (result.decision === _sdktracebase.SamplingDecision.NOT_RECORD) {
1028
+ return { ...result, decision: _sdktracebase.SamplingDecision.RECORD };
806
1029
  }
807
1030
  return result;
808
1031
  }
@@ -815,14 +1038,14 @@ var RETENTION_MAX_BUFFERED_SPANS = 5e3;
815
1038
  var RETENTION_SWEEP_INTERVAL_MS = 1e4;
816
1039
  var RETENTION_TRACE_TTL_MS = 3e4;
817
1040
  function spanIndicatesError(span) {
818
- if (span.status.code === import_api2.SpanStatusCode.ERROR) return true;
1041
+ if (span.status.code === _api.SpanStatusCode.ERROR) return true;
819
1042
  return span.events.some((event) => event.name === "exception");
820
1043
  }
821
1044
  var TAIL_RETAINED_ATTR = "autter.tail_retained";
822
1045
  function withSampledFlag(span) {
823
1046
  const spanContext = {
824
1047
  ...span.spanContext(),
825
- traceFlags: span.spanContext().traceFlags | import_api2.TraceFlags.SAMPLED
1048
+ traceFlags: span.spanContext().traceFlags | _api.TraceFlags.SAMPLED
826
1049
  };
827
1050
  return {
828
1051
  name: span.name,
@@ -844,29 +1067,29 @@ function withSampledFlag(span) {
844
1067
  droppedLinksCount: span.droppedLinksCount
845
1068
  };
846
1069
  }
847
- var ErrorTraceRetentionProcessor = class {
848
- constructor(inner, retainErrors = true, slowThresholdMs = 0) {
1070
+ var ErrorTraceRetentionProcessor = (_class2 = class {
1071
+ constructor(inner, retainErrors = true, slowThresholdMs = 0) {;_class2.prototype.__init2.call(this);_class2.prototype.__init3.call(this);
849
1072
  this.inner = inner;
850
1073
  this.retainErrors = retainErrors;
851
1074
  this.slowThresholdMs = slowThresholdMs;
852
1075
  this.sweeper = setInterval(() => this.sweep(), RETENTION_SWEEP_INTERVAL_MS);
853
- this.sweeper.unref?.();
854
- }
855
- inner;
856
- retainErrors;
857
- slowThresholdMs;
858
- traces = /* @__PURE__ */ new Map();
859
- bufferedSpans = 0;
860
- sweeper;
1076
+ _optionalChain([this, 'access', _33 => _33.sweeper, 'access', _34 => _34.unref, 'optionalCall', _35 => _35()]);
1077
+ }
1078
+
1079
+
1080
+
1081
+ __init2() {this.traces = /* @__PURE__ */ new Map()}
1082
+ __init3() {this.bufferedSpans = 0}
1083
+
861
1084
  onStart(_span, _parentContext) {
862
1085
  }
863
1086
  onEnd(span) {
864
1087
  const ctx = span.spanContext();
865
- if ((ctx.traceFlags & import_api2.TraceFlags.SAMPLED) !== 0) return;
1088
+ if ((ctx.traceFlags & _api.TraceFlags.SAMPLED) !== 0) return;
866
1089
  const entry = this.entryFor(ctx.traceId);
867
1090
  if (entry.retained) {
868
1091
  this.forward(span);
869
- } else if (this.retainErrors && spanIndicatesError(span) || this.slowThresholdMs > 0 && span.kind === import_api2.SpanKind.SERVER && span.duration[0] * 1e3 + span.duration[1] / 1e6 >= this.slowThresholdMs) {
1092
+ } else if (this.retainErrors && spanIndicatesError(span) || this.slowThresholdMs > 0 && span.kind === _api.SpanKind.SERVER && span.duration[0] * 1e3 + span.duration[1] / 1e6 >= this.slowThresholdMs) {
870
1093
  entry.retained = true;
871
1094
  this.flush(entry);
872
1095
  this.forward(span);
@@ -881,8 +1104,8 @@ var ErrorTraceRetentionProcessor = class {
881
1104
  }
882
1105
  /** Promote the active trace, if any — called on captured errors. */
883
1106
  retainActiveTrace() {
884
- const active2 = import_api2.trace.getActiveSpan()?.spanContext();
885
- if (!active2 || (active2.traceFlags & import_api2.TraceFlags.SAMPLED) !== 0) return;
1107
+ const active2 = _optionalChain([_api.trace, 'access', _36 => _36.getActiveSpan, 'call', _37 => _37(), 'optionalAccess', _38 => _38.spanContext, 'call', _39 => _39()]);
1108
+ if (!active2 || (active2.traceFlags & _api.TraceFlags.SAMPLED) !== 0) return;
886
1109
  const entry = this.entryFor(active2.traceId);
887
1110
  if (entry.retained) return;
888
1111
  entry.retained = true;
@@ -937,10 +1160,10 @@ var ErrorTraceRetentionProcessor = class {
937
1160
  if (entry.firstSeenAtMs <= cutoff) this.drop(traceId);
938
1161
  }
939
1162
  }
940
- };
1163
+ }, _class2);
941
1164
  function llmBaseAttributes(info) {
942
1165
  return {
943
- "gen_ai.operation.name": info.operation ?? "chat",
1166
+ "gen_ai.operation.name": _nullishCoalesce(info.operation, () => ( "chat")),
944
1167
  // Both keys: gen_ai.system is the pre-1.37 semconv name and what
945
1168
  // most tooling still matches on.
946
1169
  "gen_ai.provider.name": info.provider,
@@ -970,97 +1193,106 @@ function usageAttributes(usage) {
970
1193
  return attrs;
971
1194
  }
972
1195
  async function runLlmSpan(tracer, info, fn) {
973
- const span = tracer.startSpan(`${info.operation ?? "chat"} ${info.model}`, {
974
- kind: import_api2.SpanKind.CLIENT,
1196
+ const span = tracer.startSpan(`${_nullishCoalesce(info.operation, () => ( "chat"))} ${info.model}`, {
1197
+ kind: _api.SpanKind.CLIENT,
975
1198
  attributes: llmBaseAttributes(info)
976
1199
  });
977
- const setResponseModel = (model) => span.setAttribute("gen_ai.response.model", model);
1200
+ const usage = {};
1201
+ let responseModel;
1202
+ const setResponseModel = (model) => {
1203
+ responseModel = model;
1204
+ span.setAttribute("gen_ai.response.model", model);
1205
+ };
978
1206
  const handle = {
979
- setUsage: (usage) => span.setAttributes(usageAttributes(usage)),
980
- setCost: (usd) => span.setAttribute("autter.llm.cost_usd", usd),
1207
+ setUsage: (next) => {
1208
+ Object.assign(usage, next);
1209
+ span.setAttributes(usageAttributes(next));
1210
+ },
1211
+ setCost: (usd) => {
1212
+ usage.costUsd = usd;
1213
+ span.setAttribute("autter.llm.cost_usd", usd);
1214
+ },
981
1215
  setResponseModel,
982
1216
  setModel: setResponseModel,
983
- setAttributes: (attributes) => span.setAttributes(attributes)
1217
+ setAttributes: (attributes) => span.setAttributes(activeRedactor(attributes))
984
1218
  };
985
1219
  try {
986
- const result = await import_api2.context.with(
987
- import_api2.trace.setSpan(import_api2.context.active(), span),
1220
+ const result = await _api.context.with(
1221
+ _api.trace.setSpan(_api.context.active(), span),
988
1222
  () => fn(handle)
989
1223
  );
990
- span.setStatus({ code: import_api2.SpanStatusCode.OK });
1224
+ span.setStatus({ code: _api.SpanStatusCode.OK });
991
1225
  return result;
992
1226
  } catch (err) {
993
- if (err instanceof Error) {
994
- span.recordException(err);
995
- span.setAttribute("error.type", err.name);
996
- }
997
- span.setStatus({
998
- code: import_api2.SpanStatusCode.ERROR,
999
- message: err instanceof Error ? err.message : String(err)
1000
- });
1227
+ recordError(span, err);
1228
+ if (err instanceof Error) span.setAttribute("error.type", err.name);
1001
1229
  throw err;
1002
1230
  } finally {
1003
1231
  span.end();
1232
+ _chunkP4VRTFAVcjs.recordOperationAiUsage.call(void 0, { ...usage, model: _nullishCoalesce(responseModel, () => ( info.model)) });
1004
1233
  }
1005
1234
  }
1006
1235
  function recordLlmCall(tracer, call) {
1007
- const durationMs = Math.max(0, call.durationMs ?? 0);
1236
+ _chunkP4VRTFAVcjs.recordOperationAiUsage.call(void 0, { ...call, model: call.model });
1237
+ const durationMs = Math.max(0, _nullishCoalesce(call.durationMs, () => ( 0)));
1008
1238
  const endTime = /* @__PURE__ */ new Date();
1009
1239
  const startTime = new Date(endTime.getTime() - durationMs);
1010
1240
  const span = tracer.startSpan(
1011
- `${call.operation ?? "chat"} ${call.model}`,
1241
+ `${_nullishCoalesce(call.operation, () => ( "chat"))} ${call.model}`,
1012
1242
  {
1013
- kind: import_api2.SpanKind.CLIENT,
1243
+ kind: _api.SpanKind.CLIENT,
1014
1244
  startTime,
1015
1245
  attributes: { ...llmBaseAttributes(call), ...usageAttributes(call) }
1016
1246
  }
1017
1247
  );
1018
1248
  if (call.error !== void 0 && call.error !== null) {
1249
+ recordError(span, call.error);
1019
1250
  if (call.error instanceof Error) {
1020
- span.recordException(call.error);
1021
1251
  span.setAttribute("error.type", call.error.name);
1022
1252
  }
1023
- span.setStatus({
1024
- code: import_api2.SpanStatusCode.ERROR,
1025
- message: call.error instanceof Error ? call.error.message : String(call.error)
1026
- });
1027
1253
  } else {
1028
- span.setStatus({ code: import_api2.SpanStatusCode.OK });
1254
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1029
1255
  }
1030
1256
  span.end(endTime);
1031
1257
  }
1032
- async function runWithSpan(tracer, name, fn, attributes) {
1033
- const span = tracer.startSpan(name, { attributes });
1258
+ async function runWithSpan(tracer, name, fn, attributes, links) {
1259
+ const span = tracer.startSpan(name, {
1260
+ attributes,
1261
+ ..._optionalChain([links, 'optionalAccess', _40 => _40.length]) ? { links } : {}
1262
+ });
1034
1263
  try {
1035
- const result = await import_api2.context.with(
1036
- import_api2.trace.setSpan(import_api2.context.active(), span),
1264
+ const result = await _api.context.with(
1265
+ _api.trace.setSpan(_api.context.active(), span),
1037
1266
  fn
1038
1267
  );
1039
- span.setStatus({ code: import_api2.SpanStatusCode.OK });
1268
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1040
1269
  return result;
1041
1270
  } catch (err) {
1042
- if (err instanceof Error) span.recordException(err);
1043
- span.setStatus({
1044
- code: import_api2.SpanStatusCode.ERROR,
1045
- message: err instanceof Error ? err.message : String(err)
1046
- });
1271
+ recordError(span, err);
1047
1272
  throw err;
1048
1273
  } finally {
1049
1274
  span.end();
1050
1275
  }
1051
1276
  }
1052
- function expressRouteOf(req) {
1053
- const props = req;
1054
- const path = props?.route?.path;
1055
- if (typeof path !== "string" || path === "") return null;
1056
- const base = typeof props?.baseUrl === "string" ? props.baseUrl : "";
1057
- const route = base + path;
1058
- return route.startsWith("/") ? route : null;
1277
+ function recordError(span, err) {
1278
+ const isError = err instanceof Error;
1279
+ const message = activeRedactor.text(isError ? err.message : String(err));
1280
+ if (isError) {
1281
+ span.addEvent("exception", {
1282
+ "exception.type": err.name,
1283
+ "exception.message": message,
1284
+ ...err.stack ? { "exception.stacktrace": activeRedactor.text(err.stack) } : {}
1285
+ });
1286
+ }
1287
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message });
1288
+ }
1289
+ function redactWithActive(attributes) {
1290
+ return activeRedactor(attributes);
1059
1291
  }
1060
1292
  function captureExpressRoute(_span, response) {
1061
- if (!(response instanceof import_node_http.ServerResponse)) return;
1062
- const rpcMetadata = (0, import_core2.getRPCMetadata)(import_api2.context.active());
1063
- if (rpcMetadata?.type !== import_core2.RPCType.HTTP) return;
1293
+ if (!(response instanceof _http.ServerResponse)) return;
1294
+ const rpcMetadata = _core.getRPCMetadata.call(void 0, _api.context.active());
1295
+ if (_optionalChain([rpcMetadata, 'optionalAccess', _41 => _41.type]) !== _core.RPCType.HTTP) return;
1064
1296
  const setRoute = () => {
1065
1297
  if (rpcMetadata.route) return;
1066
1298
  const route = expressRouteOf(response.req);
@@ -1068,33 +1300,60 @@ function captureExpressRoute(_span, response) {
1068
1300
  };
1069
1301
  response.prependListener("finish", setRoute);
1070
1302
  response.prependListener("close", setRoute);
1303
+ if (hookRequests) startHookRequest(response);
1304
+ }
1305
+ var hookRequests = false;
1306
+ function structuredErrorAttributes(error) {
1307
+ const attrs = { ..._chunkP4VRTFAVcjs.errorAttributes.call(void 0, error, { causes: false }) };
1308
+ const internal = _chunkP4VRTFAVcjs.errorInternal.call(void 0, error);
1309
+ if (internal) {
1310
+ try {
1311
+ attrs["autter.error.internal"] = JSON.stringify(
1312
+ activeRedactor(internal)
1313
+ ).slice(0, 4e3);
1314
+ } catch (e21) {
1315
+ }
1316
+ }
1317
+ return attrs;
1071
1318
  }
1072
1319
  var active = null;
1073
1320
  var activeAlwaysOnProvider = null;
1074
- var activeRedactor = makeRedactor(true);
1321
+ var activeRedactor = _chunkP4VRTFAVcjs.makeRedactor.call(void 0, true);
1075
1322
  function initAutterServer(options) {
1076
1323
  if (active) return active;
1077
- const endpoint = (options.endpoint ?? "https://otlp.autter.dev").replace(
1324
+ const endpoint = (_nullishCoalesce(options.endpoint, () => ( "https://otlp.autter.dev"))).replace(
1078
1325
  /\/$/,
1079
1326
  ""
1080
1327
  );
1081
1328
  const headers = { authorization: `Bearer ${options.apiKey}` };
1082
- const environment = options.environment ?? process.env.NODE_ENV ?? "production";
1083
- if (isDebugEnabled() || options.debug === true) setDebugMode(true);
1084
- debugLog(`initialising service=${options.service} endpoint=${endpoint}`);
1085
- activeRedactor = makeRedactor(options.redactAttributes ?? true);
1086
- const resource = new import_resources.Resource({
1087
- [import_semantic_conventions.ATTR_SERVICE_NAME]: options.service,
1088
- "service.instance.id": (options.instanceId || process.env.AUTTER_RUNTIME_INSTANCE_ID || (0, import_node_crypto.randomUUID)()).slice(0, 128),
1089
- ...options.release ? { [import_semantic_conventions.ATTR_SERVICE_VERSION]: options.release } : {},
1329
+ const traceExporter = () => new (0, _chunkGI47WGRRcjs.CountingExporter)(
1330
+ new RedactingSpanExporter(
1331
+ new (0, _exportertraceotlphttp.OTLPTraceExporter)({ url: `${endpoint}/v1/traces`, headers }),
1332
+ () => activeRedactor
1333
+ )
1334
+ );
1335
+ const environment = _nullishCoalesce(_nullishCoalesce(options.environment, () => ( process.env.NODE_ENV)), () => ( "production"));
1336
+ if (_chunkGI47WGRRcjs.isDebugEnabled.call(void 0, ) || options.debug === true) _chunkGI47WGRRcjs.setDebugMode.call(void 0, true);
1337
+ _chunkGI47WGRRcjs.debugLog.call(void 0, `initialising service=${options.service} endpoint=${endpoint}`);
1338
+ activeRedactor = _chunkP4VRTFAVcjs.makeRedactor.call(void 0, _nullishCoalesce(options.redactAttributes, () => ( true)));
1339
+ const distro = _nullishCoalesce(options.distro, () => ( _chunkGI47WGRRcjs.SDK_IDENTITY));
1340
+ _chunkGI47WGRRcjs.configureCompatCheck.call(void 0, { endpoint, enabled: options.compatCheck !== false, sdk: distro });
1341
+ const resource = new (0, _resources.Resource)({
1342
+ [_semanticconventions.ATTR_SERVICE_NAME]: options.service,
1343
+ "service.instance.id": (options.instanceId || process.env.AUTTER_RUNTIME_INSTANCE_ID || _crypto.randomUUID.call(void 0, )).slice(0, 128),
1344
+ ...options.release ? { [_semanticconventions.ATTR_SERVICE_VERSION]: options.release } : {},
1090
1345
  "deployment.environment": environment,
1346
+ // OTel semconv for SDK distributions: the ingester records which
1347
+ // Autter SDK version each service runs (version compatibility checks).
1348
+ "telemetry.distro.name": distro.name,
1349
+ "telemetry.distro.version": distro.version,
1091
1350
  // Tells the ingester request metrics arrive on the metrics pipe, so
1092
1351
  // it must not also fold our server spans into usage rollups (that
1093
1352
  // would double-count every sampled request).
1094
1353
  "autter.metrics_wired": true
1095
1354
  });
1096
- const headSampler = new import_sdk_trace_base.ParentBasedSampler({
1097
- root: new import_sdk_trace_base.TraceIdRatioBasedSampler(options.traceSampleRate ?? 0.01)
1355
+ const headSampler = new (0, _sdktracebase.ParentBasedSampler)({
1356
+ root: new (0, _sdktracebase.TraceIdRatioBasedSampler)(_nullishCoalesce(options.traceSampleRate, () => ( 0.01)))
1098
1357
  });
1099
1358
  const retainOnError = options.retainTracesOnError !== false;
1100
1359
  const slowThresholdMs = Number.isFinite(options.retainTracesAboveMs) ? Math.max(0, options.retainTracesAboveMs) : 0;
@@ -1102,33 +1361,27 @@ function initAutterServer(options) {
1102
1361
  let sampler = retainTraces ? new RecordUnsampledSampler(headSampler) : headSampler;
1103
1362
  if (options.llmTracing !== false) sampler = new LlmAwareSampler(sampler);
1104
1363
  const errorTraceBuffer = retainTraces ? new ErrorTraceRetentionProcessor(
1105
- new import_sdk_trace_base.BatchSpanProcessor(
1106
- new CountingExporter(
1107
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1108
- ),
1109
- { scheduledDelayMillis: 2e3 }
1110
- ),
1364
+ new (0, _sdktracebase.BatchSpanProcessor)(traceExporter(), { scheduledDelayMillis: 2e3 }),
1111
1365
  retainOnError,
1112
1366
  slowThresholdMs
1113
1367
  ) : null;
1114
- const mainSpanProcessor = new import_sdk_trace_base.BatchSpanProcessor(
1115
- new CountingExporter(
1116
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1117
- )
1118
- );
1119
- const metricReader = new import_sdk_metrics.PeriodicExportingMetricReader({
1120
- exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
1121
- url: `${endpoint}/v1/metrics`,
1122
- headers,
1123
- // Deltas, not lifetime totals: the ingester SUMs data points
1124
- // into runtime_metrics_1m, and the default (cumulative)
1125
- // temporality would re-count every past request on each
1126
- // 60 s export.
1127
- temporalityPreference: import_exporter_metrics_otlp_http.AggregationTemporalityPreference.DELTA
1128
- }),
1129
- exportIntervalMillis: options.metricIntervalMs ?? 6e4
1368
+ const mainSpanProcessor = new (0, _sdktracebase.BatchSpanProcessor)(traceExporter());
1369
+ const metricReader = new (0, _sdkmetrics.PeriodicExportingMetricReader)({
1370
+ exporter: new RedactingMetricExporter(
1371
+ new (0, _exportermetricsotlphttp.OTLPMetricExporter)({
1372
+ url: `${endpoint}/v1/metrics`,
1373
+ headers,
1374
+ // Deltas, not lifetime totals: the ingester SUMs data points
1375
+ // into runtime_metrics_1m, and the default (cumulative)
1376
+ // temporality would re-count every past request on each
1377
+ // 60 s export.
1378
+ temporalityPreference: _exportermetricsotlphttp.AggregationTemporalityPreference.DELTA
1379
+ }),
1380
+ () => activeRedactor
1381
+ ),
1382
+ exportIntervalMillis: _nullishCoalesce(options.metricIntervalMs, () => ( 6e4))
1130
1383
  });
1131
- const sdk = new import_sdk_node.NodeSDK({
1384
+ const sdk = new (0, _sdknode.NodeSDK)({
1132
1385
  resource,
1133
1386
  sampler,
1134
1387
  spanProcessors: [
@@ -1137,105 +1390,129 @@ function initAutterServer(options) {
1137
1390
  ],
1138
1391
  metricReader,
1139
1392
  views: [
1140
- new import_sdk_metrics.View({ instrumentName: "http.server.duration", aggregation: new import_sdk_metrics.ExplicitBucketHistogramAggregation(
1393
+ new (0, _sdkmetrics.View)({ instrumentName: "http.server.duration", aggregation: new (0, _sdkmetrics.ExplicitBucketHistogramAggregation)(
1141
1394
  [5, 10, 25, 50, 100, 250, 500, 750, 1e3, 1500, 2e3, 3e3, 5e3, 7500, 1e4, 15e3, 2e4, 3e4, 6e4, 12e4]
1142
1395
  ) }),
1143
- new import_sdk_metrics.View({ instrumentName: "http.server.request.duration", aggregation: new import_sdk_metrics.ExplicitBucketHistogramAggregation(
1396
+ new (0, _sdkmetrics.View)({ instrumentName: "http.server.request.duration", aggregation: new (0, _sdkmetrics.ExplicitBucketHistogramAggregation)(
1144
1397
  [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]
1145
1398
  ) })
1146
1399
  ],
1147
1400
  instrumentations: [
1148
- new import_instrumentation_http.HttpInstrumentation({ responseHook: captureExpressRoute }),
1149
- ...options.instrumentations ?? []
1401
+ new (0, _instrumentationhttp.HttpInstrumentation)({ responseHook: captureExpressRoute }),
1402
+ ..._nullishCoalesce(options.instrumentations, () => ( []))
1150
1403
  ]
1151
1404
  });
1152
1405
  sdk.start();
1153
1406
  const stopMemoryMetrics = options.memoryMetrics === false ? null : startMemoryMetrics();
1154
- const alwaysOnProvider = new import_sdk_trace_base.BasicTracerProvider({
1407
+ _chunkGI47WGRRcjs.noteCompatFeature.call(void 0, "endpoint_latency");
1408
+ if (stopMemoryMetrics) _chunkGI47WGRRcjs.noteCompatFeature.call(void 0, "memory_metrics");
1409
+ if (options.llmTracing !== false) _chunkGI47WGRRcjs.noteCompatFeature.call(void 0, "llm_calls");
1410
+ const alwaysOnProvider = new (0, _sdktracebase.BasicTracerProvider)({
1155
1411
  resource,
1156
- sampler: new import_sdk_trace_base.AlwaysOnSampler(),
1412
+ sampler: new (0, _sdktracebase.AlwaysOnSampler)(),
1157
1413
  spanProcessors: [
1158
- new import_sdk_trace_base.BatchSpanProcessor(
1159
- new CountingExporter(
1160
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1161
- ),
1162
- { scheduledDelayMillis: 2e3 }
1163
- )
1414
+ new (0, _sdktracebase.BatchSpanProcessor)(traceExporter(), { scheduledDelayMillis: 2e3 })
1164
1415
  ]
1165
1416
  });
1166
1417
  const errorTracer = alwaysOnProvider.getTracer("autter-errors");
1167
1418
  const processTracer = alwaysOnProvider.getTracer("autter-processes");
1168
1419
  const llmTracer = alwaysOnProvider.getTracer("autter-llm");
1169
1420
  function captureException2(error, attributes) {
1170
- errorTraceBuffer?.retainActiveTrace();
1171
- telemetryStats.markCaptured();
1421
+ _optionalChain([errorTraceBuffer, 'optionalAccess', _42 => _42.retainActiveTrace, 'call', _43 => _43()]);
1422
+ _chunkGI47WGRRcjs.telemetryStats.markCaptured();
1172
1423
  const isError = error instanceof Error;
1173
- const message = isError ? error.message : String(error);
1424
+ const message = activeRedactor.text(isError ? error.message : String(error));
1425
+ const stackText = isError && error.stack ? activeRedactor.text(error.stack) : "";
1174
1426
  const redacted = activeRedactor(attributes);
1175
- const activeSpan = import_api2.trace.getActiveSpan();
1176
- const reuseActive = activeSpan?.isRecording() === true;
1427
+ const activeSpan = _api.trace.getActiveSpan();
1428
+ const reuseActive = _optionalChain([activeSpan, 'optionalAccess', _44 => _44.isRecording, 'call', _45 => _45()]) === true;
1177
1429
  const span = reuseActive ? activeSpan : errorTracer.startSpan(isError ? error.name : "Error");
1178
- span.setAttributes({ "autter.severity": "error", ...redacted });
1179
- if (isError && error.stack) {
1180
- if (redacted["autter.handled"] === true) {
1181
- span.addEvent("exception", {
1182
- "exception.type": error.name,
1183
- "exception.message": message,
1184
- "exception.stacktrace": error.stack,
1185
- "autter.handled": true,
1186
- "autter.sampled": redacted["autter.sampled"] === true
1187
- });
1188
- } else {
1189
- span.recordException(error);
1190
- }
1430
+ const structured = structuredErrorAttributes(error);
1431
+ const causes = _chunkP4VRTFAVcjs.errorAttributes.call(void 0, error);
1432
+ const declared = Object.fromEntries(
1433
+ Object.entries(causes).filter(([key]) => key !== "autter.error.internal")
1434
+ );
1435
+ const requestId = _optionalChain([_chunkP4VRTFAVcjs.currentOperation.call(void 0, ), 'optionalAccess', _46 => _46.requestId]);
1436
+ span.setAttributes({
1437
+ "autter.severity": "error",
1438
+ ...redacted,
1439
+ ...structured,
1440
+ ...requestId ? { "autter.request.id": requestId } : {}
1441
+ });
1442
+ markCaptured(error);
1443
+ _chunkP4VRTFAVcjs.noteOperationError.call(void 0, error);
1444
+ _chunkP4VRTFAVcjs.notifyException.call(void 0, error, redacted);
1445
+ if (isError && stackText) {
1446
+ span.addEvent("exception", {
1447
+ "exception.type": error.name,
1448
+ "exception.message": message,
1449
+ "exception.stacktrace": stackText,
1450
+ ...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
1451
+ ...declared
1452
+ });
1191
1453
  } else {
1192
- const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureException")).join("\n");
1454
+ const stack = _optionalChain([new Error(), 'access', _47 => _47.stack, 'optionalAccess', _48 => _48.split, 'call', _49 => _49("\n"), 'access', _50 => _50.filter, 'call', _51 => _51((line, i) => i === 0 || !line.includes("captureException")), 'access', _52 => _52.join, 'call', _53 => _53("\n")]);
1193
1455
  span.addEvent("exception", {
1194
1456
  "exception.type": isError ? error.name : "Error",
1195
1457
  "exception.message": message,
1196
- ...stack ? { "exception.stacktrace": stack } : {},
1197
- ...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {}
1458
+ ...stack ? { "exception.stacktrace": activeRedactor.text(stack) } : {},
1459
+ ...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
1460
+ ...declared
1198
1461
  });
1199
1462
  }
1200
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message });
1463
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message });
1201
1464
  if (!reuseActive) span.end();
1202
1465
  }
1203
1466
  function captureMessage2(message, severity = "warning", attributes) {
1204
1467
  if (severity === "error" || severity === "fatal") {
1205
- errorTraceBuffer?.retainActiveTrace();
1468
+ _optionalChain([errorTraceBuffer, 'optionalAccess', _54 => _54.retainActiveTrace, 'call', _55 => _55()]);
1206
1469
  }
1207
- telemetryStats.markCaptured();
1208
- const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureMessage")).join("\n");
1470
+ _chunkGI47WGRRcjs.telemetryStats.markCaptured();
1471
+ const stack = _optionalChain([new Error(), 'access', _56 => _56.stack, 'optionalAccess', _57 => _57.split, 'call', _58 => _58("\n"), 'access', _59 => _59.filter, 'call', _60 => _60((line, i) => i === 0 || !line.includes("captureMessage")), 'access', _61 => _61.join, 'call', _62 => _62("\n")]);
1472
+ const safeMessage = activeRedactor.text(message);
1209
1473
  const span = errorTracer.startSpan("Message", {
1210
1474
  attributes: { "autter.severity": severity, ...activeRedactor(attributes) }
1211
1475
  });
1212
1476
  span.addEvent("exception", {
1213
1477
  "exception.type": "Message",
1214
- "exception.message": message,
1215
- ...stack ? { "exception.stacktrace": stack } : {},
1478
+ "exception.message": safeMessage,
1479
+ ...stack ? { "exception.stacktrace": activeRedactor.text(stack) } : {},
1216
1480
  "autter.severity": severity
1217
1481
  });
1218
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message });
1482
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1219
1483
  span.end();
1220
1484
  }
1221
1485
  function reportOutcome2(name, message, attributes) {
1222
- errorTraceBuffer?.retainActiveTrace();
1223
- telemetryStats.markCaptured();
1224
- const activeSpan = import_api2.trace.getActiveSpan();
1225
- const reuseActive = activeSpan?.isRecording() === true;
1486
+ _optionalChain([errorTraceBuffer, 'optionalAccess', _63 => _63.retainActiveTrace, 'call', _64 => _64()]);
1487
+ _chunkGI47WGRRcjs.telemetryStats.markCaptured();
1488
+ const activeSpan = _api.trace.getActiveSpan();
1489
+ const reuseActive = _optionalChain([activeSpan, 'optionalAccess', _65 => _65.isRecording, 'call', _66 => _66()]) === true;
1226
1490
  const span = reuseActive ? activeSpan : errorTracer.startSpan("OutcomeFailure");
1227
1491
  const safeOutcome = activeRedactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1228
- const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
1229
- const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
1492
+ const safeName = String(_nullishCoalesce(safeOutcome["autter.outcome.name"], () => ( "operation")));
1493
+ const safeMessage = String(_nullishCoalesce(safeOutcome["autter.outcome.message"], () => ( "failed")));
1230
1494
  span.addEvent("autter.outcome", {
1231
1495
  ...activeRedactor(attributes),
1232
1496
  "autter.outcome.status": "error",
1233
1497
  "autter.outcome.name": safeName,
1234
1498
  "autter.outcome.message": safeMessage
1235
1499
  });
1236
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message: safeMessage });
1500
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1237
1501
  if (!reuseActive) span.end();
1238
1502
  }
1503
+ _chunkP4VRTFAVcjs.configureRuntimeLogger.call(void 0, {
1504
+ endpoint,
1505
+ apiKey: options.apiKey,
1506
+ service: options.service,
1507
+ environment,
1508
+ distro,
1509
+ release: options.release,
1510
+ options: options.logging,
1511
+ redact: activeRedactor,
1512
+ run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn, activeRedactor(attributes), links),
1513
+ reportOutcome: reportOutcome2
1514
+ });
1515
+ hookRequests = _optionalChain([options, 'access', _67 => _67.logging, 'optionalAccess', _68 => _68.requests]) === true;
1239
1516
  if (options.captureGlobalErrors !== false) {
1240
1517
  process.on("uncaughtExceptionMonitor", (err) => {
1241
1518
  captureException2(err, { "autter.unhandled": true });
@@ -1246,6 +1523,7 @@ function initAutterServer(options) {
1246
1523
  const flushTarget = {
1247
1524
  forceFlush: async () => {
1248
1525
  const results = await Promise.allSettled([
1526
+ _chunkP4VRTFAVcjs.flushRuntimeLogs.call(void 0, ),
1249
1527
  Promise.resolve().then(() => alwaysOnProvider.forceFlush()),
1250
1528
  Promise.resolve().then(() => mainSpanProcessor.forceFlush()),
1251
1529
  ...errorTraceBuffer ? [Promise.resolve().then(() => errorTraceBuffer.forceFlush())] : [],
@@ -1259,10 +1537,10 @@ function initAutterServer(options) {
1259
1537
  }
1260
1538
  }
1261
1539
  };
1262
- registerFlushTarget("active-server", flushTarget);
1540
+ _chunkGI47WGRRcjs.registerFlushTarget.call(void 0, "active-server", flushTarget);
1263
1541
  let autoFlushHandle = null;
1264
1542
  if (options.autoFlush !== false) {
1265
- autoFlushHandle = installAutterAutoFlush();
1543
+ autoFlushHandle = _chunkGI47WGRRcjs.installAutterAutoFlush.call(void 0, );
1266
1544
  }
1267
1545
  const server = {
1268
1546
  captureException: captureException2,
@@ -1272,14 +1550,17 @@ function initAutterServer(options) {
1272
1550
  withLlmCall: (info, fn) => runLlmSpan(llmTracer, info, fn),
1273
1551
  trackLlmCall: (call) => recordLlmCall(llmTracer, call),
1274
1552
  shutdown: async () => {
1275
- stopMemoryMetrics?.();
1553
+ const logShutdown = await Promise.allSettled([_chunkP4VRTFAVcjs.shutdownRuntimeLogger.call(void 0, )]);
1554
+ hookRequests = false;
1555
+ _optionalChain([stopMemoryMetrics, 'optionalCall', _69 => _69()]);
1276
1556
  active = null;
1277
1557
  activeAlwaysOnProvider = null;
1278
- autoFlushHandle?.dispose();
1558
+ _optionalChain([autoFlushHandle, 'optionalAccess', _70 => _70.dispose, 'call', _71 => _71()]);
1279
1559
  autoFlushHandle = null;
1280
- unregisterFlushTargets();
1281
- telemetryStats.markAllFlushed();
1560
+ _chunkGI47WGRRcjs.unregisterFlushTargets.call(void 0, );
1561
+ _chunkGI47WGRRcjs.telemetryStats.markAllFlushed();
1282
1562
  await Promise.allSettled([alwaysOnProvider.shutdown(), sdk.shutdown()]);
1563
+ if (_optionalChain([logShutdown, 'access', _72 => _72[0], 'optionalAccess', _73 => _73.status]) === "rejected") throw logShutdown[0].reason;
1283
1564
  }
1284
1565
  };
1285
1566
  active = server;
@@ -1291,69 +1572,88 @@ function captureException(error, attributes) {
1291
1572
  active.captureException(error, attributes);
1292
1573
  return;
1293
1574
  }
1294
- const span = import_api2.trace.getTracer("autter-errors").startSpan(error instanceof Error ? error.name : "Error", { attributes });
1295
- if (error instanceof Error) span.recordException(error);
1296
- span.setStatus({
1297
- code: import_api2.SpanStatusCode.ERROR,
1298
- message: error instanceof Error ? error.message : String(error)
1575
+ if (loggerOnlyCapture) {
1576
+ loggerOnlyCapture(error, attributes);
1577
+ return;
1578
+ }
1579
+ markCaptured(error);
1580
+ _chunkP4VRTFAVcjs.noteOperationError.call(void 0, error);
1581
+ _chunkP4VRTFAVcjs.notifyException.call(void 0, error, attributes);
1582
+ const span = _api.trace.getTracer("autter-errors").startSpan(error instanceof Error ? error.name : "Error", {
1583
+ attributes: activeRedactor(attributes)
1299
1584
  });
1585
+ recordError(span, error);
1300
1586
  span.end();
1301
1587
  }
1588
+ var loggerOnlyCapture = null;
1589
+ function setLoggerOnlyCapture(fn) {
1590
+ loggerOnlyCapture = fn;
1591
+ }
1592
+ function serverActive() {
1593
+ return active !== null;
1594
+ }
1595
+ setRequestExceptionCapturer((error) => captureException(error));
1302
1596
  function withProcessSpan(name, fn, attributes) {
1303
1597
  if (active) return active.withProcessSpan(name, fn, attributes);
1304
- return runWithSpan(import_api2.trace.getTracer("autter-processes"), name, fn, attributes);
1598
+ return runWithSpan(
1599
+ _api.trace.getTracer("autter-processes"),
1600
+ name,
1601
+ fn,
1602
+ activeRedactor(attributes)
1603
+ );
1305
1604
  }
1306
1605
  function withLlmCall(info, fn) {
1307
1606
  if (active) return active.withLlmCall(info, fn);
1308
- return runLlmSpan(import_api2.trace.getTracer("autter-llm"), info, fn);
1607
+ return runLlmSpan(_api.trace.getTracer("autter-llm"), info, fn);
1309
1608
  }
1310
1609
  function trackLlmCall(call) {
1311
1610
  if (active) {
1312
1611
  active.trackLlmCall(call);
1313
1612
  return;
1314
1613
  }
1315
- recordLlmCall(import_api2.trace.getTracer("autter-llm"), call);
1614
+ recordLlmCall(_api.trace.getTracer("autter-llm"), call);
1316
1615
  }
1317
1616
  function captureMessage(message, severity = "warning", attributes) {
1318
1617
  if (active) {
1319
1618
  active.captureMessage(message, severity, attributes);
1320
1619
  return;
1321
1620
  }
1322
- const span = import_api2.trace.getTracer("autter-errors").startSpan("Message", {
1323
- attributes: { "autter.severity": severity, ...attributes }
1621
+ const safeMessage = activeRedactor.text(message);
1622
+ const span = _api.trace.getTracer("autter-errors").startSpan("Message", {
1623
+ attributes: { "autter.severity": severity, ...activeRedactor(attributes) }
1324
1624
  });
1325
1625
  span.addEvent("exception", {
1326
1626
  "exception.type": "Message",
1327
- "exception.message": message,
1627
+ "exception.message": safeMessage,
1328
1628
  "autter.severity": severity
1329
1629
  });
1330
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message });
1630
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1331
1631
  span.end();
1332
1632
  }
1333
1633
  function reportOutcome(name, message, attributes) {
1334
1634
  if (active) return active.reportOutcome(name, message, attributes);
1335
- const span = import_api2.trace.getTracer("autter-outcomes").startSpan("OutcomeFailure");
1336
- const safeOutcome = redactAttributes({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1337
- const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
1338
- const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
1635
+ const span = _api.trace.getTracer("autter-outcomes").startSpan("OutcomeFailure");
1636
+ const safeOutcome = _chunkP4VRTFAVcjs.redactAttributes.call(void 0, { "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1637
+ const safeName = String(_nullishCoalesce(safeOutcome["autter.outcome.name"], () => ( "operation")));
1638
+ const safeMessage = String(_nullishCoalesce(safeOutcome["autter.outcome.message"], () => ( "failed")));
1339
1639
  span.addEvent("autter.outcome", {
1340
- ...redactAttributes(attributes),
1640
+ ..._chunkP4VRTFAVcjs.redactAttributes.call(void 0, attributes),
1341
1641
  "autter.outcome.status": "error",
1342
1642
  "autter.outcome.name": safeName,
1343
1643
  "autter.outcome.message": safeMessage
1344
1644
  });
1345
- span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message: safeMessage });
1645
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1346
1646
  span.end();
1347
1647
  }
1348
1648
  function makeSafeCapture(options) {
1349
- const clean = (attributes) => attributes ? { ...redactAttributes(attributes, options) } : void 0;
1649
+ const clean = (attributes) => attributes ? { ..._chunkP4VRTFAVcjs.redactAttributes.call(void 0, attributes, options) } : void 0;
1350
1650
  return {
1351
1651
  captureException: (error, attributes) => captureException(error, clean(attributes)),
1352
- captureMessage: (message, severity, attributes) => captureMessage(message, severity ?? "warning", clean(attributes))
1652
+ captureMessage: (message, severity, attributes) => captureMessage(message, _nullishCoalesce(severity, () => ( "warning")), clean(attributes))
1353
1653
  };
1354
1654
  }
1355
1655
  function alwaysOnTracer(name) {
1356
- return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) : import_api2.trace.getTracer(name);
1656
+ return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) : _api.trace.getTracer(name);
1357
1657
  }
1358
1658
  function autterLlmTracer() {
1359
1659
  return alwaysOnTracer("autter-llm");
@@ -1373,7 +1673,7 @@ async function emitLlmSelftestTrace() {
1373
1673
  attributes: { "autter.selftest": true }
1374
1674
  },
1375
1675
  (llm) => {
1376
- traceId = import_api2.trace.getActiveSpan()?.spanContext().traceId ?? "";
1676
+ traceId = _nullishCoalesce(_optionalChain([_api.trace, 'access', _74 => _74.getActiveSpan, 'call', _75 => _75(), 'optionalAccess', _76 => _76.spanContext, 'call', _77 => _77(), 'access', _78 => _78.traceId]), () => ( ""));
1377
1677
  llm.setUsage({ inputTokens: 1, outputTokens: 1 });
1378
1678
  llm.setCost(0);
1379
1679
  }
@@ -1383,7 +1683,10 @@ async function emitLlmSelftestTrace() {
1383
1683
  }
1384
1684
 
1385
1685
  // src/llm-instrument.ts
1386
- var import_api3 = require("@opentelemetry/api");
1686
+
1687
+
1688
+
1689
+
1387
1690
  var CALL_METHODS = /* @__PURE__ */ new Set([
1388
1691
  "create",
1389
1692
  // openai chat/completions/embeddings/responses, anthropic messages
@@ -1398,15 +1701,15 @@ var CALL_METHODS = /* @__PURE__ */ new Set([
1398
1701
  // openai beta structured outputs
1399
1702
  ]);
1400
1703
  function detectProvider(client) {
1401
- const name = client.constructor?.name?.toLowerCase() ?? "";
1704
+ const name = _nullishCoalesce(_optionalChain([client, 'access', _79 => _79.constructor, 'optionalAccess', _80 => _80.name, 'optionalAccess', _81 => _81.toLowerCase, 'call', _82 => _82()]), () => ( ""));
1402
1705
  for (const known of ["openai", "anthropic", "mistral", "groq", "cohere"]) {
1403
1706
  if (name.includes(known)) return known;
1404
1707
  }
1405
1708
  if (name.includes("google") || name.includes("genai")) return "google";
1406
1709
  const baseUrl = String(
1407
- client.baseURL ?? client.baseUrl ?? ""
1710
+ _nullishCoalesce(_nullishCoalesce(client.baseURL, () => ( client.baseUrl)), () => ( ""))
1408
1711
  );
1409
- const host = baseUrl.match(/https?:\/\/([^/]+)/)?.[1] ?? "";
1712
+ const host = _nullishCoalesce(_optionalChain([baseUrl, 'access', _83 => _83.match, 'call', _84 => _84(/https?:\/\/([^/]+)/), 'optionalAccess', _85 => _85[1]]), () => ( ""));
1410
1713
  if (host.includes("openai")) return "openai";
1411
1714
  if (host.includes("anthropic")) return "anthropic";
1412
1715
  if (host.includes("googleapis")) return "google";
@@ -1416,17 +1719,28 @@ function detectProvider(client) {
1416
1719
  }
1417
1720
  function extractUsage(result) {
1418
1721
  const r = result;
1419
- const usage = r?.usage ?? r?.message?.usage;
1420
- const meta = r?.usageMetadata;
1421
- const input = usage?.prompt_tokens ?? usage?.input_tokens ?? meta?.promptTokenCount ?? void 0;
1422
- const output = usage?.completion_tokens ?? usage?.output_tokens ?? meta?.candidatesTokenCount ?? void 0;
1423
- const responseModel = r?.model ?? r?.modelVersion;
1722
+ const usage = _nullishCoalesce(_optionalChain([r, 'optionalAccess', _86 => _86.usage]), () => ( _optionalChain([r, 'optionalAccess', _87 => _87.message, 'optionalAccess', _88 => _88.usage])));
1723
+ const meta = _optionalChain([r, 'optionalAccess', _89 => _89.usageMetadata]);
1724
+ const details = _optionalChain([usage, 'optionalAccess', _90 => _90.prompt_tokens_details]);
1725
+ const cached = _nullishCoalesce(_nullishCoalesce(_optionalChain([usage, 'optionalAccess', _91 => _91.cache_read_input_tokens]), () => ( (typeof _optionalChain([details, 'optionalAccess', _92 => _92.cached_tokens]) === "number" ? details.cached_tokens : void 0))), () => ( _optionalChain([meta, 'optionalAccess', _93 => _93.cachedContentTokenCount])));
1726
+ const input = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([usage, 'optionalAccess', _94 => _94.prompt_tokens]), () => ( _optionalChain([usage, 'optionalAccess', _95 => _95.input_tokens]))), () => ( _optionalChain([meta, 'optionalAccess', _96 => _96.promptTokenCount]))), () => ( void 0));
1727
+ const output = _nullishCoalesce(_nullishCoalesce(_nullishCoalesce(_optionalChain([usage, 'optionalAccess', _97 => _97.completion_tokens]), () => ( _optionalChain([usage, 'optionalAccess', _98 => _98.output_tokens]))), () => ( _optionalChain([meta, 'optionalAccess', _99 => _99.candidatesTokenCount]))), () => ( void 0));
1728
+ const responseModel = _nullishCoalesce(_optionalChain([r, 'optionalAccess', _100 => _100.model]), () => ( _optionalChain([r, 'optionalAccess', _101 => _101.modelVersion])));
1424
1729
  return {
1425
1730
  inputTokens: typeof input === "number" ? input : void 0,
1426
1731
  outputTokens: typeof output === "number" ? output : void 0,
1732
+ cacheReadTokens: typeof cached === "number" ? cached : void 0,
1427
1733
  responseModel: typeof responseModel === "string" ? responseModel : void 0
1428
1734
  };
1429
1735
  }
1736
+ function rollUp(model, usage) {
1737
+ _chunkP4VRTFAVcjs.recordOperationAiUsage.call(void 0, {
1738
+ model: _nullishCoalesce(usage.responseModel, () => ( model)),
1739
+ ...usage.inputTokens !== void 0 ? { inputTokens: usage.inputTokens } : {},
1740
+ ...usage.outputTokens !== void 0 ? { outputTokens: usage.outputTokens } : {},
1741
+ ...usage.cacheReadTokens !== void 0 ? { cacheReadTokens: usage.cacheReadTokens } : {}
1742
+ });
1743
+ }
1430
1744
  function applyUsage(span, usage) {
1431
1745
  if (usage.inputTokens !== void 0) {
1432
1746
  span.setAttribute("gen_ai.usage.input_tokens", usage.inputTokens);
@@ -1439,14 +1753,10 @@ function applyUsage(span, usage) {
1439
1753
  }
1440
1754
  }
1441
1755
  function endWithError(span, err) {
1442
- if (err instanceof Error) span.recordException(err);
1443
- span.setStatus({
1444
- code: import_api3.SpanStatusCode.ERROR,
1445
- message: err instanceof Error ? err.message : String(err)
1446
- });
1756
+ recordError(span, err);
1447
1757
  span.end();
1448
1758
  }
1449
- function wrapStream(stream, span) {
1759
+ function wrapStream(stream, span, model) {
1450
1760
  let ended = false;
1451
1761
  const seen = {
1452
1762
  inputTokens: void 0,
@@ -1457,11 +1767,12 @@ function wrapStream(stream, span) {
1457
1767
  if (ended) return;
1458
1768
  ended = true;
1459
1769
  applyUsage(span, seen);
1770
+ rollUp(model, seen);
1460
1771
  span.setAttribute("autter.llm.streamed", true);
1461
1772
  if (err !== void 0) {
1462
1773
  endWithError(span, err);
1463
1774
  } else {
1464
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1775
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1465
1776
  span.end();
1466
1777
  }
1467
1778
  };
@@ -1478,6 +1789,7 @@ function wrapStream(stream, span) {
1478
1789
  const usage = extractUsage(step.value);
1479
1790
  if (usage.inputTokens !== void 0) seen.inputTokens = usage.inputTokens;
1480
1791
  if (usage.outputTokens !== void 0) seen.outputTokens = usage.outputTokens;
1792
+ if (usage.cacheReadTokens !== void 0) seen.cacheReadTokens = usage.cacheReadTokens;
1481
1793
  if (usage.responseModel) seen.responseModel = usage.responseModel;
1482
1794
  } else {
1483
1795
  finish();
@@ -1506,24 +1818,24 @@ function wrapStream(stream, span) {
1506
1818
  });
1507
1819
  }
1508
1820
  function instrumentLlmClient(client, options) {
1509
- const provider = (options?.provider ?? detectProvider(client)).toLowerCase();
1821
+ const provider = (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _102 => _102.provider]), () => ( detectProvider(client)))).toLowerCase();
1510
1822
  const proxied = /* @__PURE__ */ new WeakMap();
1511
1823
  function resolveUserId() {
1512
- return typeof options?.userId === "function" ? options.userId() : options?.userId;
1824
+ return typeof _optionalChain([options, 'optionalAccess', _103 => _103.userId]) === "function" ? options.userId() : _optionalChain([options, 'optionalAccess', _104 => _104.userId]);
1513
1825
  }
1514
1826
  function traceCall(fn, self, callPath, args) {
1515
1827
  const request = args[0];
1516
1828
  const operation = /embed/i.test(callPath) ? "embeddings" : "chat";
1517
1829
  const userId = resolveUserId();
1518
1830
  const span = autterLlmTracer().startSpan(`${operation} ${request.model}`, {
1519
- kind: import_api3.SpanKind.CLIENT,
1831
+ kind: _api.SpanKind.CLIENT,
1520
1832
  attributes: {
1521
1833
  "gen_ai.operation.name": operation,
1522
1834
  "gen_ai.provider.name": provider,
1523
1835
  "gen_ai.system": provider,
1524
1836
  "gen_ai.request.model": request.model,
1525
1837
  ...userId ? { "autter.user_id": userId } : {},
1526
- ...options?.attributes
1838
+ ...redactWithActive(_optionalChain([options, 'optionalAccess', _105 => _105.attributes]))
1527
1839
  }
1528
1840
  });
1529
1841
  let result;
@@ -1535,20 +1847,24 @@ function instrumentLlmClient(client, options) {
1535
1847
  }
1536
1848
  if (!(result instanceof Promise)) {
1537
1849
  if (result && typeof result === "object" && Symbol.asyncIterator in result) {
1538
- return wrapStream(result, span);
1850
+ return wrapStream(result, span, request.model);
1539
1851
  }
1540
- applyUsage(span, extractUsage(result));
1541
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1852
+ const usage = extractUsage(result);
1853
+ applyUsage(span, usage);
1854
+ rollUp(request.model, usage);
1855
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1542
1856
  span.end();
1543
1857
  return result;
1544
1858
  }
1545
1859
  return result.then(
1546
1860
  (resolved) => {
1547
1861
  if (resolved && typeof resolved === "object" && Symbol.asyncIterator in resolved) {
1548
- return wrapStream(resolved, span);
1862
+ return wrapStream(resolved, span, request.model);
1549
1863
  }
1550
- applyUsage(span, extractUsage(resolved));
1551
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1864
+ const usage = extractUsage(resolved);
1865
+ applyUsage(span, usage);
1866
+ rollUp(request.model, usage);
1867
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1552
1868
  span.end();
1553
1869
  return resolved;
1554
1870
  },
@@ -1596,11 +1912,11 @@ function instrumentLlmClient(client, options) {
1596
1912
  }
1597
1913
 
1598
1914
  // src/caught-exceptions.ts
1599
- var import_node_inspector = __toESM(require("inspector"), 1);
1915
+ var _inspector = require('inspector'); var _inspector2 = _interopRequireDefault(_inspector);
1600
1916
  function startCaughtExceptionSampler(options = {}) {
1601
- const rate = Math.max(0, Math.min(1, options.sampleRate ?? 0.01));
1602
- const cap = Math.max(1, Math.min(100, options.maxPerMinute ?? 10));
1603
- const session = new import_node_inspector.default.Session();
1917
+ const rate = Math.max(0, Math.min(1, _nullishCoalesce(options.sampleRate, () => ( 0.01))));
1918
+ const cap = Math.max(1, Math.min(100, _nullishCoalesce(options.maxPerMinute, () => ( 10))));
1919
+ const session = new _inspector2.default.Session();
1604
1920
  let active2 = true;
1605
1921
  let minute = 0;
1606
1922
  let sent = 0;
@@ -1616,7 +1932,7 @@ function startCaughtExceptionSampler(options = {}) {
1616
1932
  }
1617
1933
  if (sent >= cap || Math.random() >= rate) return;
1618
1934
  sent++;
1619
- 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})`);
1935
+ 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})`);
1620
1936
  if (!frames.length) return;
1621
1937
  const error = new Error("Sampled caught exception");
1622
1938
  error.name = "CaughtException";
@@ -1638,22 +1954,245 @@ ${frames.join("\n")}`;
1638
1954
  });
1639
1955
  } };
1640
1956
  }
1641
- // Annotate the CommonJS export names for ESM import in node:
1642
- 0 && (module.exports = {
1643
- captureException,
1644
- captureMessage,
1645
- createBrowserRelayFetchHandler,
1646
- createBrowserRelayHandler,
1647
- emitLlmSelftestTrace,
1648
- initAutterServer,
1649
- installAutterAutoFlush,
1650
- instrumentLlmClient,
1651
- makeSafeCapture,
1652
- redactAttributes,
1653
- reportOutcome,
1654
- sanitizeBrowserPayload,
1655
- startCaughtExceptionSampler,
1656
- trackLlmCall,
1657
- withLlmCall,
1658
- withProcessSpan
1659
- });
1957
+
1958
+ // src/logging-only.ts
1959
+
1960
+
1961
+
1962
+
1963
+ var activeLogging = null;
1964
+ function initAutterLogging(options) {
1965
+ if (activeLogging) return activeLogging;
1966
+ if (serverActive()) {
1967
+ console.warn(
1968
+ "[autter-runtime] initAutterLogging() ignored: initAutterServer() is already active and includes logging"
1969
+ );
1970
+ return {
1971
+ captureException,
1972
+ flush: _chunkP4VRTFAVcjs.flushRuntimeLogs,
1973
+ shutdown: async () => {
1974
+ }
1975
+ };
1976
+ }
1977
+ if (_chunkGI47WGRRcjs.isDebugEnabled.call(void 0, ) || options.debug === true) _chunkGI47WGRRcjs.setDebugMode.call(void 0, true);
1978
+ const endpoint = (_nullishCoalesce(options.endpoint, () => ( "https://otlp.autter.dev"))).replace(/\/$/, "");
1979
+ const environment = _nullishCoalesce(_nullishCoalesce(options.environment, () => ( process.env.NODE_ENV)), () => ( "production"));
1980
+ const redact = _chunkP4VRTFAVcjs.makeRedactor.call(void 0, _nullishCoalesce(options.redactAttributes, () => ( true)));
1981
+ const mode = _nullishCoalesce(options.exceptions, () => ( "auto"));
1982
+ _chunkGI47WGRRcjs.debugLog.call(void 0, `initialising logger-only service=${options.service} endpoint=${endpoint}`);
1983
+ function captureException2(error, attributes) {
1984
+ markCaptured(error);
1985
+ const redacted = redact(attributes);
1986
+ const span = _api.trace.getActiveSpan();
1987
+ if (mode === "auto" && _optionalChain([span, 'optionalAccess', _106 => _106.isRecording, 'call', _107 => _107()])) {
1988
+ _chunkP4VRTFAVcjs.noteOperationError.call(void 0, error);
1989
+ _chunkP4VRTFAVcjs.notifyException.call(void 0, error, redacted);
1990
+ span.setAttributes({ "autter.severity": "error", ...redacted, ...structuredErrorAttributes(error) });
1991
+ const declared = _chunkP4VRTFAVcjs.errorAttributes.call(void 0, error);
1992
+ if (error instanceof Error) {
1993
+ span.addEvent("exception", {
1994
+ "exception.type": error.name,
1995
+ "exception.message": error.message,
1996
+ ...error.stack ? { "exception.stacktrace": error.stack } : {},
1997
+ ...declared
1998
+ });
1999
+ } else {
2000
+ span.addEvent("exception", {
2001
+ "exception.type": "Error",
2002
+ "exception.message": String(error),
2003
+ ...declared
2004
+ });
2005
+ }
2006
+ span.setStatus({
2007
+ code: _api.SpanStatusCode.ERROR,
2008
+ message: error instanceof Error ? error.message : String(error)
2009
+ });
2010
+ return;
2011
+ }
2012
+ _chunkP4VRTFAVcjs.notifyException.call(void 0, error, redacted);
2013
+ _chunkP4VRTFAVcjs.captureExceptionAsLog.call(void 0, error, redacted);
2014
+ }
2015
+ const captured = /* @__PURE__ */ new WeakSet();
2016
+ _chunkP4VRTFAVcjs.configureRuntimeLogger.call(void 0, {
2017
+ endpoint,
2018
+ apiKey: _nullishCoalesce(options.apiKey, () => ( "")),
2019
+ service: options.service,
2020
+ environment,
2021
+ ...options.release ? { release: options.release } : {},
2022
+ ...options.logging ? { options: options.logging } : {},
2023
+ redact,
2024
+ reportOutcome: (name, message, attributes) => {
2025
+ _chunkP4VRTFAVcjs.runtimeLogger.error(message, {
2026
+ ...attributes,
2027
+ "autter.outcome.name": name.slice(0, 200),
2028
+ "autter.outcome.message": message.slice(0, 1e3)
2029
+ });
2030
+ },
2031
+ captureThrown: (error) => {
2032
+ if (error && typeof error === "object") {
2033
+ if (captured.has(error)) return;
2034
+ captured.add(error);
2035
+ }
2036
+ captureException2(error);
2037
+ }
2038
+ });
2039
+ setLoggerOnlyCapture(captureException2);
2040
+ const onCrash = (error) => captureException2(error, { "autter.unhandled": true });
2041
+ if (options.captureGlobalErrors !== false)
2042
+ process.on("uncaughtExceptionMonitor", onCrash);
2043
+ _chunkGI47WGRRcjs.registerFlushTarget.call(void 0, "logging", { forceFlush: () => _chunkP4VRTFAVcjs.flushRuntimeLogs.call(void 0, ) });
2044
+ let autoFlushHandle = options.autoFlush === false ? null : _chunkGI47WGRRcjs.installAutterAutoFlush.call(void 0, );
2045
+ const handle = {
2046
+ captureException: captureException2,
2047
+ flush: _chunkP4VRTFAVcjs.flushRuntimeLogs,
2048
+ shutdown: async () => {
2049
+ process.off("uncaughtExceptionMonitor", onCrash);
2050
+ setLoggerOnlyCapture(null);
2051
+ _optionalChain([autoFlushHandle, 'optionalAccess', _108 => _108.dispose, 'call', _109 => _109()]);
2052
+ autoFlushHandle = null;
2053
+ _chunkGI47WGRRcjs.unregisterFlushTargets.call(void 0, );
2054
+ activeLogging = null;
2055
+ await _chunkP4VRTFAVcjs.shutdownRuntimeLogger.call(void 0, );
2056
+ }
2057
+ };
2058
+ activeLogging = handle;
2059
+ return handle;
2060
+ }
2061
+
2062
+ // src/enrichers.ts
2063
+ function headerOf(req, name) {
2064
+ const headers = _optionalChain([req, 'optionalAccess', _110 => _110.headers]);
2065
+ if (!headers) return void 0;
2066
+ if (typeof headers.get === "function") {
2067
+ return _nullishCoalesce(headers.get(name), () => ( void 0));
2068
+ }
2069
+ const value = headers[name.toLowerCase()];
2070
+ if (Array.isArray(value)) return value[0] === void 0 ? void 0 : String(value[0]);
2071
+ return value === void 0 || value === null ? void 0 : String(value);
2072
+ }
2073
+ function enrichUserAgent() {
2074
+ return (event, { req }) => {
2075
+ const ua = headerOf(req, "user-agent");
2076
+ if (!ua) return;
2077
+ const info = _chunkP4VRTFAVcjs.parseUserAgent.call(void 0, ua);
2078
+ if (info.browser) event.attributes["user_agent.browser"] = info.browser;
2079
+ if (info.os) event.attributes["user_agent.os"] = info.os;
2080
+ event.attributes["user_agent.device"] = info.device;
2081
+ event.attributes["user_agent.bot"] = info.bot;
2082
+ };
2083
+ }
2084
+ function enrichRequestSize() {
2085
+ return (event, { req, res }) => {
2086
+ const request = Number(headerOf(req, "content-length"));
2087
+ if (Number.isFinite(request) && request >= 0)
2088
+ event.attributes["http.request.body.size"] = request;
2089
+ const raw = _optionalChain([res, 'optionalAccess', _111 => _111.getHeader, 'optionalCall', _112 => _112(
2090
+ "content-length"
2091
+ )]);
2092
+ const response = Number(raw);
2093
+ if (raw !== void 0 && Number.isFinite(response) && response >= 0)
2094
+ event.attributes["http.response.body.size"] = response;
2095
+ };
2096
+ }
2097
+ var COUNTRY_HEADERS = [
2098
+ "cf-ipcountry",
2099
+ "x-vercel-ip-country",
2100
+ "cloudfront-viewer-country",
2101
+ "x-country-code",
2102
+ "fastly-geo-country-code"
2103
+ ];
2104
+ function enrichEdgeGeo() {
2105
+ return (event, { req }) => {
2106
+ for (const name of COUNTRY_HEADERS) {
2107
+ const value = _optionalChain([headerOf, 'call', _113 => _113(req, name), 'optionalAccess', _114 => _114.trim, 'call', _115 => _115(), 'access', _116 => _116.toUpperCase, 'call', _117 => _117()]);
2108
+ if (value && /^[A-Z]{2}$/.test(value) && value !== "XX" && value !== "T1") {
2109
+ event.attributes["geo.country.iso_code"] = value;
2110
+ return;
2111
+ }
2112
+ }
2113
+ };
2114
+ }
2115
+ var REGION_VARS = [
2116
+ "AUTTER_REGION",
2117
+ "AWS_REGION",
2118
+ "VERCEL_REGION",
2119
+ "FLY_REGION",
2120
+ "RAILWAY_REPLICA_REGION",
2121
+ "GOOGLE_CLOUD_REGION",
2122
+ "CLOUD_RUN_REGION",
2123
+ "RENDER_REGION",
2124
+ "AZURE_REGION"
2125
+ ];
2126
+ var COMMIT_VARS = [
2127
+ "AUTTER_COMMIT",
2128
+ "GIT_SHA",
2129
+ "GIT_COMMIT",
2130
+ "COMMIT_SHA",
2131
+ "SOURCE_COMMIT",
2132
+ "VERCEL_GIT_COMMIT_SHA",
2133
+ "GITHUB_SHA",
2134
+ "RENDER_GIT_COMMIT",
2135
+ "RAILWAY_GIT_COMMIT_SHA",
2136
+ "CF_PAGES_COMMIT_SHA",
2137
+ "HEROKU_SLUG_COMMIT",
2138
+ "SOURCE_VERSION"
2139
+ ];
2140
+ function enrichDeployment(env = process.env) {
2141
+ const pick = (names) => names.map((name) => _optionalChain([env, 'access', _118 => _118[name], 'optionalAccess', _119 => _119.trim, 'call', _120 => _120()])).find((value) => value);
2142
+ const region = _optionalChain([pick, 'call', _121 => _121(REGION_VARS), 'optionalAccess', _122 => _122.slice, 'call', _123 => _123(0, 64)]);
2143
+ const commit = _optionalChain([pick, 'call', _124 => _124(COMMIT_VARS), 'optionalAccess', _125 => _125.slice, 'call', _126 => _126(0, 64)]);
2144
+ return (event) => {
2145
+ if (region) event.attributes["deployment.region"] = region;
2146
+ if (commit) event.attributes["deployment.commit"] = commit;
2147
+ };
2148
+ }
2149
+
2150
+
2151
+
2152
+
2153
+
2154
+
2155
+
2156
+
2157
+
2158
+
2159
+
2160
+
2161
+
2162
+
2163
+
2164
+
2165
+
2166
+
2167
+
2168
+
2169
+
2170
+
2171
+
2172
+
2173
+
2174
+
2175
+
2176
+
2177
+
2178
+
2179
+
2180
+
2181
+
2182
+
2183
+
2184
+
2185
+
2186
+
2187
+
2188
+
2189
+
2190
+
2191
+
2192
+
2193
+
2194
+
2195
+
2196
+
2197
+
2198
+ exports.CODE_PATTERN = _chunkP4VRTFAVcjs.CODE_PATTERN; exports.COMPAT_MANIFEST = _chunkGI47WGRRcjs.COMPAT_MANIFEST; exports.INGESTER_VERSION_HEADER = _chunkGI47WGRRcjs.INGESTER_VERSION_HEADER; exports.RuntimeError = _chunkP4VRTFAVcjs.RuntimeError; exports.SDK_IDENTITY = _chunkGI47WGRRcjs.SDK_IDENTITY; exports.autterErrorResponse = autterErrorResponse; exports.autterFastify = autterFastify; exports.autterRequests = autterRequests; exports.captureException = captureException; exports.captureMessage = captureMessage; exports.consoleSink = _chunkP4VRTFAVcjs.consoleSink; exports.createBrowserRelayFetchHandler = createBrowserRelayFetchHandler; exports.createBrowserRelayHandler = createBrowserRelayHandler; exports.createRuntimeLogger = _chunkP4VRTFAVcjs.createRuntimeLogger; exports.defineRuntimeErrors = _chunkP4VRTFAVcjs.defineRuntimeErrors; exports.emitLlmSelftestTrace = emitLlmSelftestTrace; exports.enrichDeployment = enrichDeployment; exports.enrichEdgeGeo = enrichEdgeGeo; exports.enrichRequestSize = enrichRequestSize; exports.enrichUserAgent = enrichUserAgent; exports.errorAttributes = _chunkP4VRTFAVcjs.errorAttributes; exports.evaluateCompat = _chunkGI47WGRRcjs.evaluateCompat; exports.fetchIngesterCompat = _chunkGI47WGRRcjs.fetchIngesterCompat; exports.fileSink = _chunkP4VRTFAVcjs.fileSink; exports.flushRuntimeLogs = _chunkP4VRTFAVcjs.flushRuntimeLogs; exports.initAutterLogging = initAutterLogging; exports.initAutterServer = initAutterServer; exports.installAutterAutoFlush = _chunkGI47WGRRcjs.installAutterAutoFlush; exports.instrumentLlmClient = instrumentLlmClient; exports.isRuntimeErrorLike = _chunkP4VRTFAVcjs.isRuntimeErrorLike; exports.makeSafeCapture = makeSafeCapture; exports.otlpSink = _chunkP4VRTFAVcjs.otlpSink; exports.redactAttributes = _chunkP4VRTFAVcjs.redactAttributes; exports.redactText = _chunkP4VRTFAVcjs.redactText; exports.reportOutcome = reportOutcome; exports.runDoctor = _chunkL6SRL65Jcjs.runDoctor; exports.runInBackground = _chunkP4VRTFAVcjs.runInBackground; exports.runtimeContext = _chunkP4VRTFAVcjs.runtimeContext; exports.runtimeLogStats = _chunkP4VRTFAVcjs.runtimeLogStats; exports.runtimeLogger = _chunkP4VRTFAVcjs.runtimeLogger; exports.sanitizeBrowserPayload = sanitizeBrowserPayload; exports.startCaughtExceptionSampler = startCaughtExceptionSampler; exports.toClientError = _chunkP4VRTFAVcjs.toClientError; exports.trackLlmCall = trackLlmCall; exports.withLlmCall = withLlmCall; exports.withProcessSpan = withProcessSpan; exports.withRuntimeOperation = _chunkP4VRTFAVcjs.withRuntimeOperation; exports.withRuntimeRequest = withRuntimeRequest;