@autter/runtime-node 1.4.0 → 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,66 +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
- createRuntimeLogger: () => createRuntimeLogger,
38
- emitLlmSelftestTrace: () => emitLlmSelftestTrace,
39
- flushRuntimeLogs: () => flushRuntimeLogs,
40
- initAutterServer: () => initAutterServer,
41
- installAutterAutoFlush: () => installAutterAutoFlush,
42
- instrumentLlmClient: () => instrumentLlmClient,
43
- makeSafeCapture: () => makeSafeCapture,
44
- redactAttributes: () => redactAttributes,
45
- reportOutcome: () => reportOutcome,
46
- runtimeLogStats: () => runtimeLogStats,
47
- runtimeLogger: () => runtimeLogger,
48
- sanitizeBrowserPayload: () => sanitizeBrowserPayload,
49
- startCaughtExceptionSampler: () => startCaughtExceptionSampler,
50
- trackLlmCall: () => trackLlmCall,
51
- withLlmCall: () => withLlmCall,
52
- withProcessSpan: () => withProcessSpan,
53
- withRuntimeOperation: () => withRuntimeOperation
54
- });
55
- module.exports = __toCommonJS(index_exports);
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2;
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+ 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');
56
66
 
57
67
  // src/relay.ts
58
- var IpWindow = class {
59
- constructor(limitPerMinute) {
68
+ var IpWindow = (_class = class {
69
+ constructor(limitPerMinute) {;_class.prototype.__init.call(this);
60
70
  this.limitPerMinute = limitPerMinute;
61
71
  }
62
- limitPerMinute;
63
- windows = /* @__PURE__ */ new Map();
72
+
73
+ __init() {this.windows = /* @__PURE__ */ new Map()}
64
74
  allow(ip) {
65
75
  const start = Math.floor(Date.now() / 6e4) * 6e4;
66
76
  const entry = this.windows.get(ip);
@@ -72,10 +82,10 @@ var IpWindow = class {
72
82
  entry.count += 1;
73
83
  return entry.count <= this.limitPerMinute;
74
84
  }
75
- };
76
- function firstForwardedFor(value2) {
77
- const raw = Array.isArray(value2) ? value2[0] : value2;
78
- return raw ? (raw.split(",")[0] ?? "").trim() : "";
85
+ }, _class);
86
+ function firstForwardedFor(value) {
87
+ const raw = Array.isArray(value) ? value[0] : value;
88
+ return raw ? (_nullishCoalesce(raw.split(",")[0], () => ( ""))).trim() : "";
79
89
  }
80
90
  var DEFAULT_ENDPOINT = "https://otlp.autter.dev";
81
91
  var DEFAULT_MAX_BODY = 64 * 1024;
@@ -92,7 +102,120 @@ var EVENT_TYPES = /* @__PURE__ */ new Set([
92
102
  "timing"
93
103
  ]);
94
104
  var SEVERITIES = /* @__PURE__ */ new Set(["fatal", "error", "warning", "info"]);
95
- 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) {
96
219
  if (typeof raw !== "object" || raw === null) return null;
97
220
  const p = raw;
98
221
  if (p.version !== 1) return null;
@@ -109,16 +232,16 @@ function sanitizeBrowserPayload(raw) {
109
232
  type: e.type,
110
233
  timestamp: e.timestamp,
111
234
  ...typeof e.severity === "string" && SEVERITIES.has(e.severity) ? { severity: e.severity } : {},
112
- message: typeof e.message === "string" ? e.message.slice(0, 4e3) : "",
113
- ...typeof e.name === "string" ? { name: e.name.slice(0, 200) } : {},
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) } : {},
114
237
  ...typeof e.durationMs === "number" && Number.isFinite(e.durationMs) ? { durationMs: Math.max(0, Math.min(12e4, e.durationMs)) } : {},
115
- ...typeof e.stack === "string" ? { stack: e.stack.slice(0, 32e3) } : {},
238
+ ...typeof e.stack === "string" ? { stack: redactor.text(e.stack.slice(0, 32512)).slice(0, 32e3) } : {},
116
239
  ...typeof e.errorType === "string" ? { errorType: e.errorType.slice(0, 200) } : {},
117
240
  ...typeof e.filename === "string" ? { filename: e.filename.split("?")[0].slice(0, 1e3) } : {},
118
241
  ...typeof e.line === "number" ? { line: e.line } : {},
119
242
  ...typeof e.column === "number" ? { column: e.column } : {},
120
243
  ...typeof e.route === "string" ? { route: e.route.split("?")[0].slice(0, 1e3) } : {},
121
- ...typeof e.context === "object" && e.context !== null ? { context: e.context } : {}
244
+ ...typeof e.context === "object" && e.context !== null ? relayContext(e.context, redactor) : {}
122
245
  });
123
246
  }
124
247
  return {
@@ -127,11 +250,16 @@ function sanitizeBrowserPayload(raw) {
127
250
  service: p.service.slice(0, 200),
128
251
  environment: p.environment.slice(0, 100),
129
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 } : {},
130
255
  events
131
256
  };
132
257
  }
133
258
  function forward(payload, opts) {
134
- 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);
135
263
  void fetch(url, {
136
264
  method: "POST",
137
265
  headers: {
@@ -140,15 +268,24 @@ function forward(payload, opts) {
140
268
  },
141
269
  body: JSON.stringify(payload),
142
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);
143
279
  }).catch((err) => {
144
- (opts.onError ?? ((e) => console.warn("autter relay forward failed:", e)))(
280
+ (_nullishCoalesce(opts.onError, () => ( ((e) => console.warn("autter relay forward failed:", e)))))(
145
281
  err
146
282
  );
147
283
  });
148
284
  }
149
285
  function createBrowserRelayFetchHandler(opts) {
150
- const maxBody = opts.maxBodyBytes ?? DEFAULT_MAX_BODY;
151
- 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)));
152
289
  return async (request) => {
153
290
  if (request.method !== "POST") {
154
291
  return new Response(null, { status: 405 });
@@ -161,21 +298,28 @@ function createBrowserRelayFetchHandler(opts) {
161
298
  });
162
299
  }
163
300
  }
164
- const text = await request.text();
165
- 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) {
166
310
  return new Response(JSON.stringify({ error: "payload too large" }), {
167
311
  status: 413
168
312
  });
169
313
  }
170
314
  let raw;
171
315
  try {
172
- raw = JSON.parse(text);
173
- } catch {
316
+ raw = JSON.parse(bounded.text);
317
+ } catch (e9) {
174
318
  return new Response(JSON.stringify({ error: "invalid json" }), {
175
319
  status: 400
176
320
  });
177
321
  }
178
- const payload = sanitizeBrowserPayload(raw);
322
+ const payload = sanitizeBrowserPayload(raw, redactor);
179
323
  if (!payload) {
180
324
  return new Response(JSON.stringify({ error: "invalid payload" }), {
181
325
  status: 400
@@ -186,8 +330,9 @@ function createBrowserRelayFetchHandler(opts) {
186
330
  };
187
331
  }
188
332
  function createBrowserRelayHandler(opts) {
189
- const maxBody = opts.maxBodyBytes ?? DEFAULT_MAX_BODY;
190
- 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)));
191
336
  function respond(res, status, body) {
192
337
  res.statusCode = status;
193
338
  if (body) {
@@ -198,7 +343,7 @@ function createBrowserRelayHandler(opts) {
198
343
  }
199
344
  }
200
345
  function handleParsed(raw, res) {
201
- const payload = sanitizeBrowserPayload(raw);
346
+ const payload = sanitizeBrowserPayload(raw, redactor);
202
347
  if (!payload) {
203
348
  respond(res, 400, { error: "invalid payload" });
204
349
  return;
@@ -212,7 +357,7 @@ function createBrowserRelayHandler(opts) {
212
357
  return;
213
358
  }
214
359
  if (limiter) {
215
- 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";
216
361
  if (!limiter.allow(ip)) {
217
362
  respond(res, 429, { error: "rate limit exceeded" });
218
363
  return;
@@ -223,7 +368,7 @@ function createBrowserRelayHandler(opts) {
223
368
  if (typeof raw === "string" || Buffer.isBuffer(raw)) {
224
369
  try {
225
370
  raw = JSON.parse(raw.toString());
226
- } catch {
371
+ } catch (e10) {
227
372
  respond(res, 400, { error: "invalid json" });
228
373
  return;
229
374
  }
@@ -248,7 +393,7 @@ function createBrowserRelayHandler(opts) {
248
393
  if (aborted) return;
249
394
  try {
250
395
  handleParsed(JSON.parse(Buffer.concat(chunks).toString()), res);
251
- } catch {
396
+ } catch (e11) {
252
397
  respond(res, 400, { error: "invalid json" });
253
398
  }
254
399
  });
@@ -259,466 +404,162 @@ function createBrowserRelayHandler(opts) {
259
404
  }
260
405
 
261
406
  // src/server.ts
262
- var import_node_http = require("http");
263
- var import_node_crypto2 = require("crypto");
264
- var import_api3 = require("@opentelemetry/api");
265
- var import_core2 = require("@opentelemetry/core");
266
- var import_exporter_metrics_otlp_http = require("@opentelemetry/exporter-metrics-otlp-http");
267
- var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
268
- var import_instrumentation_http = require("@opentelemetry/instrumentation-http");
269
- var import_resources = require("@opentelemetry/resources");
270
- var import_sdk_metrics = require("@opentelemetry/sdk-metrics");
271
- var import_sdk_node = require("@opentelemetry/sdk-node");
272
- var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
273
- var import_semantic_conventions = require("@opentelemetry/semantic-conventions");
274
-
275
- // src/lifecycle.ts
276
- var import_core = require("@opentelemetry/core");
277
- var debugEnabled = process.env.AUTTER_DEBUG === "1" || process.env.AUTTER_DEBUG === "true";
278
- function setDebugMode(enabled) {
279
- debugEnabled = enabled;
280
- }
281
- function isDebugEnabled() {
282
- return debugEnabled;
283
- }
284
- function debugLog(...args) {
285
- if (debugEnabled) {
286
- console.error("[autter]", ...args);
287
- }
288
- }
289
- var TelemetryStats = class {
290
- /** Captures queued via our APIs and not yet seen leaving an exporter. */
291
- pendingCaptures = 0;
292
- markCaptured(count = 1) {
293
- this.pendingCaptures += count;
294
- }
295
- /** An exporter batch left the process successfully. */
296
- onExported(spanCount) {
297
- this.pendingCaptures = Math.max(0, this.pendingCaptures - spanCount);
298
- if (debugEnabled && spanCount > 0) {
299
- debugLog(`exported ${spanCount} span${spanCount === 1 ? "" : "s"}`);
300
- }
301
- }
302
- markAllFlushed() {
303
- this.pendingCaptures = 0;
304
- }
305
- };
306
- var telemetryStats = new TelemetryStats();
307
- var CountingExporter = class {
308
- constructor(inner) {
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) {
309
483
  this.inner = inner;
484
+ this.redactor = redactor;
310
485
  }
311
- inner;
486
+
487
+
312
488
  export(spans, resultCallback) {
313
- this.inner.export(spans, (result) => {
314
- if (result.code === import_core.ExportResultCode.SUCCESS) {
315
- 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
+ }
316
500
  }
317
- resultCallback(result);
318
- });
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
+ );
319
516
  }
320
517
  shutdown() {
321
518
  return this.inner.shutdown();
322
519
  }
323
520
  forceFlush() {
324
- return this.inner.forceFlush?.() ?? Promise.resolve();
521
+ return _nullishCoalesce(_optionalChain([this, 'access', _3 => _3.inner, 'access', _4 => _4.forceFlush, 'optionalCall', _5 => _5()]), () => ( Promise.resolve()));
325
522
  }
326
523
  };
327
- var flushTargets = /* @__PURE__ */ new Map();
328
- function registerFlushTarget(key, target) {
329
- flushTargets.set(key, target);
330
- }
331
- function unregisterFlushTargets() {
332
- flushTargets.clear();
333
- }
334
- function activeFlushTargets() {
335
- return [...flushTargets.values()];
336
- }
337
- var DEFAULT_SIGNALS = ["SIGINT", "SIGTERM"];
338
- var SIGNAL_EXIT_CODES = {
339
- SIGINT: 130,
340
- SIGTERM: 143
341
- };
342
- function installAutterAutoFlush(options = {}) {
343
- const logger = options.logger ?? console;
344
- const log = options.log !== false;
345
- const warnOnUnflushedExit = options.warnOnUnflushedExit !== false;
346
- const timeoutMs = Math.max(100, options.timeoutMs ?? 3e3);
347
- const signals = options.signals ?? DEFAULT_SIGNALS;
348
- const flushOnUncaughtException = options.flushOnUncaughtException !== false;
349
- let disposed = false;
350
- let inFlight2 = null;
351
- const doFlush = async () => {
352
- const targets = options.targets ?? activeFlushTargets();
353
- if (targets.length === 0) return true;
354
- let timer2;
355
- const timedOut = new Promise((resolve) => {
356
- timer2 = setTimeout(() => resolve(false), timeoutMs);
357
- });
358
- const drained = Promise.allSettled(
359
- targets.map(
360
- (target) => Promise.resolve().then(() => target.forceFlush())
361
- )
362
- ).then(
363
- (results) => results.every((result) => result.status === "fulfilled")
364
- );
365
- let ok;
366
- try {
367
- ok = await Promise.race([drained, timedOut]);
368
- } finally {
369
- clearTimeout(timer2);
370
- }
371
- if (ok) {
372
- telemetryStats.markAllFlushed();
373
- if (log) {
374
- logger.log("[autter] telemetry flushed");
375
- }
376
- } else {
377
- logger.error(
378
- `[autter] flush did not finish within ${timeoutMs}ms \u2014 some telemetry may be lost`
379
- );
380
- }
381
- return ok;
382
- };
383
- const flush = (reason = "exit") => {
384
- if (disposed) return Promise.resolve(false);
385
- if (!inFlight2) {
386
- inFlight2 = doFlush().finally(() => {
387
- inFlight2 = null;
388
- });
389
- }
390
- if (isDebugEnabled()) debugLog(`auto-flush requested on ${reason}`);
391
- return inFlight2;
392
- };
393
- const signalCounts = /* @__PURE__ */ new Map();
394
- let handlingUncaughtException = false;
395
- const onUncaughtException = (error) => {
396
- if (process.listenerCount("uncaughtException") > 1) return;
397
- if (handlingUncaughtException) return;
398
- handlingUncaughtException = true;
399
- logger.error(error instanceof Error ? error.stack ?? error.message : String(error));
400
- const keepAlive = setTimeout(() => {
401
- }, timeoutMs + 50);
402
- void flush("uncaughtException").finally(() => {
403
- clearTimeout(keepAlive);
404
- process.exit(1);
405
- });
406
- };
407
- const onSignal = (signal) => {
408
- const count = (signalCounts.get(signal) ?? 0) + 1;
409
- signalCounts.set(signal, count);
410
- const exitCode = SIGNAL_EXIT_CODES[signal] ?? 1;
411
- if (count > 1) {
412
- process.exit(exitCode);
413
- }
414
- const otherHandlers = process.listenerCount(signal) - 1;
415
- if (otherHandlers > 0) {
416
- void flush(signal);
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);
417
535
  return;
418
536
  }
419
- void flush(signal).finally(() => {
420
- process.exit(exitCode);
421
- });
422
- };
423
- const MAX_BEFORE_EXIT_FLUSHES = 10;
424
- let beforeExitFlushes = 0;
425
- const onBeforeExit = () => {
426
- if (disposed) return;
427
- const targets = options.targets ?? activeFlushTargets();
428
- const worthIt = beforeExitFlushes === 0 ? targets.length > 0 : telemetryStats.pendingCaptures > 0;
429
- if (!worthIt || beforeExitFlushes >= MAX_BEFORE_EXIT_FLUSHES) return;
430
- beforeExitFlushes++;
431
- const keepAlive = setTimeout(() => {
432
- }, timeoutMs);
433
- void flush("beforeExit").finally(() => clearTimeout(keepAlive));
434
- };
435
- const onExit = () => {
436
- if (!warnOnUnflushedExit || disposed) return;
437
- const pending = telemetryStats.pendingCaptures;
438
- if (pending > 0) {
439
- logger.error(
440
- `[autter] process exiting with ~${pending} captured item(s) never confirmed exported \u2014 await autter.shutdown() on graceful shutdown`
441
- );
442
- }
443
- };
444
- const signalHandlers = /* @__PURE__ */ new Map();
445
- process.on("beforeExit", onBeforeExit);
446
- if (flushOnUncaughtException) {
447
- process.on("uncaughtException", onUncaughtException);
448
- }
449
- for (const signal of signals) {
450
- const handler = () => onSignal(signal);
451
- signalHandlers.set(signal, handler);
452
- process.on(signal, handler);
453
- }
454
- process.on("exit", onExit);
455
- return {
456
- flush,
457
- dispose() {
458
- disposed = true;
459
- process.removeListener("beforeExit", onBeforeExit);
460
- process.removeListener("uncaughtException", onUncaughtException);
461
- process.removeListener("exit", onExit);
462
- for (const [signal, handler] of signalHandlers) {
463
- process.removeListener(signal, handler);
464
- }
465
- signalHandlers.clear();
466
- }
467
- };
468
- }
469
-
470
- // src/redact.ts
471
- var SENSITIVE_KEY_PATTERNS = [
472
- /e-?mail/,
473
- /pass(word|wd|phrase)|^pass$/,
474
- /token/,
475
- /secret/,
476
- /credential/,
477
- /(api|access|secret|private|consumer|client|signing|encryption)-?[_.]?key/,
478
- /^-?x?-?authorization$|^auth(-|_|$)|bearer/,
479
- /cookie/,
480
- /phone|msisdn/,
481
- /\bssn\b|social[-_ ]?security/,
482
- /cvv|cvc|card([-_. ]?(number|num|no))?$/,
483
- /credit[-_.]?card/,
484
- /connection[-_.]?string/,
485
- /recovery[-_.]?code|\botp\b|magic[-_.]?link/
486
- ];
487
- var PRIVATE_KEY_BLOCK_RE = /-----BEGIN [A-Z ]*PRIVATE KEY-----[\s\S]*?(?:-----END [A-Z ]*PRIVATE KEY-----|$)/g;
488
- var EMAIL_VALUE_RE = /[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi;
489
- var JWT_RE = /\beyJ[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\.[A-Za-z0-9_-]{8,}\b/g;
490
- var OPENAI_KEY_RE = /\bsk-[A-Za-z0-9]{20,}\b/g;
491
- var GITHUB_TOKEN_RE = /\bgh[pousr]_[A-Za-z0-9]{20,}\b/g;
492
- var AWS_KEY_RE = /\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/g;
493
- var SLACK_TOKEN_RE = /\bxox[baprs]-[A-Za-z0-9-]{10,}\b/g;
494
- var BEARER_RE = /\bbearer\s+[A-Za-z0-9._~+/=-]{10,}/gi;
495
- var URL_CREDENTIALS_RE = /\b([a-z][a-z0-9+.-]*:\/\/)[^\s/:@]+:[^\s/@]+@/gi;
496
- function toCaseInsensitive(pattern) {
497
- return typeof pattern === "string" ? new RegExp(pattern.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"), "i") : new RegExp(pattern.source, pattern.flags.includes("i") ? pattern.flags : `${pattern.flags}i`);
498
- }
499
- function compile(options) {
500
- const keyPatterns = [...SENSITIVE_KEY_PATTERNS];
501
- const valuePatterns = [
502
- JWT_RE,
503
- OPENAI_KEY_RE,
504
- GITHUB_TOKEN_RE,
505
- AWS_KEY_RE,
506
- SLACK_TOKEN_RE,
507
- BEARER_RE
508
- ];
509
- if (options?.additionalKeyPatterns) {
510
- for (const p of options.additionalKeyPatterns) {
511
- keyPatterns.push(toCaseInsensitive(p));
512
- }
513
- }
514
- if (options?.additionalValuePatterns) {
515
- for (const p of options.additionalValuePatterns) {
516
- if (!valuePatterns.some((existing) => existing.source === (typeof p === "string" ? p : p.source))) {
517
- valuePatterns.push(typeof p === "string" ? new RegExp(p, "gi") : p);
518
- }
519
- }
520
- }
521
- return {
522
- keyPatterns,
523
- valuePatterns,
524
- urlCredentials: URL_CREDENTIALS_RE,
525
- privateKeyBlock: PRIVATE_KEY_BLOCK_RE,
526
- mask: options?.mask ?? "[redacted]",
527
- scrubEmailValues: options?.scrubEmailValues !== false
528
- };
529
- }
530
- function redactString(value2, r) {
531
- let out = value2.replace(r.privateKeyBlock, r.mask);
532
- for (const re of r.valuePatterns) {
533
- out = out.replace(re, r.mask);
534
- }
535
- out = out.replace(r.urlCredentials, "$1" + r.mask + "@");
536
- if (r.scrubEmailValues) {
537
- out = out.replace(EMAIL_VALUE_RE, r.mask);
538
- }
539
- return out;
540
- }
541
- var MAX_REDACTION_DEPTH = 64;
542
- var MAX_REDACTION_WORK = 1e4;
543
- var MAX_COLLECTION_ENTRIES = 1e3;
544
- function canTraverse(depth, state) {
545
- if (depth > MAX_REDACTION_DEPTH || state.remainingWork <= 0) return false;
546
- state.remainingWork -= 1;
547
- return true;
548
- }
549
- function redactValue(value2, r, state, depth) {
550
- if (typeof value2 === "string") return redactString(value2, r);
551
- let isArray = false;
552
- try {
553
- isArray = Array.isArray(value2);
554
- } catch {
555
- return r.mask;
556
- }
557
- if (isArray) {
558
- return redactArray(value2, r, state, depth);
559
- }
560
- if (typeof value2 === "object" && value2 !== null) {
561
- return redactObject(value2, r, state, depth);
562
- }
563
- return value2;
564
- }
565
- function redactArray(value2, r, state, depth) {
566
- const existing = state.ancestors.get(value2);
567
- if (existing) return r.mask;
568
- if (!canTraverse(depth, state)) return r.mask;
569
- const out = [];
570
- state.ancestors.set(value2, out);
571
- let length;
572
- try {
573
- length = value2.length;
574
- } catch {
575
- state.ancestors.delete(value2);
576
- return r.mask;
577
- }
578
- const limit = Math.min(length, MAX_COLLECTION_ENTRIES);
579
- for (let i = 0; i < limit; i += 1) {
580
- let item;
537
+ let resource;
581
538
  try {
582
- item = value2[i];
583
- } catch {
584
- out.push(r.mask);
585
- continue;
586
- }
587
- out.push(redactValue(item, r, state, depth + 1));
588
- }
589
- if (length > limit) {
590
- out.push(r.mask);
591
- }
592
- state.ancestors.delete(value2);
593
- return out;
594
- }
595
- function redactObject(value2, r, state, depth) {
596
- const existing = state.ancestors.get(value2);
597
- if (existing) return r.mask;
598
- if (!canTraverse(depth, state)) return r.mask;
599
- const out = {};
600
- state.ancestors.set(value2, out);
601
- let count = 0;
602
- let truncated = false;
603
- try {
604
- for (const key in value2) {
605
- if (!Object.prototype.propertyIsEnumerable.call(
606
- value2,
607
- key
608
- )) {
609
- continue;
610
- }
611
- if (count >= MAX_COLLECTION_ENTRIES) {
612
- truncated = true;
613
- break;
614
- }
615
- let nestedValue;
616
- try {
617
- nestedValue = value2[key];
618
- } catch {
619
- out[key] = r.mask;
620
- count += 1;
621
- continue;
622
- }
623
- count += 1;
624
- out[key] = isSensitiveKey(key, nestedValue, r) ? r.mask : redactValue(
625
- nestedValue,
626
- r,
627
- state,
628
- depth + 1
629
- );
630
- }
631
- } catch {
632
- truncated = true;
633
- }
634
- if (truncated) {
635
- out.__redaction_truncated__ = r.mask;
636
- }
637
- state.ancestors.delete(value2);
638
- return out;
639
- }
640
- var USAGE_TOKEN_KEYS = /* @__PURE__ */ new Set([
641
- "input_tokens",
642
- "output_tokens",
643
- "prompt_tokens",
644
- "completion_tokens",
645
- "total_tokens",
646
- "token_count",
647
- "gen_ai.usage.input_tokens",
648
- "gen_ai.usage.output_tokens",
649
- "gen_ai.usage.prompt_tokens",
650
- "gen_ai.usage.completion_tokens",
651
- "gen_ai.usage.total_tokens",
652
- "gen_ai.usage.token_count"
653
- ]);
654
- function isSensitiveKey(key, value2, r) {
655
- const lowered = key.toLowerCase();
656
- if (USAGE_TOKEN_KEYS.has(lowered)) {
657
- return !(typeof value2 === "number" && Number.isFinite(value2) && value2 >= 0);
658
- }
659
- return r.keyPatterns.some((re) => re.test(lowered));
660
- }
661
- function redactAttributes(attributes, options) {
662
- const r = compile(options);
663
- return redactWith(attributes, r);
664
- }
665
- function redactWith(attributes, r) {
666
- const out = {};
667
- if (!attributes) return out;
668
- const state = {
669
- ancestors: /* @__PURE__ */ new WeakMap(),
670
- remainingWork: MAX_REDACTION_WORK
671
- };
672
- let count = 0;
673
- let truncated = false;
674
- try {
675
- for (const key in attributes) {
676
- if (!Object.prototype.propertyIsEnumerable.call(
677
- attributes,
678
- key
679
- )) {
680
- continue;
681
- }
682
- if (count >= MAX_COLLECTION_ENTRIES || state.remainingWork <= 0) {
683
- truncated = true;
684
- break;
685
- }
686
- let value2;
687
- try {
688
- value2 = attributes[key];
689
- } catch {
690
- out[key] = r.mask;
691
- count += 1;
692
- state.remainingWork -= 1;
693
- continue;
694
- }
695
- count += 1;
696
- state.remainingWork -= 1;
697
- if (value2 === void 0) continue;
698
- out[key] = isSensitiveKey(key, value2, r) ? r.mask : redactValue(value2, r, state, 0);
539
+ resource = redactResource(metrics2.resource, redactor);
540
+ } catch (error) {
541
+ resultCallback({ code: _core.ExportResultCode.FAILED, error });
542
+ return;
699
543
  }
700
- } catch {
701
- truncated = true;
544
+ this.inner.export({ ...metrics2, resource }, resultCallback);
702
545
  }
703
- if (truncated) {
704
- out.__redaction_truncated__ = r.mask;
546
+ forceFlush() {
547
+ return this.inner.forceFlush();
705
548
  }
706
- return out;
707
- }
708
- function makeRedactor(options) {
709
- if (options === false) {
710
- return (attributes) => ({ ...attributes ?? {} });
549
+ shutdown() {
550
+ return this.inner.shutdown();
711
551
  }
712
- const r = compile(options === true ? void 0 : options);
713
- return (attributes) => redactWith(attributes, r);
714
- }
552
+ selectAggregationTemporality(instrumentType) {
553
+ return this.inner.selectAggregationTemporality ? this.inner.selectAggregationTemporality(instrumentType) : _sdkmetrics.AggregationTemporality.CUMULATIVE;
554
+ }
555
+ };
715
556
 
716
557
  // src/memory.ts
717
- var import_node_perf_hooks = require("perf_hooks");
718
- var import_node_v8 = require("v8");
719
- var import_api = require("@opentelemetry/api");
558
+ var _perf_hooks = require('perf_hooks');
559
+ var _v8 = require('v8');
560
+
720
561
  function startMemoryMetrics() {
721
- const meter = import_api.metrics.getMeter("autter-process-memory");
562
+ const meter = _api.metrics.getMeter("autter-process-memory");
722
563
  const rss = meter.createObservableGauge("autter.process.memory.rss", { unit: "By" });
723
564
  const heapUsed = meter.createObservableGauge("autter.process.memory.heap.used", { unit: "By" });
724
565
  const heapLimit = meter.createObservableGauge("autter.process.memory.heap.limit", { unit: "By" });
@@ -732,9 +573,9 @@ function startMemoryMetrics() {
732
573
  const callbacks = [
733
574
  [rss, (result) => result.observe(process.memoryUsage().rss)],
734
575
  [heapUsed, (result) => result.observe(process.memoryUsage().heapUsed)],
735
- [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)],
736
577
  [containerLimit, (result) => {
737
- const constrained = process.constrainedMemory?.() ?? 0;
578
+ const constrained = _nullishCoalesce(_optionalChain([process, 'access', _6 => _6.constrainedMemory, 'optionalCall', _7 => _7()]), () => ( 0));
738
579
  if (constrained > 0) result.observe(constrained);
739
580
  }],
740
581
  [afterGc, (result) => {
@@ -744,7 +585,7 @@ function startMemoryMetrics() {
744
585
  [gcDuration, (result) => result.observe(durationMs)]
745
586
  ];
746
587
  for (const [instrument, callback] of callbacks) instrument.addCallback(callback);
747
- const observer = new import_node_perf_hooks.PerformanceObserver((list) => {
588
+ const observer = new (0, _perf_hooks.PerformanceObserver)((list) => {
748
589
  for (const entry of list.getEntries()) {
749
590
  collections++;
750
591
  durationMs += entry.duration;
@@ -758,388 +599,381 @@ function startMemoryMetrics() {
758
599
  };
759
600
  }
760
601
 
761
- // src/logger.ts
762
- var import_node_async_hooks = require("async_hooks");
763
- var import_node_crypto = require("crypto");
764
- var import_api2 = require("@opentelemetry/api");
765
- var local = new import_node_async_hooks.AsyncLocalStorage();
766
- var config = null;
767
- var queue = [];
768
- var queueBytes = 0;
769
- var inFlightBytes = 0;
770
- var timer;
771
- var flushing = null;
772
- var dropped = 0;
773
- var inFlight = 0;
774
- var stopping = false;
775
- var failureStreak = 0;
776
- var severity = { debug: 5, info: 9, warning: 13, error: 17 };
777
- function safe(attributes = {}) {
778
- const redacted = config?.redact(attributes) ?? redactAttributes(attributes);
779
- let budget = 512;
780
- let characters = 16384;
781
- let truncated = false;
782
- const visit = (input, depth) => {
783
- if (--budget < 0 || depth > 6) {
784
- truncated = true;
785
- return "[truncated]";
786
- }
787
- if (typeof input === "string") {
788
- const text = input.replace(/(https?:\/\/[^\s?#]+)[?#][^\s]*/gi, "$1");
789
- const kept = text.slice(0, Math.max(0, characters));
790
- truncated ||= kept.length < text.length;
791
- characters -= kept.length;
792
- return kept;
793
- }
794
- if (typeof input === "number")
795
- return Number.isFinite(input) ? input : void 0;
796
- if (typeof input === "boolean" || input === null) return input;
797
- if (Array.isArray(input)) {
798
- truncated ||= input.length > 64;
799
- return input.slice(0, 64).map((item) => visit(item, depth + 1));
800
- }
801
- if (input && typeof input === "object") {
802
- const entries = Object.entries(input);
803
- if (depth === 0) {
804
- const priority = (key) => /^autter\.(?:operation|event)\./.test(key) ? 2 : /^exception\./.test(key) ? 1 : 0;
805
- entries.sort(([a], [b]) => priority(b) - priority(a));
806
- }
807
- truncated ||= entries.length > 100;
808
- return Object.fromEntries(
809
- entries.slice(0, 100).filter(([key]) => !/^(?:__proto__|constructor|prototype)$/.test(key)).map(([key, item]) => [key.slice(0, 200), visit(item, depth + 1)])
810
- );
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);
811
654
  }
812
- return void 0;
655
+ return wrapped;
813
656
  };
814
- const result = visit(redacted, 0);
815
- if (truncated) result["autter.context.truncated"] = true;
816
- return result;
817
- }
818
- function operationAttributes(state) {
819
- return state ? {
820
- "autter.operation.id": state.id,
821
- "autter.operation.name": state.name,
822
- ...state.parentId ? { "autter.operation.parent_id": state.parentId } : {},
823
- ...state.attributes
824
- } : {};
825
- }
826
- function userAttributes(attributes = {}) {
827
- return Object.fromEntries(
828
- Object.entries(safe(attributes)).filter(
829
- ([key]) => !/^autter\.(?:operation|event)\./.test(key)
830
- )
831
- );
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
+ }
832
678
  }
833
- function mergeContext(current, next = {}) {
834
- const merge = (left, right, depth) => {
835
- const result = { ...left };
836
- for (const [key, value2] of Object.entries(right)) {
837
- const prior = result[key];
838
- result[key] = depth < 6 && value2 && typeof value2 === "object" && !Array.isArray(value2) && prior && typeof prior === "object" && !Array.isArray(prior) ? merge(prior, value2, depth + 1) : value2;
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) {
839
704
  }
840
- return result;
705
+ return original.apply(this, args);
841
706
  };
842
- return userAttributes(merge(current, userAttributes(next), 0));
843
- }
844
- function traceAttributes(state) {
845
- return Object.fromEntries(
846
- Object.entries(operationAttributes(state)).filter(([, item]) => item !== null && item !== void 0).map(([key, item]) => [
847
- key,
848
- typeof item === "object" ? JSON.stringify(item) : item
849
- ])
850
- );
851
707
  }
852
- function scheduleFlush() {
853
- if (!timer && config && !stopping && queue.length) {
854
- timer = setTimeout(
855
- () => {
856
- timer = void 0;
857
- void flushRuntimeLogs().catch(() => {
858
- });
859
- },
860
- Math.min(3e4, 2e3 * 2 ** Math.min(failureStreak, 4))
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)
861
729
  );
862
- timer.unref();
863
- }
864
- }
865
- function value(input) {
866
- if (typeof input === "number") return { doubleValue: input };
867
- if (typeof input === "boolean") return { boolValue: input };
868
- if (Array.isArray(input))
869
- return { arrayValue: { values: input.slice(0, 64).map(value) } };
870
- if (input && typeof input === "object")
871
- return {
872
- kvlistValue: {
873
- values: Object.entries(input).slice(0, 128).map(([key, item]) => ({ key, value: value(item) }))
874
- }
875
- };
876
- return { stringValue: String(input ?? "").slice(0, 32e3) };
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
+ });
877
740
  }
878
- function emit(level, message, attributes, extra = {}) {
879
- const state = local.getStore();
880
- if (state?.sealed) return;
881
- if (extra["autter.event.type"] !== "operation" && severity[level] < severity[config?.options?.minLevel ?? "debug"])
882
- return;
883
- const span = import_api2.trace.getActiveSpan()?.spanContext();
884
- const user = mergeContext(state?.attributes ?? {}, attributes);
885
- const exceptions = Object.fromEntries(
886
- Object.entries(user).filter(([key]) => key.startsWith("exception."))
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]
887
745
  );
888
- const attrs = safe({
889
- "autter.event.id": (0, import_node_crypto.randomUUID)(),
890
- ...extra,
891
- ...exceptions,
892
- ...operationAttributes(state),
893
- ...user
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
894
753
  });
895
- const record = {
896
- timeUnixNano: String(BigInt(Date.now()) * 1000000n),
897
- severityNumber: severity[level],
898
- severityText: level.toUpperCase(),
899
- body: value(String(safe({ message }).message ?? "").slice(0, 4e3)),
900
- attributes: Object.entries(attrs).map(([key, item]) => ({
901
- key,
902
- value: value(item)
903
- })),
904
- ...span && /^[a-f0-9]{32}$/.test(span.traceId) && !/^0+$/.test(span.traceId) ? { traceId: span.traceId, spanId: span.spanId } : {}
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
+ });
905
778
  };
906
- if (config?.options?.console !== false)
907
- console.log(
908
- JSON.stringify({ ...attrs, level, message: record.body.stringValue })
909
- );
910
- if (!config) return;
911
- if (stopping) {
912
- dropped++;
913
- return;
914
- }
915
- const bytes = Buffer.byteLength(JSON.stringify(record));
916
- if (bytes > 256 * 1024 || queue.length + inFlight >= 1e3 || queueBytes + inFlightBytes + bytes > 4 * 1024 * 1024) {
917
- dropped++;
918
- console.warn(
919
- "[autter-runtime] log buffer or record limit reached; record dropped"
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]
920
827
  );
921
- return;
922
- }
923
- queue.push({ record, bytes });
924
- queueBytes += bytes;
925
- scheduleFlush();
926
- }
927
- function configureRuntimeLogger(next) {
928
- config = next;
929
- stopping = false;
930
- failureStreak = 0;
931
- }
932
- function runtimeLogStats() {
933
- return { buffered: queue.length + inFlight, dropped };
934
- }
935
- async function flushRuntimeLogs() {
936
- if (flushing) return flushing;
937
- if (!config || !queue.length) return;
938
- if (timer) {
939
- clearTimeout(timer);
940
- timer = void 0;
941
- }
942
- const activeConfig = config;
943
- const deadline = Date.now() + 1e4;
944
- flushing = (async () => {
945
- const count = queue.length;
946
- for (let remaining = count; remaining > 0; ) {
947
- const batch = [];
948
- inFlightBytes = 0;
949
- while (batch.length < Math.min(50, remaining) && queue.length) {
950
- const next = queue[0];
951
- if (batch.length && inFlightBytes + next.bytes > 512 * 1024) break;
952
- batch.push(queue.shift());
953
- inFlightBytes += next.bytes;
954
- queueBytes -= next.bytes;
955
- }
956
- remaining -= batch.length;
957
- inFlight = batch.length;
958
- const body = JSON.stringify({
959
- resourceLogs: [
960
- {
961
- resource: {
962
- attributes: Object.entries({
963
- "service.name": activeConfig.service,
964
- "deployment.environment.name": activeConfig.environment,
965
- ...activeConfig.release ? { "service.version": activeConfig.release } : {}
966
- }).map(([key, item]) => ({ key, value: value(item) }))
967
- },
968
- scopeLogs: [
969
- {
970
- scope: { name: "autter-runtime" },
971
- logRecords: batch.map((entry) => entry.record)
972
- }
973
- ]
974
- }
975
- ]
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"
976
843
  });
977
- let failure;
978
- for (let attempt = 0; attempt < 3; attempt++) {
979
- try {
980
- if (Date.now() >= deadline)
981
- throw new Error("Runtime log flush exceeded 10 seconds");
982
- const response = await fetch(`${activeConfig.endpoint}/v1/logs`, {
983
- method: "POST",
984
- headers: {
985
- "content-type": "application/json",
986
- authorization: `Bearer ${activeConfig.apiKey}`
987
- },
988
- body,
989
- signal: AbortSignal.timeout(
990
- Math.max(1, Math.min(3e3, deadline - Date.now()))
991
- )
992
- });
993
- if (!response.ok)
994
- throw new Error(`Runtime log export failed (${response.status})`);
995
- failure = void 0;
996
- break;
997
- } catch (error) {
998
- failure = error;
999
- }
1000
- }
1001
- inFlight = 0;
1002
- if (failure) {
1003
- failureStreak++;
1004
- queue = [...batch, ...queue];
1005
- queueBytes += inFlightBytes;
1006
- inFlightBytes = 0;
1007
- throw failure;
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);
1008
875
  }
1009
- inFlightBytes = 0;
1010
- failureStreak = 0;
876
+ } catch (e16) {
1011
877
  }
1012
- })().finally(() => {
1013
- flushing = null;
1014
- scheduleFlush();
1015
- });
1016
- return flushing;
1017
- }
1018
- async function shutdownRuntimeLogger() {
1019
- stopping = true;
1020
- try {
1021
- await flushRuntimeLogs();
1022
- } finally {
1023
- if (queue.length) {
1024
- dropped += queue.length;
1025
- console.warn(
1026
- `[autter-runtime] ${queue.length} log records could not be delivered before shutdown`
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
1027
897
  );
898
+ if (value) target.headers.set("access-control-expose-headers", value);
1028
899
  }
1029
- queue = [];
1030
- queueBytes = 0;
1031
- config = null;
1032
- if (timer) clearTimeout(timer);
1033
- timer = void 0;
1034
- }
1035
- }
1036
- function createRuntimeLogger(attributes = {}) {
1037
- const attrs = userAttributes(attributes);
1038
- return {
1039
- debug: (message, extra) => emit("debug", message, mergeContext(attrs, extra)),
1040
- info: (message, extra) => emit("info", message, mergeContext(attrs, extra)),
1041
- warn: (message, extra) => emit("warning", message, mergeContext(attrs, extra)),
1042
- error: (error, extra) => emit("error", error instanceof Error ? error.message : String(error), {
1043
- ...attrs,
1044
- ...extra,
1045
- ...error instanceof Error ? {
1046
- "exception.type": error.name,
1047
- "exception.stacktrace": error.stack ?? ""
1048
- } : {}
1049
- })
900
+ return target;
1050
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
+ }
1051
911
  }
1052
- var runtimeLogger = createRuntimeLogger();
1053
- function withRuntimeOperation(name, fn, attributes = {}) {
1054
- const parent = local.getStore();
1055
- const state = {
1056
- id: (0, import_node_crypto.randomUUID)(),
1057
- name: String(safe({ name }).name).slice(0, 200),
1058
- parentId: parent?.sealed ? void 0 : parent?.id,
1059
- attributes: mergeContext(
1060
- parent?.sealed ? {} : parent?.attributes ?? {},
1061
- attributes
1062
- ),
1063
- startedAt: Date.now(),
1064
- outcome: "succeeded",
1065
- steps: []
1066
- };
1067
- const operation = {
1068
- id: state.id,
1069
- setContext: (attrs) => {
1070
- if (!state.sealed) {
1071
- state.attributes = mergeContext(state.attributes, attrs);
1072
- import_api2.trace.getActiveSpan()?.setAttributes(traceAttributes(state));
1073
- }
1074
- },
1075
- outcome: (status, message) => {
1076
- if (state.sealed) return;
1077
- state.outcome = status;
1078
- state.message = message;
1079
- if (status === "failed")
1080
- state.reportingStack = new Error("Operation outcome reported here").stack ?? "";
1081
- },
1082
- step: async (stepName, stepFn) => {
1083
- const started = Date.now();
1084
- let status = "succeeded";
1085
- try {
1086
- return await stepFn();
1087
- } catch (error) {
1088
- status = "failed";
1089
- throw error;
1090
- } finally {
1091
- if (!state.sealed && state.steps.length < 64)
1092
- state.steps.push({
1093
- name: String(safe({ name: stepName }).name).slice(0, 200),
1094
- status,
1095
- durationMs: Date.now() - started
1096
- });
1097
- }
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) {
1098
920
  }
1099
- };
1100
- const run = () => local.run(state, async () => {
1101
- let thrown;
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;
1102
940
  try {
1103
- return await fn(operation);
1104
- } catch (error) {
1105
- state.outcome = "failed";
1106
- thrown = error;
1107
- throw error;
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);
1108
952
  } finally {
1109
- import_api2.trace.getActiveSpan()?.setAttributes({
1110
- ...traceAttributes(state),
1111
- "autter.operation.outcome": state.outcome
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 } : {}
1112
961
  });
1113
- if (state.outcome === "failed" && !thrown)
1114
- config?.reportOutcome(
1115
- state.name,
1116
- state.message ?? "Operation failed",
1117
- {
1118
- ...traceAttributes(state),
1119
- "autter.outcome.stack": state.reportingStack ?? ""
1120
- }
1121
- );
1122
- emit(
1123
- state.outcome === "failed" ? "error" : "info",
1124
- state.message ?? `${state.name}: ${state.outcome}`,
1125
- {
1126
- ...operationAttributes(state),
1127
- ...thrown instanceof Error ? {
1128
- "exception.type": thrown.name,
1129
- "exception.stacktrace": thrown.stack ?? ""
1130
- } : {}
1131
- },
1132
- {
1133
- "autter.event.type": "operation",
1134
- "autter.operation.outcome": state.outcome,
1135
- "autter.operation.duration_ms": Date.now() - state.startedAt,
1136
- "autter.operation.steps": state.steps
962
+ if (options.waitUntil) {
963
+ try {
964
+ options.waitUntil(_chunkP4VRTFAVcjs.flushRuntimeLogs.call(void 0, ).catch(() => {
965
+ }));
966
+ } catch (e20) {
1137
967
  }
1138
- );
1139
- state.sealed = true;
968
+ }
1140
969
  }
1141
- });
1142
- return config ? config.run(state.name, run, traceAttributes(state)) : run();
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);
1143
977
  }
1144
978
 
1145
979
  // src/server.ts
@@ -1158,10 +992,10 @@ var LlmAwareSampler = class {
1158
992
  constructor(delegate) {
1159
993
  this.delegate = delegate;
1160
994
  }
1161
- delegate;
995
+
1162
996
  shouldSample(ctx, traceId, spanName, spanKind, attributes, links) {
1163
997
  if (isLlmSpan(spanName, attributes)) {
1164
- return { decision: import_sdk_trace_base.SamplingDecision.RECORD_AND_SAMPLED };
998
+ return { decision: _sdktracebase.SamplingDecision.RECORD_AND_SAMPLED };
1165
999
  }
1166
1000
  return this.delegate.shouldSample(
1167
1001
  ctx,
@@ -1180,7 +1014,7 @@ var RecordUnsampledSampler = class {
1180
1014
  constructor(delegate) {
1181
1015
  this.delegate = delegate;
1182
1016
  }
1183
- delegate;
1017
+
1184
1018
  shouldSample(ctx, traceId, spanName, spanKind, attributes, links) {
1185
1019
  const result = this.delegate.shouldSample(
1186
1020
  ctx,
@@ -1190,8 +1024,8 @@ var RecordUnsampledSampler = class {
1190
1024
  attributes,
1191
1025
  links
1192
1026
  );
1193
- if (result.decision === import_sdk_trace_base.SamplingDecision.NOT_RECORD) {
1194
- return { ...result, decision: import_sdk_trace_base.SamplingDecision.RECORD };
1027
+ if (result.decision === _sdktracebase.SamplingDecision.NOT_RECORD) {
1028
+ return { ...result, decision: _sdktracebase.SamplingDecision.RECORD };
1195
1029
  }
1196
1030
  return result;
1197
1031
  }
@@ -1204,14 +1038,14 @@ var RETENTION_MAX_BUFFERED_SPANS = 5e3;
1204
1038
  var RETENTION_SWEEP_INTERVAL_MS = 1e4;
1205
1039
  var RETENTION_TRACE_TTL_MS = 3e4;
1206
1040
  function spanIndicatesError(span) {
1207
- if (span.status.code === import_api3.SpanStatusCode.ERROR) return true;
1041
+ if (span.status.code === _api.SpanStatusCode.ERROR) return true;
1208
1042
  return span.events.some((event) => event.name === "exception");
1209
1043
  }
1210
1044
  var TAIL_RETAINED_ATTR = "autter.tail_retained";
1211
1045
  function withSampledFlag(span) {
1212
1046
  const spanContext = {
1213
1047
  ...span.spanContext(),
1214
- traceFlags: span.spanContext().traceFlags | import_api3.TraceFlags.SAMPLED
1048
+ traceFlags: span.spanContext().traceFlags | _api.TraceFlags.SAMPLED
1215
1049
  };
1216
1050
  return {
1217
1051
  name: span.name,
@@ -1233,29 +1067,29 @@ function withSampledFlag(span) {
1233
1067
  droppedLinksCount: span.droppedLinksCount
1234
1068
  };
1235
1069
  }
1236
- var ErrorTraceRetentionProcessor = class {
1237
- 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);
1238
1072
  this.inner = inner;
1239
1073
  this.retainErrors = retainErrors;
1240
1074
  this.slowThresholdMs = slowThresholdMs;
1241
1075
  this.sweeper = setInterval(() => this.sweep(), RETENTION_SWEEP_INTERVAL_MS);
1242
- this.sweeper.unref?.();
1243
- }
1244
- inner;
1245
- retainErrors;
1246
- slowThresholdMs;
1247
- traces = /* @__PURE__ */ new Map();
1248
- bufferedSpans = 0;
1249
- sweeper;
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
+
1250
1084
  onStart(_span, _parentContext) {
1251
1085
  }
1252
1086
  onEnd(span) {
1253
1087
  const ctx = span.spanContext();
1254
- if ((ctx.traceFlags & import_api3.TraceFlags.SAMPLED) !== 0) return;
1088
+ if ((ctx.traceFlags & _api.TraceFlags.SAMPLED) !== 0) return;
1255
1089
  const entry = this.entryFor(ctx.traceId);
1256
1090
  if (entry.retained) {
1257
1091
  this.forward(span);
1258
- } else if (this.retainErrors && spanIndicatesError(span) || this.slowThresholdMs > 0 && span.kind === import_api3.SpanKind.SERVER && span.duration[0] * 1e3 + span.duration[1] / 1e6 >= this.slowThresholdMs) {
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) {
1259
1093
  entry.retained = true;
1260
1094
  this.flush(entry);
1261
1095
  this.forward(span);
@@ -1270,8 +1104,8 @@ var ErrorTraceRetentionProcessor = class {
1270
1104
  }
1271
1105
  /** Promote the active trace, if any — called on captured errors. */
1272
1106
  retainActiveTrace() {
1273
- const active2 = import_api3.trace.getActiveSpan()?.spanContext();
1274
- if (!active2 || (active2.traceFlags & import_api3.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;
1275
1109
  const entry = this.entryFor(active2.traceId);
1276
1110
  if (entry.retained) return;
1277
1111
  entry.retained = true;
@@ -1326,10 +1160,10 @@ var ErrorTraceRetentionProcessor = class {
1326
1160
  if (entry.firstSeenAtMs <= cutoff) this.drop(traceId);
1327
1161
  }
1328
1162
  }
1329
- };
1163
+ }, _class2);
1330
1164
  function llmBaseAttributes(info) {
1331
1165
  return {
1332
- "gen_ai.operation.name": info.operation ?? "chat",
1166
+ "gen_ai.operation.name": _nullishCoalesce(info.operation, () => ( "chat")),
1333
1167
  // Both keys: gen_ai.system is the pre-1.37 semconv name and what
1334
1168
  // most tooling still matches on.
1335
1169
  "gen_ai.provider.name": info.provider,
@@ -1359,97 +1193,106 @@ function usageAttributes(usage) {
1359
1193
  return attrs;
1360
1194
  }
1361
1195
  async function runLlmSpan(tracer, info, fn) {
1362
- const span = tracer.startSpan(`${info.operation ?? "chat"} ${info.model}`, {
1363
- kind: import_api3.SpanKind.CLIENT,
1196
+ const span = tracer.startSpan(`${_nullishCoalesce(info.operation, () => ( "chat"))} ${info.model}`, {
1197
+ kind: _api.SpanKind.CLIENT,
1364
1198
  attributes: llmBaseAttributes(info)
1365
1199
  });
1366
- 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
+ };
1367
1206
  const handle = {
1368
- setUsage: (usage) => span.setAttributes(usageAttributes(usage)),
1369
- 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
+ },
1370
1215
  setResponseModel,
1371
1216
  setModel: setResponseModel,
1372
- setAttributes: (attributes) => span.setAttributes(attributes)
1217
+ setAttributes: (attributes) => span.setAttributes(activeRedactor(attributes))
1373
1218
  };
1374
1219
  try {
1375
- const result = await import_api3.context.with(
1376
- import_api3.trace.setSpan(import_api3.context.active(), span),
1220
+ const result = await _api.context.with(
1221
+ _api.trace.setSpan(_api.context.active(), span),
1377
1222
  () => fn(handle)
1378
1223
  );
1379
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1224
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1380
1225
  return result;
1381
1226
  } catch (err) {
1382
- if (err instanceof Error) {
1383
- span.recordException(err);
1384
- span.setAttribute("error.type", err.name);
1385
- }
1386
- span.setStatus({
1387
- code: import_api3.SpanStatusCode.ERROR,
1388
- message: err instanceof Error ? err.message : String(err)
1389
- });
1227
+ recordError(span, err);
1228
+ if (err instanceof Error) span.setAttribute("error.type", err.name);
1390
1229
  throw err;
1391
1230
  } finally {
1392
1231
  span.end();
1232
+ _chunkP4VRTFAVcjs.recordOperationAiUsage.call(void 0, { ...usage, model: _nullishCoalesce(responseModel, () => ( info.model)) });
1393
1233
  }
1394
1234
  }
1395
1235
  function recordLlmCall(tracer, call) {
1396
- 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)));
1397
1238
  const endTime = /* @__PURE__ */ new Date();
1398
1239
  const startTime = new Date(endTime.getTime() - durationMs);
1399
1240
  const span = tracer.startSpan(
1400
- `${call.operation ?? "chat"} ${call.model}`,
1241
+ `${_nullishCoalesce(call.operation, () => ( "chat"))} ${call.model}`,
1401
1242
  {
1402
- kind: import_api3.SpanKind.CLIENT,
1243
+ kind: _api.SpanKind.CLIENT,
1403
1244
  startTime,
1404
1245
  attributes: { ...llmBaseAttributes(call), ...usageAttributes(call) }
1405
1246
  }
1406
1247
  );
1407
1248
  if (call.error !== void 0 && call.error !== null) {
1249
+ recordError(span, call.error);
1408
1250
  if (call.error instanceof Error) {
1409
- span.recordException(call.error);
1410
1251
  span.setAttribute("error.type", call.error.name);
1411
1252
  }
1412
- span.setStatus({
1413
- code: import_api3.SpanStatusCode.ERROR,
1414
- message: call.error instanceof Error ? call.error.message : String(call.error)
1415
- });
1416
1253
  } else {
1417
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1254
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1418
1255
  }
1419
1256
  span.end(endTime);
1420
1257
  }
1421
- async function runWithSpan(tracer, name, fn, attributes) {
1422
- 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
+ });
1423
1263
  try {
1424
- const result = await import_api3.context.with(
1425
- import_api3.trace.setSpan(import_api3.context.active(), span),
1264
+ const result = await _api.context.with(
1265
+ _api.trace.setSpan(_api.context.active(), span),
1426
1266
  fn
1427
1267
  );
1428
- span.setStatus({ code: import_api3.SpanStatusCode.OK });
1268
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1429
1269
  return result;
1430
1270
  } catch (err) {
1431
- if (err instanceof Error) span.recordException(err);
1432
- span.setStatus({
1433
- code: import_api3.SpanStatusCode.ERROR,
1434
- message: err instanceof Error ? err.message : String(err)
1435
- });
1271
+ recordError(span, err);
1436
1272
  throw err;
1437
1273
  } finally {
1438
1274
  span.end();
1439
1275
  }
1440
1276
  }
1441
- function expressRouteOf(req) {
1442
- const props = req;
1443
- const path = props?.route?.path;
1444
- if (typeof path !== "string" || path === "") return null;
1445
- const base = typeof props?.baseUrl === "string" ? props.baseUrl : "";
1446
- const route = base + path;
1447
- return route.startsWith("/") ? route : null;
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);
1448
1291
  }
1449
1292
  function captureExpressRoute(_span, response) {
1450
- if (!(response instanceof import_node_http.ServerResponse)) return;
1451
- const rpcMetadata = (0, import_core2.getRPCMetadata)(import_api3.context.active());
1452
- if (rpcMetadata?.type !== import_core2.RPCType.HTTP) return;
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;
1453
1296
  const setRoute = () => {
1454
1297
  if (rpcMetadata.route) return;
1455
1298
  const route = expressRouteOf(response.req);
@@ -1457,33 +1300,60 @@ function captureExpressRoute(_span, response) {
1457
1300
  };
1458
1301
  response.prependListener("finish", setRoute);
1459
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;
1460
1318
  }
1461
1319
  var active = null;
1462
1320
  var activeAlwaysOnProvider = null;
1463
- var activeRedactor = makeRedactor(true);
1321
+ var activeRedactor = _chunkP4VRTFAVcjs.makeRedactor.call(void 0, true);
1464
1322
  function initAutterServer(options) {
1465
1323
  if (active) return active;
1466
- const endpoint = (options.endpoint ?? "https://otlp.autter.dev").replace(
1324
+ const endpoint = (_nullishCoalesce(options.endpoint, () => ( "https://otlp.autter.dev"))).replace(
1467
1325
  /\/$/,
1468
1326
  ""
1469
1327
  );
1470
1328
  const headers = { authorization: `Bearer ${options.apiKey}` };
1471
- const environment = options.environment ?? process.env.NODE_ENV ?? "production";
1472
- if (isDebugEnabled() || options.debug === true) setDebugMode(true);
1473
- debugLog(`initialising service=${options.service} endpoint=${endpoint}`);
1474
- activeRedactor = makeRedactor(options.redactAttributes ?? true);
1475
- const resource = new import_resources.Resource({
1476
- [import_semantic_conventions.ATTR_SERVICE_NAME]: options.service,
1477
- "service.instance.id": (options.instanceId || process.env.AUTTER_RUNTIME_INSTANCE_ID || (0, import_node_crypto2.randomUUID)()).slice(0, 128),
1478
- ...options.release ? { [import_semantic_conventions.ATTR_SERVICE_VERSION]: options.release } : {},
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 } : {},
1479
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,
1480
1350
  // Tells the ingester request metrics arrive on the metrics pipe, so
1481
1351
  // it must not also fold our server spans into usage rollups (that
1482
1352
  // would double-count every sampled request).
1483
1353
  "autter.metrics_wired": true
1484
1354
  });
1485
- const headSampler = new import_sdk_trace_base.ParentBasedSampler({
1486
- 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)))
1487
1357
  });
1488
1358
  const retainOnError = options.retainTracesOnError !== false;
1489
1359
  const slowThresholdMs = Number.isFinite(options.retainTracesAboveMs) ? Math.max(0, options.retainTracesAboveMs) : 0;
@@ -1491,33 +1361,27 @@ function initAutterServer(options) {
1491
1361
  let sampler = retainTraces ? new RecordUnsampledSampler(headSampler) : headSampler;
1492
1362
  if (options.llmTracing !== false) sampler = new LlmAwareSampler(sampler);
1493
1363
  const errorTraceBuffer = retainTraces ? new ErrorTraceRetentionProcessor(
1494
- new import_sdk_trace_base.BatchSpanProcessor(
1495
- new CountingExporter(
1496
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1497
- ),
1498
- { scheduledDelayMillis: 2e3 }
1499
- ),
1364
+ new (0, _sdktracebase.BatchSpanProcessor)(traceExporter(), { scheduledDelayMillis: 2e3 }),
1500
1365
  retainOnError,
1501
1366
  slowThresholdMs
1502
1367
  ) : null;
1503
- const mainSpanProcessor = new import_sdk_trace_base.BatchSpanProcessor(
1504
- new CountingExporter(
1505
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1506
- )
1507
- );
1508
- const metricReader = new import_sdk_metrics.PeriodicExportingMetricReader({
1509
- exporter: new import_exporter_metrics_otlp_http.OTLPMetricExporter({
1510
- url: `${endpoint}/v1/metrics`,
1511
- headers,
1512
- // Deltas, not lifetime totals: the ingester SUMs data points
1513
- // into runtime_metrics_1m, and the default (cumulative)
1514
- // temporality would re-count every past request on each
1515
- // 60 s export.
1516
- temporalityPreference: import_exporter_metrics_otlp_http.AggregationTemporalityPreference.DELTA
1517
- }),
1518
- exportIntervalMillis: options.metricIntervalMs ?? 6e4
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))
1519
1383
  });
1520
- const sdk = new import_sdk_node.NodeSDK({
1384
+ const sdk = new (0, _sdknode.NodeSDK)({
1521
1385
  resource,
1522
1386
  sampler,
1523
1387
  spanProcessors: [
@@ -1526,116 +1390,129 @@ function initAutterServer(options) {
1526
1390
  ],
1527
1391
  metricReader,
1528
1392
  views: [
1529
- 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)(
1530
1394
  [5, 10, 25, 50, 100, 250, 500, 750, 1e3, 1500, 2e3, 3e3, 5e3, 7500, 1e4, 15e3, 2e4, 3e4, 6e4, 12e4]
1531
1395
  ) }),
1532
- 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)(
1533
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]
1534
1398
  ) })
1535
1399
  ],
1536
1400
  instrumentations: [
1537
- new import_instrumentation_http.HttpInstrumentation({ responseHook: captureExpressRoute }),
1538
- ...options.instrumentations ?? []
1401
+ new (0, _instrumentationhttp.HttpInstrumentation)({ responseHook: captureExpressRoute }),
1402
+ ..._nullishCoalesce(options.instrumentations, () => ( []))
1539
1403
  ]
1540
1404
  });
1541
1405
  sdk.start();
1542
1406
  const stopMemoryMetrics = options.memoryMetrics === false ? null : startMemoryMetrics();
1543
- 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)({
1544
1411
  resource,
1545
- sampler: new import_sdk_trace_base.AlwaysOnSampler(),
1412
+ sampler: new (0, _sdktracebase.AlwaysOnSampler)(),
1546
1413
  spanProcessors: [
1547
- new import_sdk_trace_base.BatchSpanProcessor(
1548
- new CountingExporter(
1549
- new import_exporter_trace_otlp_http.OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers })
1550
- ),
1551
- { scheduledDelayMillis: 2e3 }
1552
- )
1414
+ new (0, _sdktracebase.BatchSpanProcessor)(traceExporter(), { scheduledDelayMillis: 2e3 })
1553
1415
  ]
1554
1416
  });
1555
1417
  const errorTracer = alwaysOnProvider.getTracer("autter-errors");
1556
1418
  const processTracer = alwaysOnProvider.getTracer("autter-processes");
1557
1419
  const llmTracer = alwaysOnProvider.getTracer("autter-llm");
1558
1420
  function captureException2(error, attributes) {
1559
- errorTraceBuffer?.retainActiveTrace();
1560
- telemetryStats.markCaptured();
1421
+ _optionalChain([errorTraceBuffer, 'optionalAccess', _42 => _42.retainActiveTrace, 'call', _43 => _43()]);
1422
+ _chunkGI47WGRRcjs.telemetryStats.markCaptured();
1561
1423
  const isError = error instanceof Error;
1562
- 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) : "";
1563
1426
  const redacted = activeRedactor(attributes);
1564
- const activeSpan = import_api3.trace.getActiveSpan();
1565
- const reuseActive = activeSpan?.isRecording() === true;
1427
+ const activeSpan = _api.trace.getActiveSpan();
1428
+ const reuseActive = _optionalChain([activeSpan, 'optionalAccess', _44 => _44.isRecording, 'call', _45 => _45()]) === true;
1566
1429
  const span = reuseActive ? activeSpan : errorTracer.startSpan(isError ? error.name : "Error");
1567
- span.setAttributes({ "autter.severity": "error", ...redacted });
1568
- if (isError && error.stack) {
1569
- if (redacted["autter.handled"] === true) {
1570
- span.addEvent("exception", {
1571
- "exception.type": error.name,
1572
- "exception.message": message,
1573
- "exception.stacktrace": error.stack,
1574
- "autter.handled": true,
1575
- "autter.sampled": redacted["autter.sampled"] === true
1576
- });
1577
- } else {
1578
- span.recordException(error);
1579
- }
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
+ });
1580
1453
  } else {
1581
- 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")]);
1582
1455
  span.addEvent("exception", {
1583
1456
  "exception.type": isError ? error.name : "Error",
1584
1457
  "exception.message": message,
1585
- ...stack ? { "exception.stacktrace": stack } : {},
1586
- ...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
1587
1461
  });
1588
1462
  }
1589
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message });
1463
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message });
1590
1464
  if (!reuseActive) span.end();
1591
1465
  }
1592
- function captureMessage2(message, severity2 = "warning", attributes) {
1593
- if (severity2 === "error" || severity2 === "fatal") {
1594
- errorTraceBuffer?.retainActiveTrace();
1466
+ function captureMessage2(message, severity = "warning", attributes) {
1467
+ if (severity === "error" || severity === "fatal") {
1468
+ _optionalChain([errorTraceBuffer, 'optionalAccess', _54 => _54.retainActiveTrace, 'call', _55 => _55()]);
1595
1469
  }
1596
- telemetryStats.markCaptured();
1597
- 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);
1598
1473
  const span = errorTracer.startSpan("Message", {
1599
- attributes: { "autter.severity": severity2, ...activeRedactor(attributes) }
1474
+ attributes: { "autter.severity": severity, ...activeRedactor(attributes) }
1600
1475
  });
1601
1476
  span.addEvent("exception", {
1602
1477
  "exception.type": "Message",
1603
- "exception.message": message,
1604
- ...stack ? { "exception.stacktrace": stack } : {},
1605
- "autter.severity": severity2
1478
+ "exception.message": safeMessage,
1479
+ ...stack ? { "exception.stacktrace": activeRedactor.text(stack) } : {},
1480
+ "autter.severity": severity
1606
1481
  });
1607
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message });
1482
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1608
1483
  span.end();
1609
1484
  }
1610
1485
  function reportOutcome2(name, message, attributes) {
1611
- errorTraceBuffer?.retainActiveTrace();
1612
- telemetryStats.markCaptured();
1613
- const activeSpan = import_api3.trace.getActiveSpan();
1614
- 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;
1615
1490
  const span = reuseActive ? activeSpan : errorTracer.startSpan("OutcomeFailure");
1616
1491
  const safeOutcome = activeRedactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1617
- const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
1618
- const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
1492
+ const safeName = String(_nullishCoalesce(safeOutcome["autter.outcome.name"], () => ( "operation")));
1493
+ const safeMessage = String(_nullishCoalesce(safeOutcome["autter.outcome.message"], () => ( "failed")));
1619
1494
  span.addEvent("autter.outcome", {
1620
1495
  ...activeRedactor(attributes),
1621
1496
  "autter.outcome.status": "error",
1622
1497
  "autter.outcome.name": safeName,
1623
1498
  "autter.outcome.message": safeMessage
1624
1499
  });
1625
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: safeMessage });
1500
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1626
1501
  if (!reuseActive) span.end();
1627
1502
  }
1628
- configureRuntimeLogger({
1503
+ _chunkP4VRTFAVcjs.configureRuntimeLogger.call(void 0, {
1629
1504
  endpoint,
1630
1505
  apiKey: options.apiKey,
1631
1506
  service: options.service,
1632
1507
  environment,
1508
+ distro,
1633
1509
  release: options.release,
1634
1510
  options: options.logging,
1635
1511
  redact: activeRedactor,
1636
- run: (name, fn, attributes) => runWithSpan(processTracer, name, fn, activeRedactor(attributes)),
1512
+ run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn, activeRedactor(attributes), links),
1637
1513
  reportOutcome: reportOutcome2
1638
1514
  });
1515
+ hookRequests = _optionalChain([options, 'access', _67 => _67.logging, 'optionalAccess', _68 => _68.requests]) === true;
1639
1516
  if (options.captureGlobalErrors !== false) {
1640
1517
  process.on("uncaughtExceptionMonitor", (err) => {
1641
1518
  captureException2(err, { "autter.unhandled": true });
@@ -1646,7 +1523,7 @@ function initAutterServer(options) {
1646
1523
  const flushTarget = {
1647
1524
  forceFlush: async () => {
1648
1525
  const results = await Promise.allSettled([
1649
- flushRuntimeLogs(),
1526
+ _chunkP4VRTFAVcjs.flushRuntimeLogs.call(void 0, ),
1650
1527
  Promise.resolve().then(() => alwaysOnProvider.forceFlush()),
1651
1528
  Promise.resolve().then(() => mainSpanProcessor.forceFlush()),
1652
1529
  ...errorTraceBuffer ? [Promise.resolve().then(() => errorTraceBuffer.forceFlush())] : [],
@@ -1660,10 +1537,10 @@ function initAutterServer(options) {
1660
1537
  }
1661
1538
  }
1662
1539
  };
1663
- registerFlushTarget("active-server", flushTarget);
1540
+ _chunkGI47WGRRcjs.registerFlushTarget.call(void 0, "active-server", flushTarget);
1664
1541
  let autoFlushHandle = null;
1665
1542
  if (options.autoFlush !== false) {
1666
- autoFlushHandle = installAutterAutoFlush();
1543
+ autoFlushHandle = _chunkGI47WGRRcjs.installAutterAutoFlush.call(void 0, );
1667
1544
  }
1668
1545
  const server = {
1669
1546
  captureException: captureException2,
@@ -1673,16 +1550,17 @@ function initAutterServer(options) {
1673
1550
  withLlmCall: (info, fn) => runLlmSpan(llmTracer, info, fn),
1674
1551
  trackLlmCall: (call) => recordLlmCall(llmTracer, call),
1675
1552
  shutdown: async () => {
1676
- const logShutdown = await Promise.allSettled([shutdownRuntimeLogger()]);
1677
- stopMemoryMetrics?.();
1553
+ const logShutdown = await Promise.allSettled([_chunkP4VRTFAVcjs.shutdownRuntimeLogger.call(void 0, )]);
1554
+ hookRequests = false;
1555
+ _optionalChain([stopMemoryMetrics, 'optionalCall', _69 => _69()]);
1678
1556
  active = null;
1679
1557
  activeAlwaysOnProvider = null;
1680
- autoFlushHandle?.dispose();
1558
+ _optionalChain([autoFlushHandle, 'optionalAccess', _70 => _70.dispose, 'call', _71 => _71()]);
1681
1559
  autoFlushHandle = null;
1682
- unregisterFlushTargets();
1683
- telemetryStats.markAllFlushed();
1560
+ _chunkGI47WGRRcjs.unregisterFlushTargets.call(void 0, );
1561
+ _chunkGI47WGRRcjs.telemetryStats.markAllFlushed();
1684
1562
  await Promise.allSettled([alwaysOnProvider.shutdown(), sdk.shutdown()]);
1685
- if (logShutdown[0]?.status === "rejected") throw logShutdown[0].reason;
1563
+ if (_optionalChain([logShutdown, 'access', _72 => _72[0], 'optionalAccess', _73 => _73.status]) === "rejected") throw logShutdown[0].reason;
1686
1564
  }
1687
1565
  };
1688
1566
  active = server;
@@ -1694,69 +1572,88 @@ function captureException(error, attributes) {
1694
1572
  active.captureException(error, attributes);
1695
1573
  return;
1696
1574
  }
1697
- const span = import_api3.trace.getTracer("autter-errors").startSpan(error instanceof Error ? error.name : "Error", { attributes });
1698
- if (error instanceof Error) span.recordException(error);
1699
- span.setStatus({
1700
- code: import_api3.SpanStatusCode.ERROR,
1701
- message: error instanceof Error ? error.message : String(error)
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)
1702
1584
  });
1585
+ recordError(span, error);
1703
1586
  span.end();
1704
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));
1705
1596
  function withProcessSpan(name, fn, attributes) {
1706
1597
  if (active) return active.withProcessSpan(name, fn, attributes);
1707
- return runWithSpan(import_api3.trace.getTracer("autter-processes"), name, fn, attributes);
1598
+ return runWithSpan(
1599
+ _api.trace.getTracer("autter-processes"),
1600
+ name,
1601
+ fn,
1602
+ activeRedactor(attributes)
1603
+ );
1708
1604
  }
1709
1605
  function withLlmCall(info, fn) {
1710
1606
  if (active) return active.withLlmCall(info, fn);
1711
- return runLlmSpan(import_api3.trace.getTracer("autter-llm"), info, fn);
1607
+ return runLlmSpan(_api.trace.getTracer("autter-llm"), info, fn);
1712
1608
  }
1713
1609
  function trackLlmCall(call) {
1714
1610
  if (active) {
1715
1611
  active.trackLlmCall(call);
1716
1612
  return;
1717
1613
  }
1718
- recordLlmCall(import_api3.trace.getTracer("autter-llm"), call);
1614
+ recordLlmCall(_api.trace.getTracer("autter-llm"), call);
1719
1615
  }
1720
- function captureMessage(message, severity2 = "warning", attributes) {
1616
+ function captureMessage(message, severity = "warning", attributes) {
1721
1617
  if (active) {
1722
- active.captureMessage(message, severity2, attributes);
1618
+ active.captureMessage(message, severity, attributes);
1723
1619
  return;
1724
1620
  }
1725
- const span = import_api3.trace.getTracer("autter-errors").startSpan("Message", {
1726
- attributes: { "autter.severity": severity2, ...attributes }
1621
+ const safeMessage = activeRedactor.text(message);
1622
+ const span = _api.trace.getTracer("autter-errors").startSpan("Message", {
1623
+ attributes: { "autter.severity": severity, ...activeRedactor(attributes) }
1727
1624
  });
1728
1625
  span.addEvent("exception", {
1729
1626
  "exception.type": "Message",
1730
- "exception.message": message,
1731
- "autter.severity": severity2
1627
+ "exception.message": safeMessage,
1628
+ "autter.severity": severity
1732
1629
  });
1733
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message });
1630
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1734
1631
  span.end();
1735
1632
  }
1736
1633
  function reportOutcome(name, message, attributes) {
1737
1634
  if (active) return active.reportOutcome(name, message, attributes);
1738
- const span = import_api3.trace.getTracer("autter-outcomes").startSpan("OutcomeFailure");
1739
- const safeOutcome = redactAttributes({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1740
- const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
1741
- const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
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")));
1742
1639
  span.addEvent("autter.outcome", {
1743
- ...redactAttributes(attributes),
1640
+ ..._chunkP4VRTFAVcjs.redactAttributes.call(void 0, attributes),
1744
1641
  "autter.outcome.status": "error",
1745
1642
  "autter.outcome.name": safeName,
1746
1643
  "autter.outcome.message": safeMessage
1747
1644
  });
1748
- span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: safeMessage });
1645
+ span.setStatus({ code: _api.SpanStatusCode.ERROR, message: safeMessage });
1749
1646
  span.end();
1750
1647
  }
1751
1648
  function makeSafeCapture(options) {
1752
- const clean = (attributes) => attributes ? { ...redactAttributes(attributes, options) } : void 0;
1649
+ const clean = (attributes) => attributes ? { ..._chunkP4VRTFAVcjs.redactAttributes.call(void 0, attributes, options) } : void 0;
1753
1650
  return {
1754
1651
  captureException: (error, attributes) => captureException(error, clean(attributes)),
1755
- captureMessage: (message, severity2, attributes) => captureMessage(message, severity2 ?? "warning", clean(attributes))
1652
+ captureMessage: (message, severity, attributes) => captureMessage(message, _nullishCoalesce(severity, () => ( "warning")), clean(attributes))
1756
1653
  };
1757
1654
  }
1758
1655
  function alwaysOnTracer(name) {
1759
- return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) : import_api3.trace.getTracer(name);
1656
+ return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) : _api.trace.getTracer(name);
1760
1657
  }
1761
1658
  function autterLlmTracer() {
1762
1659
  return alwaysOnTracer("autter-llm");
@@ -1776,7 +1673,7 @@ async function emitLlmSelftestTrace() {
1776
1673
  attributes: { "autter.selftest": true }
1777
1674
  },
1778
1675
  (llm) => {
1779
- traceId = import_api3.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]), () => ( ""));
1780
1677
  llm.setUsage({ inputTokens: 1, outputTokens: 1 });
1781
1678
  llm.setCost(0);
1782
1679
  }
@@ -1786,7 +1683,10 @@ async function emitLlmSelftestTrace() {
1786
1683
  }
1787
1684
 
1788
1685
  // src/llm-instrument.ts
1789
- var import_api4 = require("@opentelemetry/api");
1686
+
1687
+
1688
+
1689
+
1790
1690
  var CALL_METHODS = /* @__PURE__ */ new Set([
1791
1691
  "create",
1792
1692
  // openai chat/completions/embeddings/responses, anthropic messages
@@ -1801,15 +1701,15 @@ var CALL_METHODS = /* @__PURE__ */ new Set([
1801
1701
  // openai beta structured outputs
1802
1702
  ]);
1803
1703
  function detectProvider(client) {
1804
- 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()]), () => ( ""));
1805
1705
  for (const known of ["openai", "anthropic", "mistral", "groq", "cohere"]) {
1806
1706
  if (name.includes(known)) return known;
1807
1707
  }
1808
1708
  if (name.includes("google") || name.includes("genai")) return "google";
1809
1709
  const baseUrl = String(
1810
- client.baseURL ?? client.baseUrl ?? ""
1710
+ _nullishCoalesce(_nullishCoalesce(client.baseURL, () => ( client.baseUrl)), () => ( ""))
1811
1711
  );
1812
- const host = baseUrl.match(/https?:\/\/([^/]+)/)?.[1] ?? "";
1712
+ const host = _nullishCoalesce(_optionalChain([baseUrl, 'access', _83 => _83.match, 'call', _84 => _84(/https?:\/\/([^/]+)/), 'optionalAccess', _85 => _85[1]]), () => ( ""));
1813
1713
  if (host.includes("openai")) return "openai";
1814
1714
  if (host.includes("anthropic")) return "anthropic";
1815
1715
  if (host.includes("googleapis")) return "google";
@@ -1819,17 +1719,28 @@ function detectProvider(client) {
1819
1719
  }
1820
1720
  function extractUsage(result) {
1821
1721
  const r = result;
1822
- const usage = r?.usage ?? r?.message?.usage;
1823
- const meta = r?.usageMetadata;
1824
- const input = usage?.prompt_tokens ?? usage?.input_tokens ?? meta?.promptTokenCount ?? void 0;
1825
- const output = usage?.completion_tokens ?? usage?.output_tokens ?? meta?.candidatesTokenCount ?? void 0;
1826
- const responseModel = r?.model ?? r?.modelVersion;
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])));
1827
1729
  return {
1828
1730
  inputTokens: typeof input === "number" ? input : void 0,
1829
1731
  outputTokens: typeof output === "number" ? output : void 0,
1732
+ cacheReadTokens: typeof cached === "number" ? cached : void 0,
1830
1733
  responseModel: typeof responseModel === "string" ? responseModel : void 0
1831
1734
  };
1832
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
+ }
1833
1744
  function applyUsage(span, usage) {
1834
1745
  if (usage.inputTokens !== void 0) {
1835
1746
  span.setAttribute("gen_ai.usage.input_tokens", usage.inputTokens);
@@ -1842,14 +1753,10 @@ function applyUsage(span, usage) {
1842
1753
  }
1843
1754
  }
1844
1755
  function endWithError(span, err) {
1845
- if (err instanceof Error) span.recordException(err);
1846
- span.setStatus({
1847
- code: import_api4.SpanStatusCode.ERROR,
1848
- message: err instanceof Error ? err.message : String(err)
1849
- });
1756
+ recordError(span, err);
1850
1757
  span.end();
1851
1758
  }
1852
- function wrapStream(stream, span) {
1759
+ function wrapStream(stream, span, model) {
1853
1760
  let ended = false;
1854
1761
  const seen = {
1855
1762
  inputTokens: void 0,
@@ -1860,11 +1767,12 @@ function wrapStream(stream, span) {
1860
1767
  if (ended) return;
1861
1768
  ended = true;
1862
1769
  applyUsage(span, seen);
1770
+ rollUp(model, seen);
1863
1771
  span.setAttribute("autter.llm.streamed", true);
1864
1772
  if (err !== void 0) {
1865
1773
  endWithError(span, err);
1866
1774
  } else {
1867
- span.setStatus({ code: import_api4.SpanStatusCode.OK });
1775
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1868
1776
  span.end();
1869
1777
  }
1870
1778
  };
@@ -1881,6 +1789,7 @@ function wrapStream(stream, span) {
1881
1789
  const usage = extractUsage(step.value);
1882
1790
  if (usage.inputTokens !== void 0) seen.inputTokens = usage.inputTokens;
1883
1791
  if (usage.outputTokens !== void 0) seen.outputTokens = usage.outputTokens;
1792
+ if (usage.cacheReadTokens !== void 0) seen.cacheReadTokens = usage.cacheReadTokens;
1884
1793
  if (usage.responseModel) seen.responseModel = usage.responseModel;
1885
1794
  } else {
1886
1795
  finish();
@@ -1891,9 +1800,9 @@ function wrapStream(stream, span) {
1891
1800
  throw err;
1892
1801
  }
1893
1802
  },
1894
- async return(value3) {
1803
+ async return(value2) {
1895
1804
  finish();
1896
- return inner.return ? inner.return(value3) : { done: true, value: void 0 };
1805
+ return inner.return ? inner.return(value2) : { done: true, value: void 0 };
1897
1806
  },
1898
1807
  async throw(err) {
1899
1808
  finish(err);
@@ -1903,30 +1812,30 @@ function wrapStream(stream, span) {
1903
1812
  };
1904
1813
  };
1905
1814
  }
1906
- const value2 = Reflect.get(target, prop, receiver);
1907
- return typeof value2 === "function" ? value2.bind(target) : value2;
1815
+ const value = Reflect.get(target, prop, receiver);
1816
+ return typeof value === "function" ? value.bind(target) : value;
1908
1817
  }
1909
1818
  });
1910
1819
  }
1911
1820
  function instrumentLlmClient(client, options) {
1912
- const provider = (options?.provider ?? detectProvider(client)).toLowerCase();
1821
+ const provider = (_nullishCoalesce(_optionalChain([options, 'optionalAccess', _102 => _102.provider]), () => ( detectProvider(client)))).toLowerCase();
1913
1822
  const proxied = /* @__PURE__ */ new WeakMap();
1914
1823
  function resolveUserId() {
1915
- 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]);
1916
1825
  }
1917
1826
  function traceCall(fn, self, callPath, args) {
1918
1827
  const request = args[0];
1919
1828
  const operation = /embed/i.test(callPath) ? "embeddings" : "chat";
1920
1829
  const userId = resolveUserId();
1921
1830
  const span = autterLlmTracer().startSpan(`${operation} ${request.model}`, {
1922
- kind: import_api4.SpanKind.CLIENT,
1831
+ kind: _api.SpanKind.CLIENT,
1923
1832
  attributes: {
1924
1833
  "gen_ai.operation.name": operation,
1925
1834
  "gen_ai.provider.name": provider,
1926
1835
  "gen_ai.system": provider,
1927
1836
  "gen_ai.request.model": request.model,
1928
1837
  ...userId ? { "autter.user_id": userId } : {},
1929
- ...options?.attributes
1838
+ ...redactWithActive(_optionalChain([options, 'optionalAccess', _105 => _105.attributes]))
1930
1839
  }
1931
1840
  });
1932
1841
  let result;
@@ -1938,20 +1847,24 @@ function instrumentLlmClient(client, options) {
1938
1847
  }
1939
1848
  if (!(result instanceof Promise)) {
1940
1849
  if (result && typeof result === "object" && Symbol.asyncIterator in result) {
1941
- return wrapStream(result, span);
1850
+ return wrapStream(result, span, request.model);
1942
1851
  }
1943
- applyUsage(span, extractUsage(result));
1944
- span.setStatus({ code: import_api4.SpanStatusCode.OK });
1852
+ const usage = extractUsage(result);
1853
+ applyUsage(span, usage);
1854
+ rollUp(request.model, usage);
1855
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1945
1856
  span.end();
1946
1857
  return result;
1947
1858
  }
1948
1859
  return result.then(
1949
1860
  (resolved) => {
1950
1861
  if (resolved && typeof resolved === "object" && Symbol.asyncIterator in resolved) {
1951
- return wrapStream(resolved, span);
1862
+ return wrapStream(resolved, span, request.model);
1952
1863
  }
1953
- applyUsage(span, extractUsage(resolved));
1954
- span.setStatus({ code: import_api4.SpanStatusCode.OK });
1864
+ const usage = extractUsage(resolved);
1865
+ applyUsage(span, usage);
1866
+ rollUp(request.model, usage);
1867
+ span.setStatus({ code: _api.SpanStatusCode.OK });
1955
1868
  span.end();
1956
1869
  return resolved;
1957
1870
  },
@@ -1966,30 +1879,30 @@ function instrumentLlmClient(client, options) {
1966
1879
  if (cached) return cached;
1967
1880
  const proxy = new Proxy(target, {
1968
1881
  get(t, prop, receiver) {
1969
- const value2 = Reflect.get(t, prop, receiver);
1970
- if (typeof prop === "symbol") return value2;
1882
+ const value = Reflect.get(t, prop, receiver);
1883
+ if (typeof prop === "symbol") return value;
1971
1884
  const propPath = path ? `${path}.${prop}` : prop;
1972
- if (typeof value2 === "function") {
1885
+ if (typeof value === "function") {
1973
1886
  if (CALL_METHODS.has(prop)) {
1974
1887
  return (...args) => {
1975
1888
  const first = args[0];
1976
1889
  if (first && typeof first === "object" && typeof first.model === "string") {
1977
1890
  return traceCall(
1978
- value2,
1891
+ value,
1979
1892
  t,
1980
1893
  propPath,
1981
1894
  args
1982
1895
  );
1983
1896
  }
1984
- return value2.apply(t, args);
1897
+ return value.apply(t, args);
1985
1898
  };
1986
1899
  }
1987
- return value2.bind(t);
1900
+ return value.bind(t);
1988
1901
  }
1989
- if (value2 !== null && typeof value2 === "object" && !(value2 instanceof Promise)) {
1990
- return deepProxy(value2, propPath);
1902
+ if (value !== null && typeof value === "object" && !(value instanceof Promise)) {
1903
+ return deepProxy(value, propPath);
1991
1904
  }
1992
- return value2;
1905
+ return value;
1993
1906
  }
1994
1907
  });
1995
1908
  proxied.set(target, proxy);
@@ -1999,11 +1912,11 @@ function instrumentLlmClient(client, options) {
1999
1912
  }
2000
1913
 
2001
1914
  // src/caught-exceptions.ts
2002
- var import_node_inspector = __toESM(require("inspector"), 1);
1915
+ var _inspector = require('inspector'); var _inspector2 = _interopRequireDefault(_inspector);
2003
1916
  function startCaughtExceptionSampler(options = {}) {
2004
- const rate = Math.max(0, Math.min(1, options.sampleRate ?? 0.01));
2005
- const cap = Math.max(1, Math.min(100, options.maxPerMinute ?? 10));
2006
- const session = new import_node_inspector.default.Session();
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();
2007
1920
  let active2 = true;
2008
1921
  let minute = 0;
2009
1922
  let sent = 0;
@@ -2019,7 +1932,7 @@ function startCaughtExceptionSampler(options = {}) {
2019
1932
  }
2020
1933
  if (sent >= cap || Math.random() >= rate) return;
2021
1934
  sent++;
2022
- const frames = message.params.callFrames.slice(0, 8).filter((frame) => frame.url && !frame.url.startsWith("node:")).map((frame) => ` at ${frame.functionName || "anonymous"} (${frame.url.split("?")[0]}:${frame.location.lineNumber + 1}:${(frame.location.columnNumber ?? 0) + 1})`);
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})`);
2023
1936
  if (!frames.length) return;
2024
1937
  const error = new Error("Sampled caught exception");
2025
1938
  error.name = "CaughtException";
@@ -2041,27 +1954,245 @@ ${frames.join("\n")}`;
2041
1954
  });
2042
1955
  } };
2043
1956
  }
2044
- // Annotate the CommonJS export names for ESM import in node:
2045
- 0 && (module.exports = {
2046
- captureException,
2047
- captureMessage,
2048
- createBrowserRelayFetchHandler,
2049
- createBrowserRelayHandler,
2050
- createRuntimeLogger,
2051
- emitLlmSelftestTrace,
2052
- flushRuntimeLogs,
2053
- initAutterServer,
2054
- installAutterAutoFlush,
2055
- instrumentLlmClient,
2056
- makeSafeCapture,
2057
- redactAttributes,
2058
- reportOutcome,
2059
- runtimeLogStats,
2060
- runtimeLogger,
2061
- sanitizeBrowserPayload,
2062
- startCaughtExceptionSampler,
2063
- trackLlmCall,
2064
- withLlmCall,
2065
- withProcessSpan,
2066
- withRuntimeOperation
2067
- });
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;