@autter/runtime-node 1.6.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -45,10 +45,10 @@ import {
45
45
  splitFingerprint,
46
46
  toClientError,
47
47
  withRuntimeOperation
48
- } from "./chunk-FBKYOHU2.js";
48
+ } from "./chunk-5KISVAVB.js";
49
49
  import {
50
50
  runDoctor
51
- } from "./chunk-Y4T7SQMO.js";
51
+ } from "./chunk-L5ENELB2.js";
52
52
  import {
53
53
  COMPAT_MANIFEST,
54
54
  CountingExporter,
@@ -67,9 +67,10 @@ import {
67
67
  observeIngesterResponse,
68
68
  registerFlushTarget,
69
69
  setDebugMode,
70
+ sharedSlot,
70
71
  telemetryStats,
71
72
  unregisterFlushTargets
72
- } from "./chunk-OY2HTUWY.js";
73
+ } from "./chunk-HRDELHZP.js";
73
74
 
74
75
  // src/relay.ts
75
76
  var IpWindow = class {
@@ -478,6 +479,89 @@ import { Resource } from "@opentelemetry/resources";
478
479
  import {
479
480
  AggregationTemporality
480
481
  } from "@opentelemetry/sdk-metrics";
482
+
483
+ // src/url-query.ts
484
+ var URL_KEYS = ["http.target", "http.url", "url.full", "url.original", "url.path"];
485
+ var QUERY_KEY = "url.query";
486
+ var NAME_KEYS = ["next.span_name"];
487
+ var MASK = "[redacted]";
488
+ var SCHEME = /^[a-z][a-z0-9+.-]*:\/\//i;
489
+ function splitUrl(value) {
490
+ const from = SCHEME.test(value) ? value.indexOf("://") + 3 : 0;
491
+ const question = value.indexOf("?", from);
492
+ const hash = value.indexOf("#", from);
493
+ const at = question < 0 ? hash : hash < 0 ? question : Math.min(question, hash);
494
+ if (at < 0) return null;
495
+ const query = at === question ? value.slice(at + 1, hash > at ? hash : void 0) : null;
496
+ return { base: value.slice(0, at), query };
497
+ }
498
+ function decodeName(raw) {
499
+ try {
500
+ return decodeURIComponent(raw.replace(/\+/g, " "));
501
+ } catch {
502
+ return raw;
503
+ }
504
+ }
505
+ function makeUrlQueryPolicy(keepQueryParams = []) {
506
+ const keep = new Set(keepQueryParams.filter((name) => typeof name === "string"));
507
+ const maskQuery = (query) => {
508
+ const out = [];
509
+ for (const part of query.split("&")) {
510
+ if (!part) continue;
511
+ const eq = part.indexOf("=");
512
+ const name = eq < 0 ? part : part.slice(0, eq);
513
+ if (keep.size && keep.has(decodeName(name))) out.push(part);
514
+ else if (eq < 0) out.push(MASK);
515
+ else out.push(eq === part.length - 1 ? part : `${name}=${MASK}`);
516
+ }
517
+ return out.join("&");
518
+ };
519
+ const stripName = (name) => {
520
+ if (!name.includes("?") && !name.includes("#")) return name;
521
+ return name.split(" ").map((token) => {
522
+ if (!token.startsWith("/") && !SCHEME.test(token)) return token;
523
+ return splitUrl(token)?.base ?? token;
524
+ }).join(" ");
525
+ };
526
+ return {
527
+ attributes(attributes) {
528
+ let out = null;
529
+ const set = (key, value) => {
530
+ out ??= { ...attributes };
531
+ out[key] = value;
532
+ };
533
+ let dropped = null;
534
+ for (const key of URL_KEYS) {
535
+ const value = attributes[key];
536
+ if (typeof value !== "string") continue;
537
+ const split = splitUrl(value);
538
+ if (!split) continue;
539
+ set(key, split.base);
540
+ if (split.query) dropped ??= split.query;
541
+ }
542
+ for (const key of NAME_KEYS) {
543
+ const value = attributes[key];
544
+ if (typeof value !== "string") continue;
545
+ const stripped = stripName(value);
546
+ if (stripped !== value) set(key, stripped);
547
+ }
548
+ const current = attributes[QUERY_KEY];
549
+ if (typeof current === "string") {
550
+ const masked = maskQuery(current.startsWith("?") ? current.slice(1) : current);
551
+ if (masked !== current) set(QUERY_KEY, masked);
552
+ } else if (current !== void 0) {
553
+ set(QUERY_KEY, MASK);
554
+ } else if (dropped !== null) {
555
+ const masked = maskQuery(dropped);
556
+ if (masked) set(QUERY_KEY, masked);
557
+ }
558
+ return out ?? attributes;
559
+ },
560
+ name: stripName
561
+ };
562
+ }
563
+
564
+ // src/redact-exporter.ts
481
565
  var scrubbedResources = /* @__PURE__ */ new WeakMap();
482
566
  function redactResource(resource, redactor) {
483
567
  const cached = scrubbedResources.get(resource);
@@ -486,17 +570,41 @@ function redactResource(resource, redactor) {
486
570
  scrubbedResources.set(resource, scrubbed);
487
571
  return scrubbed;
488
572
  }
489
- function redactSpan(span, redactor) {
490
- const status = span.status.message ? { ...span.status, message: redactor.text(span.status.message) } : span.status;
573
+ var DEFAULT_QUERY_POLICY = makeUrlQueryPolicy();
574
+ function stripQueries(span, query) {
575
+ const name = query.name(span.name);
576
+ const attributes = query.attributes(span.attributes);
577
+ if (name === span.name && attributes === span.attributes) return span;
578
+ return wrap(span, { name, attributes });
579
+ }
580
+ function wrap(span, fields) {
491
581
  return {
492
- name: redactor.text(span.name),
582
+ name: fields.name,
493
583
  kind: span.kind,
494
584
  spanContext: () => span.spanContext(),
495
585
  parentSpanId: span.parentSpanId,
496
586
  startTime: span.startTime,
497
587
  endTime: span.endTime,
588
+ status: fields.status ?? span.status,
589
+ attributes: fields.attributes,
590
+ links: fields.links ?? span.links,
591
+ events: fields.events ?? span.events,
592
+ duration: span.duration,
593
+ ended: span.ended,
594
+ resource: fields.resource ?? span.resource,
595
+ instrumentationLibrary: span.instrumentationLibrary,
596
+ droppedAttributesCount: span.droppedAttributesCount,
597
+ droppedEventsCount: span.droppedEventsCount,
598
+ droppedLinksCount: span.droppedLinksCount
599
+ };
600
+ }
601
+ function redactSpan(span, redactor, query = DEFAULT_QUERY_POLICY) {
602
+ if (!redactor.enabled) return stripQueries(span, query);
603
+ const status = span.status.message ? { ...span.status, message: redactor.text(span.status.message) } : span.status;
604
+ return wrap(span, {
605
+ name: query.name(redactor.text(span.name)),
498
606
  status,
499
- attributes: redactor.exported(span.attributes),
607
+ attributes: query.attributes(redactor.exported(span.attributes)),
500
608
  links: span.links.map(
501
609
  (link) => link.attributes ? { ...link, attributes: redactor.exported(link.attributes) } : link
502
610
  ),
@@ -505,34 +613,27 @@ function redactSpan(span, redactor) {
505
613
  name: redactor.text(event.name),
506
614
  ...event.attributes ? { attributes: redactor.exported(event.attributes) } : {}
507
615
  })),
508
- duration: span.duration,
509
- ended: span.ended,
510
- resource: redactResource(span.resource, redactor),
511
- instrumentationLibrary: span.instrumentationLibrary,
512
- droppedAttributesCount: span.droppedAttributesCount,
513
- droppedEventsCount: span.droppedEventsCount,
514
- droppedLinksCount: span.droppedLinksCount
515
- };
616
+ resource: redactResource(span.resource, redactor)
617
+ });
516
618
  }
517
619
  var RedactingSpanExporter = class {
518
- constructor(inner, redactor) {
620
+ constructor(inner, redactor, query = DEFAULT_QUERY_POLICY) {
519
621
  this.inner = inner;
520
622
  this.redactor = redactor;
623
+ this.query = query;
521
624
  }
522
625
  inner;
523
626
  redactor;
627
+ query;
524
628
  export(spans, resultCallback) {
525
629
  const redactor = this.redactor();
526
- let scrubbed = spans;
630
+ const scrubbed = [];
527
631
  let failed = 0;
528
- if (redactor.enabled) {
529
- scrubbed = [];
530
- for (const span of spans) {
531
- try {
532
- scrubbed.push(redactSpan(span, redactor));
533
- } catch {
534
- failed++;
535
- }
632
+ for (const span of spans) {
633
+ try {
634
+ scrubbed.push(redactSpan(span, redactor, this.query));
635
+ } catch {
636
+ failed++;
536
637
  }
537
638
  }
538
639
  if (!failed) {
@@ -641,7 +742,7 @@ import { context, trace } from "@opentelemetry/api";
641
742
  import { getRPCMetadata, RPCType } from "@opentelemetry/core";
642
743
  var REQUEST_STATE = /* @__PURE__ */ Symbol.for("autter.runtime.request");
643
744
  var BOUND = /* @__PURE__ */ Symbol.for("autter.runtime.bound");
644
- var CAPTURED = /* @__PURE__ */ new WeakSet();
745
+ var CAPTURED = sharedSlot("requests", () => ({ captured: /* @__PURE__ */ new WeakSet() })).captured;
645
746
  var capturer = () => {
646
747
  };
647
748
  function setRequestExceptionCapturer(fn) {
@@ -667,14 +768,14 @@ function defaultShouldCapture(error) {
667
768
  return error instanceof RuntimeError || errorCodeOf(error) !== void 0 || responseStatusOf(error) >= 500;
668
769
  }
669
770
  function onRequestSpan(fn) {
670
- const active2 = context.active();
671
- const metadata = getRPCMetadata(active2);
771
+ const active = context.active();
772
+ const metadata = getRPCMetadata(active);
672
773
  const span = metadata?.type === RPCType.HTTP ? metadata.span : void 0;
673
- if (!span || !span.isRecording() || trace.getSpan(active2) === span) {
774
+ if (!span || !span.isRecording() || trace.getSpan(active) === span) {
674
775
  fn();
675
776
  return;
676
777
  }
677
- context.with(trace.setSpan(active2, span), fn);
778
+ context.with(trace.setSpan(active, span), fn);
678
779
  }
679
780
  function captureAtBoundary(error, state, rule = void 0, attributes) {
680
781
  let wanted;
@@ -713,7 +814,7 @@ function bindEmitter(emitter, state) {
713
814
  if (!target || typeof target !== "object" || target[BOUND]) return;
714
815
  target[BOUND] = true;
715
816
  const wrappers = /* @__PURE__ */ new WeakMap();
716
- const wrap = (listener) => {
817
+ const wrap2 = (listener) => {
717
818
  if (typeof listener !== "function") return listener;
718
819
  let wrapped = wrappers.get(listener);
719
820
  if (!wrapped) {
@@ -737,7 +838,7 @@ function bindEmitter(emitter, state) {
737
838
  const original = target[method];
738
839
  if (typeof original !== "function") continue;
739
840
  target[method] = function(event, listener) {
740
- return original.call(this, event, wrap(listener));
841
+ return original.call(this, event, wrap2(listener));
741
842
  };
742
843
  }
743
844
  for (const method of ["removeListener", "off"]) {
@@ -1176,6 +1277,13 @@ function installUnhandledRejectionCapture(capture, mode = unhandledRejectionsMod
1176
1277
  }
1177
1278
 
1178
1279
  // src/server.ts
1280
+ var S = sharedSlot("server", () => ({
1281
+ active: null,
1282
+ alwaysOnProvider: null,
1283
+ redactor: makeRedactor(true),
1284
+ loggerOnlyCapture: null,
1285
+ hookRequests: false
1286
+ }));
1179
1287
  var LLM_MARKER_ATTRIBUTES = [
1180
1288
  "gen_ai.operation.name",
1181
1289
  "gen_ai.system",
@@ -1303,9 +1411,9 @@ var ErrorTraceRetentionProcessor = class {
1303
1411
  }
1304
1412
  /** Promote the active trace, if any — called on captured errors. */
1305
1413
  retainActiveTrace() {
1306
- const active2 = trace2.getActiveSpan()?.spanContext();
1307
- if (!active2 || (active2.traceFlags & TraceFlags.SAMPLED) !== 0) return;
1308
- const entry = this.entryFor(active2.traceId);
1414
+ const active = trace2.getActiveSpan()?.spanContext();
1415
+ if (!active || (active.traceFlags & TraceFlags.SAMPLED) !== 0) return;
1416
+ const entry = this.entryFor(active.traceId);
1309
1417
  if (entry.retained) return;
1310
1418
  entry.retained = true;
1311
1419
  this.flush(entry);
@@ -1372,7 +1480,7 @@ function llmBaseAttributes(info) {
1372
1480
  ...info.sessionId ? { "autter.session_id": info.sessionId } : {},
1373
1481
  // Caller-supplied extras go through redaction like every other
1374
1482
  // custom attribute family (prompts can contain emails/keys).
1375
- ...info.attributes ? activeRedactor(info.attributes) : {}
1483
+ ...info.attributes ? S.redactor(info.attributes) : {}
1376
1484
  };
1377
1485
  }
1378
1486
  function usageAttributes(usage) {
@@ -1413,7 +1521,7 @@ async function runLlmSpan(tracer, info, fn) {
1413
1521
  },
1414
1522
  setResponseModel,
1415
1523
  setModel: setResponseModel,
1416
- setAttributes: (attributes) => span.setAttributes(activeRedactor(attributes))
1524
+ setAttributes: (attributes) => span.setAttributes(S.redactor(attributes))
1417
1525
  };
1418
1526
  try {
1419
1527
  const result = await context2.with(
@@ -1475,19 +1583,19 @@ async function runWithSpan(tracer, name, fn, attributes, links) {
1475
1583
  }
1476
1584
  function recordError(span, err) {
1477
1585
  const isErr = isError(err);
1478
- const message = activeRedactor.text(isErr ? err.message : String(err));
1586
+ const message = S.redactor.text(isErr ? err.message : String(err));
1479
1587
  if (isErr) {
1480
1588
  span.addEvent("exception", {
1481
1589
  "exception.type": err.name,
1482
1590
  "exception.message": message,
1483
- ...err.stack ? { "exception.stacktrace": activeRedactor.text(err.stack) } : {},
1484
- ...breadcrumbEventAttributes(activeRedactor.text, err)
1591
+ ...err.stack ? { "exception.stacktrace": S.redactor.text(err.stack) } : {},
1592
+ ...breadcrumbEventAttributes(S.redactor.text, err)
1485
1593
  });
1486
1594
  }
1487
1595
  span.setStatus({ code: SpanStatusCode.ERROR, message });
1488
1596
  }
1489
1597
  function redactWithActive(attributes) {
1490
- return activeRedactor(attributes);
1598
+ return S.redactor(attributes);
1491
1599
  }
1492
1600
  function captureExpressRoute(_span, response) {
1493
1601
  if (!(response instanceof ServerResponse)) return;
@@ -1500,42 +1608,41 @@ function captureExpressRoute(_span, response) {
1500
1608
  };
1501
1609
  response.prependListener("finish", setRoute);
1502
1610
  response.prependListener("close", setRoute);
1503
- if (hookRequests) startHookRequest(response);
1611
+ if (S.hookRequests) startHookRequest(response);
1504
1612
  }
1505
- var hookRequests = false;
1506
1613
  function structuredErrorAttributes(error) {
1507
1614
  const attrs = { ...errorAttributes(error, { causes: false }) };
1508
1615
  const internal = errorInternal(error);
1509
1616
  if (internal) {
1510
1617
  try {
1511
1618
  attrs["autter.error.internal"] = JSON.stringify(
1512
- activeRedactor(internal)
1619
+ S.redactor(internal)
1513
1620
  ).slice(0, 4e3);
1514
1621
  } catch {
1515
1622
  }
1516
1623
  }
1517
1624
  return attrs;
1518
1625
  }
1519
- var active = null;
1520
- var activeAlwaysOnProvider = null;
1521
- var activeRedactor = makeRedactor(true);
1522
1626
  function initAutterServer(options) {
1523
- if (active) return active;
1627
+ if (S.active) return S.active;
1524
1628
  const endpoint = (options.endpoint ?? "https://otlp.autter.dev").replace(
1525
1629
  /\/$/,
1526
1630
  ""
1527
1631
  );
1528
1632
  const headers = { authorization: `Bearer ${options.apiKey}` };
1633
+ const redactor = makeRedactor(options.redactAttributes ?? true);
1634
+ const queryPolicy = makeUrlQueryPolicy(options.keepQueryParams);
1529
1635
  const traceExporter = () => new CountingExporter(
1530
1636
  new RedactingSpanExporter(
1531
1637
  new OTLPTraceExporter({ url: `${endpoint}/v1/traces`, headers }),
1532
- () => activeRedactor
1638
+ () => redactor,
1639
+ queryPolicy
1533
1640
  )
1534
1641
  );
1535
1642
  const environment = options.environment ?? process.env.NODE_ENV ?? "production";
1536
1643
  if (isDebugEnabled() || options.debug === true) setDebugMode(true);
1537
1644
  debugLog(`initialising service=${options.service} endpoint=${endpoint}`);
1538
- activeRedactor = makeRedactor(options.redactAttributes ?? true);
1645
+ S.redactor = redactor;
1539
1646
  const distro = options.distro ?? SDK_IDENTITY;
1540
1647
  configureCompatCheck({ endpoint, enabled: options.compatCheck !== false, sdk: distro });
1541
1648
  const resource = new Resource2({
@@ -1584,7 +1691,7 @@ function initAutterServer(options) {
1584
1691
  // 60 s export.
1585
1692
  temporalityPreference: AggregationTemporalityPreference.DELTA
1586
1693
  }),
1587
- () => activeRedactor
1694
+ () => redactor
1588
1695
  ),
1589
1696
  exportIntervalMillis: options.metricIntervalMs ?? 6e4
1590
1697
  });
@@ -1628,12 +1735,12 @@ function initAutterServer(options) {
1628
1735
  errorTraceBuffer?.retainActiveTrace();
1629
1736
  telemetryStats.markCaptured();
1630
1737
  const isErr = isError(error);
1631
- const message = activeRedactor.text(isErr ? error.message : String(error));
1632
- const stackText = isErr && error.stack ? activeRedactor.text(error.stack) : "";
1738
+ const message = redactor.text(isErr ? error.message : String(error));
1739
+ const stackText = isErr && error.stack ? redactor.text(error.stack) : "";
1633
1740
  const split = splitFingerprint(attributes);
1634
- const fingerprint = fingerprintEventAttributes(split.fingerprint, activeRedactor.text);
1741
+ const fingerprint = fingerprintEventAttributes(split.fingerprint, redactor.text);
1635
1742
  if (fingerprint["autter.fingerprint"]) noteCompatFeature("fingerprint_override");
1636
- const redacted = activeRedactor(split.attributes);
1743
+ const redacted = redactor(split.attributes);
1637
1744
  const activeSpan = trace2.getActiveSpan();
1638
1745
  const reuseActive = activeSpan?.isRecording() === true;
1639
1746
  const span = reuseActive ? activeSpan : errorTracer.startSpan(isErr ? error.name : "Error");
@@ -1660,17 +1767,17 @@ function initAutterServer(options) {
1660
1767
  "exception.stacktrace": stackText,
1661
1768
  ...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
1662
1769
  ...declared,
1663
- ...breadcrumbEventAttributes(activeRedactor.text, error)
1770
+ ...breadcrumbEventAttributes(redactor.text, error)
1664
1771
  });
1665
1772
  } else {
1666
1773
  const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureException")).join("\n");
1667
1774
  span.addEvent("exception", {
1668
1775
  "exception.type": isErr ? error.name : "Error",
1669
1776
  "exception.message": message,
1670
- ...stack ? { "exception.stacktrace": activeRedactor.text(stack) } : {},
1777
+ ...stack ? { "exception.stacktrace": redactor.text(stack) } : {},
1671
1778
  ...redacted["autter.handled"] === true ? { "autter.handled": true, "autter.sampled": redacted["autter.sampled"] === true } : {},
1672
1779
  ...declared,
1673
- ...breadcrumbEventAttributes(activeRedactor.text, error)
1780
+ ...breadcrumbEventAttributes(redactor.text, error)
1674
1781
  });
1675
1782
  }
1676
1783
  span.setStatus({ code: SpanStatusCode.ERROR, message });
@@ -1682,16 +1789,16 @@ function initAutterServer(options) {
1682
1789
  }
1683
1790
  telemetryStats.markCaptured();
1684
1791
  const stack = new Error().stack?.split("\n").filter((line, i) => i === 0 || !line.includes("captureMessage")).join("\n");
1685
- const safeMessage = activeRedactor.text(message);
1792
+ const safeMessage = redactor.text(message);
1686
1793
  const span = errorTracer.startSpan("Message", {
1687
- attributes: { "autter.severity": severity, ...activeRedactor(attributes) }
1794
+ attributes: { "autter.severity": severity, ...redactor(attributes) }
1688
1795
  });
1689
1796
  span.addEvent("exception", {
1690
1797
  "exception.type": "Message",
1691
1798
  "exception.message": safeMessage,
1692
- ...stack ? { "exception.stacktrace": activeRedactor.text(stack) } : {},
1799
+ ...stack ? { "exception.stacktrace": redactor.text(stack) } : {},
1693
1800
  "autter.severity": severity,
1694
- ...breadcrumbEventAttributes(activeRedactor.text)
1801
+ ...breadcrumbEventAttributes(redactor.text)
1695
1802
  });
1696
1803
  span.setStatus({ code: SpanStatusCode.ERROR, message: safeMessage });
1697
1804
  span.end();
@@ -1702,11 +1809,11 @@ function initAutterServer(options) {
1702
1809
  const activeSpan = trace2.getActiveSpan();
1703
1810
  const reuseActive = activeSpan?.isRecording() === true;
1704
1811
  const span = reuseActive ? activeSpan : errorTracer.startSpan("OutcomeFailure");
1705
- const safeOutcome = activeRedactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1812
+ const safeOutcome = redactor({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1706
1813
  const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
1707
1814
  const safeMessage = String(safeOutcome["autter.outcome.message"] ?? "failed");
1708
1815
  span.addEvent("autter.outcome", {
1709
- ...activeRedactor(attributes),
1816
+ ...redactor(attributes),
1710
1817
  "autter.outcome.status": "error",
1711
1818
  "autter.outcome.name": safeName,
1712
1819
  "autter.outcome.message": safeMessage
@@ -1722,11 +1829,11 @@ function initAutterServer(options) {
1722
1829
  distro,
1723
1830
  release: options.release,
1724
1831
  options: options.logging,
1725
- redact: activeRedactor,
1726
- run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn, activeRedactor(attributes), links),
1832
+ redact: redactor,
1833
+ run: (name, fn, attributes, links) => runWithSpan(processTracer, name, fn, redactor(attributes), links),
1727
1834
  reportOutcome: reportOutcome2
1728
1835
  });
1729
- hookRequests = options.logging?.requests === true;
1836
+ S.hookRequests = options.logging?.requests === true;
1730
1837
  let onCrash = null;
1731
1838
  let uninstallRejections = null;
1732
1839
  if (options.captureGlobalErrors !== false) {
@@ -1769,17 +1876,20 @@ function initAutterServer(options) {
1769
1876
  captureException: captureException2,
1770
1877
  captureMessage: captureMessage2,
1771
1878
  reportOutcome: reportOutcome2,
1772
- withProcessSpan: (name, fn, attributes) => runWithSpan(processTracer, name, fn, activeRedactor(attributes)),
1879
+ withProcessSpan: (name, fn, attributes) => runWithSpan(processTracer, name, fn, redactor(attributes)),
1773
1880
  withLlmCall: (info, fn) => runLlmSpan(llmTracer, info, fn),
1774
1881
  trackLlmCall: (call) => recordLlmCall(llmTracer, call),
1775
1882
  shutdown: async () => {
1776
1883
  const logShutdown = await Promise.allSettled([shutdownRuntimeLogger()]);
1777
- hookRequests = false;
1778
1884
  if (onCrash) process.off("uncaughtExceptionMonitor", onCrash);
1779
1885
  uninstallRejections?.();
1780
1886
  stopMemoryMetrics?.();
1781
- active = null;
1782
- activeAlwaysOnProvider = null;
1887
+ if (S.active === server) {
1888
+ S.active = null;
1889
+ S.alwaysOnProvider = null;
1890
+ S.hookRequests = false;
1891
+ S.redactor = makeRedactor(true);
1892
+ }
1783
1893
  autoFlushHandle?.dispose();
1784
1894
  autoFlushHandle = null;
1785
1895
  unregisterFlushTargets();
@@ -1788,82 +1898,81 @@ function initAutterServer(options) {
1788
1898
  if (logShutdown[0]?.status === "rejected") throw logShutdown[0].reason;
1789
1899
  }
1790
1900
  };
1791
- active = server;
1792
- activeAlwaysOnProvider = alwaysOnProvider;
1901
+ S.active = server;
1902
+ S.alwaysOnProvider = alwaysOnProvider;
1793
1903
  return server;
1794
1904
  }
1795
1905
  function captureException(error, attributes) {
1796
- if (active) {
1797
- active.captureException(error, attributes);
1906
+ if (S.active) {
1907
+ S.active.captureException(error, attributes);
1798
1908
  return;
1799
1909
  }
1800
- if (loggerOnlyCapture) {
1801
- loggerOnlyCapture(error, attributes);
1910
+ if (S.loggerOnlyCapture) {
1911
+ S.loggerOnlyCapture(error, attributes);
1802
1912
  return;
1803
1913
  }
1804
1914
  markCaptured(error);
1805
1915
  noteOperationError(error);
1806
1916
  const split = splitFingerprint(attributes);
1807
- const fingerprint = fingerprintEventAttributes(split.fingerprint, activeRedactor.text);
1917
+ const fingerprint = fingerprintEventAttributes(split.fingerprint, S.redactor.text);
1808
1918
  notifyException(error, { ...split.attributes, ...fingerprint });
1809
1919
  const span = trace2.getTracer("autter-errors").startSpan(isError(error) ? error.name : "Error", {
1810
- attributes: { ...activeRedactor(split.attributes), ...fingerprint }
1920
+ attributes: { ...S.redactor(split.attributes), ...fingerprint }
1811
1921
  });
1812
1922
  recordError(span, error);
1813
1923
  span.end();
1814
1924
  }
1815
- var loggerOnlyCapture = null;
1816
1925
  function setLoggerOnlyCapture(fn) {
1817
- loggerOnlyCapture = fn;
1926
+ S.loggerOnlyCapture = fn;
1818
1927
  }
1819
1928
  function serverActive() {
1820
- return active !== null;
1929
+ return S.active !== null;
1821
1930
  }
1822
1931
  setRequestExceptionCapturer((error, attributes) => captureException(error, attributes));
1823
1932
  setRequestSpanAnnotator((attributes) => {
1824
1933
  const span = trace2.getActiveSpan();
1825
- if (span?.isRecording()) span.setAttributes(activeRedactor(splitFingerprint(attributes).attributes));
1934
+ if (span?.isRecording()) span.setAttributes(S.redactor(splitFingerprint(attributes).attributes));
1826
1935
  });
1827
1936
  function withProcessSpan(name, fn, attributes) {
1828
- if (active) return active.withProcessSpan(name, fn, attributes);
1937
+ if (S.active) return S.active.withProcessSpan(name, fn, attributes);
1829
1938
  return runWithSpan(
1830
1939
  trace2.getTracer("autter-processes"),
1831
1940
  name,
1832
1941
  fn,
1833
- activeRedactor(attributes)
1942
+ S.redactor(attributes)
1834
1943
  );
1835
1944
  }
1836
1945
  function withLlmCall(info, fn) {
1837
- if (active) return active.withLlmCall(info, fn);
1946
+ if (S.active) return S.active.withLlmCall(info, fn);
1838
1947
  return runLlmSpan(trace2.getTracer("autter-llm"), info, fn);
1839
1948
  }
1840
1949
  function trackLlmCall(call) {
1841
- if (active) {
1842
- active.trackLlmCall(call);
1950
+ if (S.active) {
1951
+ S.active.trackLlmCall(call);
1843
1952
  return;
1844
1953
  }
1845
1954
  recordLlmCall(trace2.getTracer("autter-llm"), call);
1846
1955
  }
1847
1956
  function captureMessage(message, severity = "warning", attributes) {
1848
- if (active) {
1849
- active.captureMessage(message, severity, attributes);
1957
+ if (S.active) {
1958
+ S.active.captureMessage(message, severity, attributes);
1850
1959
  return;
1851
1960
  }
1852
- const safeMessage = activeRedactor.text(message);
1961
+ const safeMessage = S.redactor.text(message);
1853
1962
  const span = trace2.getTracer("autter-errors").startSpan("Message", {
1854
- attributes: { "autter.severity": severity, ...activeRedactor(attributes) }
1963
+ attributes: { "autter.severity": severity, ...S.redactor(attributes) }
1855
1964
  });
1856
1965
  span.addEvent("exception", {
1857
1966
  "exception.type": "Message",
1858
1967
  "exception.message": safeMessage,
1859
1968
  "autter.severity": severity,
1860
- ...breadcrumbEventAttributes(activeRedactor.text)
1969
+ ...breadcrumbEventAttributes(S.redactor.text)
1861
1970
  });
1862
1971
  span.setStatus({ code: SpanStatusCode.ERROR, message: safeMessage });
1863
1972
  span.end();
1864
1973
  }
1865
1974
  function reportOutcome(name, message, attributes) {
1866
- if (active) return active.reportOutcome(name, message, attributes);
1975
+ if (S.active) return S.active.reportOutcome(name, message, attributes);
1867
1976
  const span = trace2.getTracer("autter-outcomes").startSpan("OutcomeFailure");
1868
1977
  const safeOutcome = redactAttributes({ "autter.outcome.name": name.slice(0, 200), "autter.outcome.message": message.slice(0, 1e3) });
1869
1978
  const safeName = String(safeOutcome["autter.outcome.name"] ?? "operation");
@@ -1885,13 +1994,13 @@ function makeSafeCapture(options) {
1885
1994
  };
1886
1995
  }
1887
1996
  function alwaysOnTracer(name) {
1888
- return activeAlwaysOnProvider ? activeAlwaysOnProvider.getTracer(name) : trace2.getTracer(name);
1997
+ return S.alwaysOnProvider ? S.alwaysOnProvider.getTracer(name) : trace2.getTracer(name);
1889
1998
  }
1890
1999
  function autterLlmTracer() {
1891
2000
  return alwaysOnTracer("autter-llm");
1892
2001
  }
1893
2002
  async function emitLlmSelftestTrace() {
1894
- const provider = activeAlwaysOnProvider;
2003
+ const provider = S.alwaysOnProvider;
1895
2004
  if (!provider) {
1896
2005
  throw new Error(
1897
2006
  "emitLlmSelftestTrace() requires initAutterServer() to have been called"
@@ -2149,14 +2258,14 @@ function startCaughtExceptionSampler(options = {}) {
2149
2258
  const rate = Math.max(0, Math.min(1, options.sampleRate ?? 0.01));
2150
2259
  const cap = Math.max(1, Math.min(100, options.maxPerMinute ?? 10));
2151
2260
  const session = new inspector.Session();
2152
- let active2 = true;
2261
+ let active = true;
2153
2262
  let minute = 0;
2154
2263
  let sent = 0;
2155
2264
  session.connect();
2156
2265
  session.on("Debugger.paused", (message) => {
2157
2266
  session.post("Debugger.resume", () => {
2158
2267
  });
2159
- if (!active2 || message.params.reason !== "exception") return;
2268
+ if (!active || message.params.reason !== "exception") return;
2160
2269
  const nowMinute = Math.floor(Date.now() / 6e4);
2161
2270
  if (nowMinute !== minute) {
2162
2271
  minute = nowMinute;
@@ -2171,16 +2280,16 @@ function startCaughtExceptionSampler(options = {}) {
2171
2280
  error.stack = `${error.name}: ${error.message}
2172
2281
  ${frames.join("\n")}`;
2173
2282
  queueMicrotask(() => {
2174
- if (active2) captureException(error, { "autter.handled": true, "autter.sampled": true });
2283
+ if (active) captureException(error, { "autter.handled": true, "autter.sampled": true });
2175
2284
  });
2176
2285
  });
2177
2286
  session.post("Debugger.enable", (error) => {
2178
- if (!error && active2) session.post("Debugger.setPauseOnExceptions", { state: "all" }, () => {
2287
+ if (!error && active) session.post("Debugger.setPauseOnExceptions", { state: "all" }, () => {
2179
2288
  });
2180
2289
  });
2181
2290
  return { stop() {
2182
- if (!active2) return;
2183
- active2 = false;
2291
+ if (!active) return;
2292
+ active = false;
2184
2293
  session.post("Debugger.setPauseOnExceptions", { state: "none" }, () => {
2185
2294
  session.post("Debugger.disable", () => session.disconnect());
2186
2295
  });
@@ -2228,9 +2337,9 @@ import {
2228
2337
  SpanStatusCode as SpanStatusCode3,
2229
2338
  trace as trace3
2230
2339
  } from "@opentelemetry/api";
2231
- var activeLogging = null;
2340
+ var L = sharedSlot("logging", () => ({ active: null }));
2232
2341
  function initAutterLogging(options) {
2233
- if (activeLogging) return activeLogging;
2342
+ if (L.active) return L.active;
2234
2343
  if (serverActive()) {
2235
2344
  console.warn(
2236
2345
  "[autter-runtime] initAutterLogging() ignored: initAutterServer() is already active and includes logging"
@@ -2332,11 +2441,11 @@ function initAutterLogging(options) {
2332
2441
  autoFlushHandle?.dispose();
2333
2442
  autoFlushHandle = null;
2334
2443
  unregisterFlushTargets();
2335
- activeLogging = null;
2444
+ if (L.active === handle) L.active = null;
2336
2445
  await shutdownRuntimeLogger();
2337
2446
  }
2338
2447
  };
2339
- activeLogging = handle;
2448
+ L.active = handle;
2340
2449
  return handle;
2341
2450
  }
2342
2451