raindrop-ai 0.4.0 → 0.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.
@@ -39,7 +39,69 @@ module.exports = __toCommonJS(tracing_exports);
39
39
  var import_api6 = require("@opentelemetry/api");
40
40
  var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
41
41
 
42
- // ../core/dist/chunk-3V4MIA75.js
42
+ // ../core/dist/chunk-BYBMRLZM.js
43
+ var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
44
+ var PROBE_SCOPE = { correlationId: "" };
45
+ var EvalScopeStorage = class {
46
+ constructor() {
47
+ this._als = null;
48
+ this._probed = false;
49
+ }
50
+ maybeAdoptAsyncLocalStorage() {
51
+ if (this._probed) return;
52
+ this._probed = true;
53
+ try {
54
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
55
+ if (!Ctor) return;
56
+ const als = new Ctor();
57
+ als.run(PROBE_SCOPE, () => {
58
+ });
59
+ this._als = als;
60
+ } catch (e) {
61
+ this._als = null;
62
+ }
63
+ }
64
+ run(scope, callback) {
65
+ this.maybeAdoptAsyncLocalStorage();
66
+ if (this._als) return this._als.run(scope, callback);
67
+ const previous = this._syncScope;
68
+ this._syncScope = scope;
69
+ try {
70
+ return callback();
71
+ } finally {
72
+ this._syncScope = previous;
73
+ }
74
+ }
75
+ current() {
76
+ this.maybeAdoptAsyncLocalStorage();
77
+ if (this._als) return this._als.getStore();
78
+ return this._syncScope;
79
+ }
80
+ };
81
+ var EVAL_SCOPE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.evalScopeStorage");
82
+ function evalScopeStorage() {
83
+ const holder = globalThis;
84
+ let storage = holder[EVAL_SCOPE_STORAGE_KEY];
85
+ if (!storage) {
86
+ storage = new EvalScopeStorage();
87
+ holder[EVAL_SCOPE_STORAGE_KEY] = storage;
88
+ }
89
+ return storage;
90
+ }
91
+ function currentEvalScope() {
92
+ try {
93
+ return evalScopeStorage().current();
94
+ } catch (e) {
95
+ return void 0;
96
+ }
97
+ }
98
+ function evalScopeAttributes() {
99
+ const scope = currentEvalScope();
100
+ if (!scope) return {};
101
+ return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
102
+ }
103
+
104
+ // ../core/dist/chunk-T53LQAH7.js
43
105
  function normalizeFeatureFlags(input) {
44
106
  if (Array.isArray(input)) {
45
107
  return Object.fromEntries(input.map((name) => [name, "true"]));
@@ -462,6 +524,7 @@ async function postJson(url, body, headers, opts) {
462
524
  const resp = await runWithTracingSuppressed(
463
525
  () => fetch(url, {
464
526
  method: "POST",
527
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
465
528
  headers: {
466
529
  "Content-Type": "application/json",
467
530
  ...headers
@@ -590,6 +653,55 @@ function attrDouble(key, value) {
590
653
  if (!Number.isFinite(value)) return void 0;
591
654
  return { key, value: { doubleValue: value } };
592
655
  }
656
+ var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
657
+ function state() {
658
+ const holder = globalThis;
659
+ let current = holder[STATE_KEY];
660
+ if (!current) {
661
+ let storage = null;
662
+ try {
663
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
664
+ if (Ctor) storage = new Ctor();
665
+ } catch (e) {
666
+ storage = null;
667
+ }
668
+ current = {
669
+ storage,
670
+ syncDestination: void 0,
671
+ spanDestinations: /* @__PURE__ */ new WeakMap()
672
+ };
673
+ holder[STATE_KEY] = current;
674
+ }
675
+ return current;
676
+ }
677
+ function currentReplayTraceDestination() {
678
+ var _a, _b;
679
+ const routing = state();
680
+ return (_b = (_a = routing.storage) == null ? void 0 : _a.getStore()) != null ? _b : routing.syncDestination;
681
+ }
682
+ function rememberReplayTraceDestination(span) {
683
+ const destination = currentReplayTraceDestination();
684
+ if (destination) state().spanDestinations.set(span, destination);
685
+ }
686
+ function copyReplayTraceDestination(source, target) {
687
+ const destination = state().spanDestinations.get(source);
688
+ if (destination) state().spanDestinations.set(target, destination);
689
+ }
690
+ function replayTraceDestinationFor(value) {
691
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
692
+ return void 0;
693
+ }
694
+ return state().spanDestinations.get(value);
695
+ }
696
+ function recordReplayExportedSpan(destination, spanId, traceId) {
697
+ var _a, _b;
698
+ if (!destination || !spanId || !traceId) return;
699
+ (_a = destination.exportedSpanIds) == null ? void 0 : _a.add(spanId);
700
+ (_b = destination.exportedTraceIds) == null ? void 0 : _b.add(traceId);
701
+ }
702
+ function replayTraceUrl(baseUrl) {
703
+ return `${baseUrl.replace(/\/+$/, "")}/v1/traces`;
704
+ }
593
705
  var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
594
706
  var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
595
707
  var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
@@ -655,19 +767,23 @@ function resolveLocalDebuggerBaseUrl(baseUrl) {
655
767
  function localDebuggerEnabled(baseUrl) {
656
768
  return resolveLocalDebuggerBaseUrl(baseUrl) !== null;
657
769
  }
770
+ var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
658
771
  function mirrorTraceExportToLocalDebugger(body, options = {}) {
659
772
  var _a;
660
773
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
661
- if (!baseUrl) return;
662
- void postJson(`${baseUrl}traces`, body, {}, {
774
+ if (!baseUrl) return Promise.resolve();
775
+ return postJson(`${baseUrl}traces`, body, {}, {
663
776
  maxAttempts: 1,
664
777
  debug: (_a = options.debug) != null ? _a : false,
665
- sdkName: options.sdkName
778
+ sdkName: options.sdkName,
779
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
666
780
  }).catch(() => {
667
781
  });
668
782
  }
669
783
  function sendLocalDebuggerLiveEvent(event, options = {}) {
670
784
  var _a, _b;
785
+ const destination = currentReplayTraceDestination();
786
+ if (destination && destination.kind !== "workshop") return;
671
787
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
672
788
  if (!baseUrl) return;
673
789
  void postJson(
@@ -1096,570 +1212,179 @@ var import_instrumentation_anthropic = require("@traceloop/instrumentation-anthr
1096
1212
  var import_instrumentation_bedrock = require("@traceloop/instrumentation-bedrock");
1097
1213
  var import_instrumentation_chromadb = require("@traceloop/instrumentation-chromadb");
1098
1214
  var import_instrumentation_cohere = require("@traceloop/instrumentation-cohere");
1099
- var import_instrumentation_openai = require("@traceloop/instrumentation-openai");
1100
1215
  var import_instrumentation_langchain = require("@traceloop/instrumentation-langchain");
1101
1216
  var import_instrumentation_llamaindex = require("@traceloop/instrumentation-llamaindex");
1217
+ var import_instrumentation_openai = require("@traceloop/instrumentation-openai");
1102
1218
  var import_instrumentation_pinecone = require("@traceloop/instrumentation-pinecone");
1103
1219
  var import_instrumentation_qdrant = require("@traceloop/instrumentation-qdrant");
1104
1220
  var import_instrumentation_together = require("@traceloop/instrumentation-together");
1105
1221
  var import_instrumentation_vertexai = require("@traceloop/instrumentation-vertexai");
1222
+ var import_weakref = require("weakref");
1106
1223
 
1107
- // src/tracing/otel-core/index.ts
1108
- var import_api = require("@opentelemetry/api");
1109
- var import_core = require("@opentelemetry/core");
1110
- var import_exporter_trace_otlp_proto = require("@opentelemetry/exporter-trace-otlp-proto");
1111
- var import_instrumentation = require("@opentelemetry/instrumentation");
1112
- var resourceModule = __toESM(require("@opentelemetry/resources"));
1113
- var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
1114
- var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
1115
- var import_ai_semantic_conventions = require("@traceloop/ai-semantic-conventions");
1116
- var ALL_INSTRUMENTATION_LIBRARIES = "all";
1117
- var TRACER_NAME = "@traceloop/node-server-sdk";
1118
- var WORKFLOW_NAME_KEY = /* @__PURE__ */ Symbol.for("raindrop.otelCore.workflowName");
1119
- var ENTITY_NAME_KEY = /* @__PURE__ */ Symbol.for("raindrop.otelCore.entityName");
1120
- var ASSOCIATION_PROPERTIES_KEY = /* @__PURE__ */ Symbol.for("raindrop.otelCore.associationProperties");
1121
- var INSTRUMENTATION_LIBRARIES = [
1122
- "ai",
1123
- "@traceloop/node-server-sdk",
1124
- "@traceloop/instrumentation-openai",
1125
- "@traceloop/instrumentation-langchain",
1126
- "@traceloop/instrumentation-chroma",
1127
- "@traceloop/instrumentation-chromadb",
1128
- "@traceloop/instrumentation-anthropic",
1129
- "@traceloop/instrumentation-llamaindex",
1130
- "@traceloop/instrumentation-vertexai",
1131
- "@traceloop/instrumentation-bedrock",
1132
- "@traceloop/instrumentation-cohere",
1133
- "@traceloop/instrumentation-pinecone",
1134
- "@traceloop/instrumentation-qdrant",
1135
- "@traceloop/instrumentation-together",
1136
- TRACER_NAME,
1137
- "traceloop.tracer"
1138
- ];
1139
- var AI_GENERATE_TEXT = "ai.generateText.doGenerate";
1140
- var AI_STREAM_TEXT = "ai.streamText.doStream";
1141
- var AI_RESPONSE_TEXT = "ai.response.text";
1142
- var AI_PROMPT_MESSAGES = "ai.prompt.messages";
1143
- var AI_PROMPT_TOKENS = "ai.usage.promptTokens";
1144
- var AI_COMPLETION_TOKENS = "ai.usage.completionTokens";
1145
- var AI_MODEL_PROVIDER = "ai.model.provider";
1146
- var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.otelCore.state");
1147
- function getState() {
1148
- var _a;
1149
- const holder = globalThis;
1150
- (_a = holder[STATE_KEY]) != null ? _a : holder[STATE_KEY] = {};
1151
- return holder[STATE_KEY];
1152
- }
1153
- function parseHeaders(value) {
1154
- const headers = {};
1155
- if (!value) return headers;
1156
- for (const pair of value.split(",")) {
1157
- const separator = pair.indexOf("=");
1158
- if (separator <= 0) continue;
1159
- try {
1160
- const key = decodeURIComponent(pair.slice(0, separator).trim());
1161
- const val = decodeURIComponent(pair.slice(separator + 1).trim());
1162
- if (key && val) headers[key] = val;
1163
- } catch (e) {
1164
- }
1165
- }
1166
- return headers;
1224
+ // src/lib/inject-als.ts
1225
+ var import_node_async_hooks = require("async_hooks");
1226
+ if (!globalThis.RAINDROP_ASYNC_LOCAL_STORAGE) {
1227
+ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_node_async_hooks.AsyncLocalStorage;
1167
1228
  }
1168
- function safeStringify(value) {
1169
- try {
1170
- const result = JSON.stringify(value);
1171
- return result === void 0 ? String(value) : result;
1172
- } catch (e) {
1173
- return "[unserializable]";
1174
- }
1229
+
1230
+ // src/tracing/direct/http.ts
1231
+ function wait2(ms) {
1232
+ return new Promise((resolve) => setTimeout(resolve, ms));
1175
1233
  }
1176
- function createResource(attributes) {
1177
- if ("resourceFromAttributes" in resourceModule) {
1178
- const factory = resourceModule.resourceFromAttributes;
1179
- if (typeof factory === "function") return factory(attributes);
1180
- }
1181
- return new resourceModule.Resource(attributes);
1234
+ function formatEndpoint2(endpoint) {
1235
+ if (!endpoint) return void 0;
1236
+ return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
1182
1237
  }
1183
- function detectRuntimeResource() {
1184
- try {
1185
- if ("detectResourcesSync" in resourceModule && typeof resourceModule.detectResourcesSync === "function" && "envDetectorSync" in resourceModule) {
1186
- return resourceModule.detectResourcesSync({
1187
- detectors: [
1188
- resourceModule.envDetectorSync,
1189
- resourceModule.processDetectorSync,
1190
- resourceModule.hostDetectorSync
1191
- ]
1192
- });
1193
- }
1194
- if ("detectResources" in resourceModule && typeof resourceModule.detectResources === "function" && "envDetector" in resourceModule) {
1195
- const detected = resourceModule.detectResources({
1196
- detectors: [
1197
- resourceModule.envDetector,
1198
- resourceModule.processDetector,
1199
- resourceModule.hostDetector
1200
- ]
1201
- });
1202
- if (!(detected instanceof Promise)) {
1203
- return detected;
1204
- }
1205
- }
1206
- } catch (e) {
1238
+ function parseRetryAfter2(headers) {
1239
+ var _a;
1240
+ const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
1241
+ if (!value) return void 0;
1242
+ const asNumber = Number(value);
1243
+ if (!Number.isNaN(asNumber)) return asNumber * 1e3;
1244
+ const asDate = new Date(value).getTime();
1245
+ if (!Number.isNaN(asDate)) {
1246
+ const delta = asDate - Date.now();
1247
+ return delta > 0 ? delta : 0;
1207
1248
  }
1208
1249
  return void 0;
1209
1250
  }
1210
- function logLevel(level) {
1211
- switch (level) {
1212
- case "debug":
1213
- return import_api.DiagLogLevel.DEBUG;
1214
- case "info":
1215
- return import_api.DiagLogLevel.INFO;
1216
- case "warn":
1217
- return import_api.DiagLogLevel.WARN;
1218
- default:
1219
- return import_api.DiagLogLevel.ERROR;
1251
+ function getRetryDelayMs2(attemptNumber, previousError) {
1252
+ if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
1253
+ const v = previousError.retryAfterMs;
1254
+ if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
1220
1255
  }
1256
+ if (attemptNumber <= 1) return 0;
1257
+ const base = 500;
1258
+ const factor = Math.pow(2, attemptNumber - 2);
1259
+ return Math.min(base * factor, MAX_RETRY_DELAY_MS);
1221
1260
  }
1222
- function transformAiSdkSpan(span) {
1223
- const names = {
1224
- [AI_GENERATE_TEXT]: "ai.generateText.generate",
1225
- [AI_STREAM_TEXT]: "ai.streamText.stream"
1226
- };
1227
- if (!(span.name in names)) return span;
1228
- const attributes = span.attributes;
1229
- if (AI_RESPONSE_TEXT in attributes) {
1230
- const response = attributes[AI_RESPONSE_TEXT];
1231
- if (typeof response === "string") {
1232
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_COMPLETIONS}.0.content`] = response;
1261
+ async function withRetry2(operation, opName, opts) {
1262
+ let lastError = void 0;
1263
+ for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
1264
+ if (attemptNumber > 1) {
1265
+ const delay = getRetryDelayMs2(attemptNumber, lastError);
1266
+ if (opts.debug) {
1267
+ console.warn(
1268
+ `[raindrop] ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
1269
+ );
1270
+ }
1271
+ if (delay > 0) await wait2(delay);
1272
+ } else if (opts.debug) {
1273
+ console.log(`[raindrop] ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
1233
1274
  }
1234
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_COMPLETIONS}.0.role`] = "assistant";
1235
- delete attributes[AI_RESPONSE_TEXT];
1236
- }
1237
- if (AI_PROMPT_MESSAGES in attributes) {
1238
1275
  try {
1239
- const parsed = JSON.parse(String(attributes[AI_PROMPT_MESSAGES]));
1240
- if (Array.isArray(parsed)) {
1241
- parsed.forEach((message, index) => {
1242
- if (!message || typeof message !== "object") return;
1243
- const content = "content" in message ? message.content : void 0;
1244
- const role = "role" in message ? message.role : void 0;
1245
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_PROMPTS}.${index}.content`] = typeof content === "string" ? content : safeStringify(content);
1246
- if (typeof role === "string") {
1247
- attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_PROMPTS}.${index}.role`] = role;
1248
- }
1249
- });
1276
+ return await operation();
1277
+ } catch (err) {
1278
+ lastError = err;
1279
+ if (opts.debug) {
1280
+ const msg = err instanceof Error ? err.message : String(err);
1281
+ console.warn(
1282
+ `[raindrop] ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
1283
+ );
1250
1284
  }
1251
- delete attributes[AI_PROMPT_MESSAGES];
1252
- } catch (e) {
1285
+ if (attemptNumber === opts.maxAttempts) break;
1253
1286
  }
1254
1287
  }
1255
- if (AI_PROMPT_TOKENS in attributes) {
1256
- attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_PROMPT_TOKENS] = Number(attributes[AI_PROMPT_TOKENS]);
1257
- delete attributes[AI_PROMPT_TOKENS];
1258
- }
1259
- if (AI_COMPLETION_TOKENS in attributes) {
1260
- attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_COMPLETION_TOKENS] = Number(attributes[AI_COMPLETION_TOKENS]);
1261
- delete attributes[AI_COMPLETION_TOKENS];
1262
- }
1263
- const prompt = attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_PROMPT_TOKENS];
1264
- const completion = attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_COMPLETION_TOKENS];
1265
- if (prompt !== void 0 && completion !== void 0) {
1266
- attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_TOTAL_TOKENS] = Number(prompt) + Number(completion);
1267
- }
1268
- if (AI_MODEL_PROVIDER in attributes) {
1269
- const vendor = String(attributes[AI_MODEL_PROVIDER]);
1270
- attributes[import_ai_semantic_conventions.SpanAttributes.LLM_SYSTEM] = vendor.startsWith("openai") ? "OpenAI" : vendor;
1271
- delete attributes[AI_MODEL_PROVIDER];
1272
- }
1273
- Object.defineProperty(span, "name", {
1274
- configurable: true,
1275
- value: names[span.name],
1276
- writable: true
1277
- });
1278
- return span;
1288
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
1279
1289
  }
1280
- function scopeName(span) {
1290
+ async function postJson2(url, body, headers, opts) {
1281
1291
  var _a;
1282
- if ("instrumentationScope" in span) {
1283
- const scope = span.instrumentationScope;
1284
- if (scope && typeof scope === "object" && "name" in scope && typeof scope.name === "string") {
1285
- return scope.name;
1286
- }
1287
- }
1288
- return (_a = span.instrumentationLibrary) == null ? void 0 : _a.name;
1289
- }
1290
- function contentCaptureDisabled(options) {
1291
- return options.traceContent === false || (process.env.TRACELOOP_TRACE_CONTENT || "true").toLowerCase() === "false";
1292
- }
1293
- function shouldSendTraceContent() {
1294
- var _a;
1295
- const contextual = import_api.context.active().getValue(import_ai_semantic_conventions.CONTEXT_KEY_ALLOW_TRACE_CONTENT);
1296
- if (typeof contextual === "boolean") return contextual;
1297
- if (((_a = getState().configuration) == null ? void 0 : _a.traceContent) === false) return false;
1298
- return (process.env.TRACELOOP_TRACE_CONTENT || "true").toLowerCase() !== "false";
1299
- }
1300
- function enrichStart(span) {
1301
- const active = import_api.context.active();
1302
- const workflow = active.getValue(WORKFLOW_NAME_KEY);
1303
- if (typeof workflow === "string") span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_WORKFLOW_NAME, workflow);
1304
- const entity = active.getValue(ENTITY_NAME_KEY);
1305
- if (typeof entity === "string") span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_PATH, entity);
1306
- const properties = active.getValue(ASSOCIATION_PROPERTIES_KEY);
1307
- if (properties && typeof properties === "object") {
1308
- for (const [key, value] of Object.entries(properties)) {
1309
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
1310
- span.setAttribute(`${import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ASSOCIATION_PROPERTIES}.${key}`, value);
1311
- }
1312
- }
1313
- }
1314
- }
1315
- function createSpanProcessor(options) {
1316
- var _a, _b;
1317
- const baseUrl = options.baseUrl || process.env.TRACELOOP_BASE_URL || "https://api.traceloop.com";
1318
- const apiKey = options.apiKey || process.env.TRACELOOP_API_KEY;
1319
- const resolvedHeaders = (_a = options.headers) != null ? _a : process.env.TRACELOOP_HEADERS ? parseHeaders(process.env.TRACELOOP_HEADERS) : { Authorization: `Bearer ${apiKey}` };
1320
- const exporter = (_b = options.exporter) != null ? _b : new import_exporter_trace_otlp_proto.OTLPTraceExporter({ url: `${baseUrl}/v1/traces`, headers: resolvedHeaders });
1321
- const processor = options.disableBatch ? new import_sdk_trace_base.SimpleSpanProcessor(exporter) : new import_sdk_trace_base.BatchSpanProcessor(exporter);
1322
- const originalOnStart = processor.onStart.bind(processor);
1323
- const originalOnEnd = processor.onEnd.bind(processor);
1324
- processor.onStart = (span, parentContext) => {
1325
- try {
1326
- enrichStart(span);
1327
- originalOnStart(span, parentContext);
1328
- } catch (e) {
1329
- }
1330
- };
1331
- processor.onEnd = (span) => {
1332
- var _a2;
1333
- let outgoing = span;
1334
- try {
1335
- const allowed = options.allowedInstrumentationLibraries;
1336
- if (allowed !== ALL_INSTRUMENTATION_LIBRARIES && ![...INSTRUMENTATION_LIBRARIES, ...allowed != null ? allowed : []].includes((_a2 = scopeName(span)) != null ? _a2 : "")) {
1337
- return;
1292
+ const opName = `POST ${redactUrlForLog(url)}`;
1293
+ const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
1294
+ await withRetry2(
1295
+ async () => {
1296
+ const resp = await runWithTracingSuppressed(
1297
+ () => fetch(url, {
1298
+ method: "POST",
1299
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
1300
+ headers: {
1301
+ "Content-Type": "application/json",
1302
+ ...headers
1303
+ },
1304
+ body: JSON.stringify(body),
1305
+ signal: AbortSignal.timeout(timeoutMs)
1306
+ })
1307
+ );
1308
+ if (!resp.ok) {
1309
+ const text = await resp.text().catch(() => "");
1310
+ const err = new Error(
1311
+ `HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
1312
+ );
1313
+ const retryAfterMs = parseRetryAfter2(resp.headers);
1314
+ if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
1315
+ throw err;
1338
1316
  }
1339
- outgoing = transformAiSdkSpan(span);
1340
- } catch (e) {
1341
- }
1342
- try {
1343
- originalOnEnd(outgoing);
1344
- } catch (e) {
1345
- }
1346
- };
1347
- return processor;
1317
+ },
1318
+ opName,
1319
+ opts
1320
+ );
1348
1321
  }
1349
- function initialize(options = {}) {
1350
- var _a;
1351
- const state = getState();
1352
- if (state.configuration) return;
1353
- state.configuration = Object.freeze({ ...options });
1354
- if (options.logLevel) import_api.diag.setLogger(new import_api.DiagConsoleLogger(), logLevel(options.logLevel));
1355
- if (options.tracingEnabled === false) return;
1356
- const baseUrl = options.baseUrl || process.env.TRACELOOP_BASE_URL || "https://api.traceloop.com";
1357
- state.defaultProcessor = createSpanProcessor({
1358
- ...options,
1359
- baseUrl,
1360
- allowedInstrumentationLibraries: ALL_INSTRUMENTATION_LIBRARIES
1361
- });
1362
- const serviceResource = createResource({
1363
- "service.name": options.appName || process.env.npm_package_name || "unknown_service"
1364
- });
1365
- const detectedResource = detectRuntimeResource();
1366
- state.provider = new import_sdk_trace_node.NodeTracerProvider({
1367
- // Detected attributes win over the configured resource, matching
1368
- // sdk-node's `this._resource.merge(detectResourcesSync(...))` so
1369
- // OTEL_SERVICE_NAME / OTEL_RESOURCE_ATTRIBUTES can still override appName.
1370
- resource: detectedResource ? serviceResource.merge(detectedResource) : serviceResource,
1371
- spanProcessors: [state.defaultProcessor, ...options.processor ? [options.processor] : []]
1372
- });
1373
- state.provider.register({
1374
- contextManager: options.contextManager,
1375
- propagator: options.propagator
1376
- });
1377
- const instrumentations = (_a = options.instrumentations) != null ? _a : [];
1378
- if (contentCaptureDisabled(options)) {
1379
- for (const instrumentation of instrumentations) {
1380
- try {
1381
- const config = {
1382
- ...instrumentation.getConfig(),
1383
- traceContent: false
1384
- };
1385
- instrumentation.setConfig(config);
1386
- } catch (e) {
1387
- }
1388
- }
1389
- }
1390
- (0, import_instrumentation.registerInstrumentations)({ instrumentations });
1322
+
1323
+ // src/tracing/direct/ids.ts
1324
+ function getCrypto2() {
1325
+ const c = globalThis.crypto;
1326
+ return c;
1391
1327
  }
1392
- async function forceFlush() {
1393
- var _a, _b;
1394
- const state = getState();
1395
- try {
1396
- await ((_a = state.provider) == null ? void 0 : _a.forceFlush());
1397
- await ((_b = state.defaultProcessor) == null ? void 0 : _b.forceFlush());
1398
- } catch (e) {
1328
+ function randomBytes2(length) {
1329
+ const cryptoObj = getCrypto2();
1330
+ const out = new Uint8Array(length);
1331
+ if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
1332
+ cryptoObj.getRandomValues(out);
1333
+ return out;
1399
1334
  }
1335
+ for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
1336
+ return out;
1400
1337
  }
1401
- function withEntity(type, config, fn, args) {
1402
- let entityContext = import_api.context.active();
1403
- if (type === import_ai_semantic_conventions.TraceloopSpanKindValues.WORKFLOW) {
1404
- entityContext = entityContext.setValue(WORKFLOW_NAME_KEY, config.name);
1405
- }
1406
- const parentPath = entityContext.getValue(ENTITY_NAME_KEY);
1407
- if (type === import_ai_semantic_conventions.TraceloopSpanKindValues.TASK || type === import_ai_semantic_conventions.TraceloopSpanKindValues.TOOL) {
1408
- entityContext = entityContext.setValue(
1409
- ENTITY_NAME_KEY,
1410
- `${typeof parentPath === "string" ? `${parentPath}.` : ""}${config.name}`
1411
- );
1338
+ function base64Encode2(bytes) {
1339
+ const maybeBuffer = globalThis.Buffer;
1340
+ if (maybeBuffer) {
1341
+ return maybeBuffer.from(bytes).toString("base64");
1412
1342
  }
1413
- if (config.traceContent !== void 0) {
1414
- entityContext = entityContext.setValue(import_ai_semantic_conventions.CONTEXT_KEY_ALLOW_TRACE_CONTENT, config.traceContent);
1343
+ let binary = "";
1344
+ for (let i2 = 0; i2 < bytes.length; i2++) {
1345
+ binary += String.fromCharCode(bytes[i2]);
1415
1346
  }
1416
- if (config.associationProperties) {
1417
- entityContext = entityContext.setValue(ASSOCIATION_PROPERTIES_KEY, config.associationProperties);
1347
+ const btoaFn = globalThis.btoa;
1348
+ if (typeof btoaFn === "function") return btoaFn(binary);
1349
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1350
+ let out = "";
1351
+ let i = 0;
1352
+ while (i < binary.length) {
1353
+ const c1 = binary.charCodeAt(i++) & 255;
1354
+ const c2 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
1355
+ const c3 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
1356
+ const e1 = c1 >> 2;
1357
+ const e2 = (c1 & 3) << 4 | (Number.isNaN(c2) ? 0 : c2 >> 4);
1358
+ const e3 = Number.isNaN(c2) ? 64 : (c2 & 15) << 2 | (Number.isNaN(c3) ? 0 : c3 >> 6);
1359
+ const e4 = Number.isNaN(c3) ? 64 : c3 & 63;
1360
+ out += alphabet.charAt(e1);
1361
+ out += alphabet.charAt(e2);
1362
+ out += e3 === 64 ? "=" : alphabet.charAt(e3);
1363
+ out += e4 === 64 ? "=" : alphabet.charAt(e4);
1418
1364
  }
1419
- if (config.suppressTracing) {
1420
- entityContext = (0, import_core.suppressTracing)(entityContext);
1365
+ return out;
1366
+ }
1367
+ function base64ToHex2(base64) {
1368
+ const maybeBuffer = globalThis.Buffer;
1369
+ if (maybeBuffer) {
1370
+ return maybeBuffer.from(base64, "base64").toString("hex");
1421
1371
  }
1422
- let callbackStarted = false;
1423
- const run = (span) => {
1424
- var _a;
1425
- try {
1426
- span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_NAME, config.name);
1427
- span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_PATH, typeof parentPath === "string" ? parentPath : "");
1428
- span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_SPAN_KIND, type);
1429
- if (type === import_ai_semantic_conventions.TraceloopSpanKindValues.WORKFLOW) {
1430
- span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_WORKFLOW_NAME, config.name);
1431
- }
1432
- if (config.version !== void 0) span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_VERSION, config.version);
1433
- const input = (_a = config.inputParameters) != null ? _a : args;
1434
- if (shouldSendTraceContent()) {
1435
- span.setAttribute(
1436
- import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_INPUT,
1437
- safeStringify(input.length === 1 && input[0] !== null && typeof input[0] === "object" && !(input[0] instanceof Map) ? { args: [], kwargs: input[0] } : { args: input, kwargs: {} })
1438
- );
1439
- }
1440
- } catch (e) {
1441
- }
1442
- let result;
1443
- try {
1444
- callbackStarted = true;
1445
- result = fn(...args);
1446
- } catch (error) {
1447
- try {
1448
- span.end();
1449
- } catch (e) {
1450
- }
1451
- throw error;
1452
- }
1453
- if (result instanceof Promise) {
1454
- return result.then(
1455
- (value) => {
1456
- try {
1457
- if (shouldSendTraceContent()) span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_OUTPUT, safeStringify(value));
1458
- span.end();
1459
- } catch (e) {
1460
- }
1461
- return value;
1462
- },
1463
- (error) => {
1464
- try {
1465
- span.end();
1466
- } catch (e) {
1467
- }
1468
- throw error;
1469
- }
1470
- );
1471
- }
1472
- try {
1473
- if (shouldSendTraceContent()) span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_OUTPUT, safeStringify(result));
1474
- span.end();
1475
- } catch (e) {
1372
+ const atobFn = globalThis.atob;
1373
+ if (typeof atobFn === "function") {
1374
+ const binary = atobFn(base64);
1375
+ let hex = "";
1376
+ for (let i = 0; i < binary.length; i++) {
1377
+ hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
1476
1378
  }
1477
- return result;
1478
- };
1479
- try {
1480
- const tracer = import_api.trace.getTracer(TRACER_NAME);
1481
- return import_api.context.with(
1482
- entityContext,
1483
- () => tracer.startActiveSpan(`${config.name}.${type}`, {}, entityContext, run)
1484
- );
1485
- } catch (error) {
1486
- if (callbackStarted) throw error;
1487
- return fn(...args);
1379
+ return hex;
1488
1380
  }
1489
- }
1490
- function withTask(config, fn, ...args) {
1491
- return withEntity(import_ai_semantic_conventions.TraceloopSpanKindValues.TASK, config, fn, args);
1492
- }
1493
- function withTool(config, fn, ...args) {
1494
- return withEntity(import_ai_semantic_conventions.TraceloopSpanKindValues.TOOL, config, fn, args);
1495
- }
1496
-
1497
- // src/tracing/tracer-core.ts
1498
- var import_weakref = require("weakref");
1499
-
1500
- // src/lib/inject-als.ts
1501
- var import_node_async_hooks = require("async_hooks");
1502
- if (!globalThis.RAINDROP_ASYNC_LOCAL_STORAGE) {
1503
- globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_node_async_hooks.AsyncLocalStorage;
1504
- }
1505
-
1506
- // src/tracing/direct/http.ts
1507
- function wait2(ms) {
1508
- return new Promise((resolve) => setTimeout(resolve, ms));
1509
- }
1510
- function formatEndpoint2(endpoint) {
1511
- if (!endpoint) return void 0;
1512
- return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
1513
- }
1514
- function parseRetryAfter2(headers) {
1515
- var _a;
1516
- const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
1517
- if (!value) return void 0;
1518
- const asNumber = Number(value);
1519
- if (!Number.isNaN(asNumber)) return asNumber * 1e3;
1520
- const asDate = new Date(value).getTime();
1521
- if (!Number.isNaN(asDate)) {
1522
- const delta = asDate - Date.now();
1523
- return delta > 0 ? delta : 0;
1524
- }
1525
- return void 0;
1526
- }
1527
- function getRetryDelayMs2(attemptNumber, previousError) {
1528
- if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
1529
- const v = previousError.retryAfterMs;
1530
- if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
1531
- }
1532
- if (attemptNumber <= 1) return 0;
1533
- const base = 500;
1534
- const factor = Math.pow(2, attemptNumber - 2);
1535
- return Math.min(base * factor, MAX_RETRY_DELAY_MS);
1536
- }
1537
- async function withRetry2(operation, opName, opts) {
1538
- let lastError = void 0;
1539
- for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
1540
- if (attemptNumber > 1) {
1541
- const delay = getRetryDelayMs2(attemptNumber, lastError);
1542
- if (opts.debug) {
1543
- console.warn(
1544
- `[raindrop] ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
1545
- );
1546
- }
1547
- if (delay > 0) await wait2(delay);
1548
- } else if (opts.debug) {
1549
- console.log(`[raindrop] ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
1550
- }
1551
- try {
1552
- return await operation();
1553
- } catch (err) {
1554
- lastError = err;
1555
- if (opts.debug) {
1556
- const msg = err instanceof Error ? err.message : String(err);
1557
- console.warn(
1558
- `[raindrop] ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
1559
- );
1560
- }
1561
- if (attemptNumber === opts.maxAttempts) break;
1562
- }
1563
- }
1564
- throw lastError instanceof Error ? lastError : new Error(String(lastError));
1565
- }
1566
- async function postJson2(url, body, headers, opts) {
1567
- var _a;
1568
- const opName = `POST ${redactUrlForLog(url)}`;
1569
- const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
1570
- await withRetry2(
1571
- async () => {
1572
- const resp = await runWithTracingSuppressed(
1573
- () => fetch(url, {
1574
- method: "POST",
1575
- headers: {
1576
- "Content-Type": "application/json",
1577
- ...headers
1578
- },
1579
- body: JSON.stringify(body),
1580
- signal: AbortSignal.timeout(timeoutMs)
1581
- })
1582
- );
1583
- if (!resp.ok) {
1584
- const text = await resp.text().catch(() => "");
1585
- const err = new Error(
1586
- `HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
1587
- );
1588
- const retryAfterMs = parseRetryAfter2(resp.headers);
1589
- if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
1590
- throw err;
1591
- }
1592
- },
1593
- opName,
1594
- opts
1595
- );
1596
- }
1597
-
1598
- // src/tracing/direct/ids.ts
1599
- function getCrypto2() {
1600
- const c = globalThis.crypto;
1601
- return c;
1602
- }
1603
- function randomBytes2(length) {
1604
- const cryptoObj = getCrypto2();
1605
- const out = new Uint8Array(length);
1606
- if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
1607
- cryptoObj.getRandomValues(out);
1608
- return out;
1609
- }
1610
- for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
1611
- return out;
1612
- }
1613
- function base64Encode2(bytes) {
1614
- const maybeBuffer = globalThis.Buffer;
1615
- if (maybeBuffer) {
1616
- return maybeBuffer.from(bytes).toString("base64");
1617
- }
1618
- let binary = "";
1619
- for (let i2 = 0; i2 < bytes.length; i2++) {
1620
- binary += String.fromCharCode(bytes[i2]);
1621
- }
1622
- const btoaFn = globalThis.btoa;
1623
- if (typeof btoaFn === "function") return btoaFn(binary);
1624
- const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
1625
- let out = "";
1626
- let i = 0;
1627
- while (i < binary.length) {
1628
- const c1 = binary.charCodeAt(i++) & 255;
1629
- const c2 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
1630
- const c3 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
1631
- const e1 = c1 >> 2;
1632
- const e2 = (c1 & 3) << 4 | (Number.isNaN(c2) ? 0 : c2 >> 4);
1633
- const e3 = Number.isNaN(c2) ? 64 : (c2 & 15) << 2 | (Number.isNaN(c3) ? 0 : c3 >> 6);
1634
- const e4 = Number.isNaN(c3) ? 64 : c3 & 63;
1635
- out += alphabet.charAt(e1);
1636
- out += alphabet.charAt(e2);
1637
- out += e3 === 64 ? "=" : alphabet.charAt(e3);
1638
- out += e4 === 64 ? "=" : alphabet.charAt(e4);
1639
- }
1640
- return out;
1641
- }
1642
- function base64ToHex2(base64) {
1643
- const maybeBuffer = globalThis.Buffer;
1644
- if (maybeBuffer) {
1645
- return maybeBuffer.from(base64, "base64").toString("hex");
1646
- }
1647
- const atobFn = globalThis.atob;
1648
- if (typeof atobFn === "function") {
1649
- const binary = atobFn(base64);
1650
- let hex = "";
1651
- for (let i = 0; i < binary.length; i++) {
1652
- hex += binary.charCodeAt(i).toString(16).padStart(2, "0");
1653
- }
1654
- return hex;
1655
- }
1656
- throw new Error("No base64 decoder available in this runtime");
1381
+ throw new Error("No base64 decoder available in this runtime");
1657
1382
  }
1658
1383
 
1659
1384
  // package.json
1660
1385
  var package_default = {
1661
1386
  name: "raindrop-ai",
1662
- version: "0.4.0",
1387
+ version: "0.5.0",
1663
1388
  main: "dist/index.js",
1664
1389
  module: "dist/index.mjs",
1665
1390
  types: "dist/index.d.ts",
@@ -1670,9 +1395,14 @@ var package_default = {
1670
1395
  },
1671
1396
  exports: {
1672
1397
  ".": {
1673
- types: "./dist/index.d.ts",
1674
- import: "./dist/index.mjs",
1675
- require: "./dist/index.js"
1398
+ import: {
1399
+ types: "./dist/index.d.mts",
1400
+ default: "./dist/index.mjs"
1401
+ },
1402
+ require: {
1403
+ types: "./dist/index.d.ts",
1404
+ default: "./dist/index.js"
1405
+ }
1676
1406
  },
1677
1407
  "./tracing": {
1678
1408
  types: "./dist/tracing/index.d.ts",
@@ -1712,8 +1442,8 @@ var package_default = {
1712
1442
  "@raindrop-ai/core": "workspace:*",
1713
1443
  "@raindrop-ai/redact-pii": "workspace:*",
1714
1444
  "@raindrop-ai/schemas": "workspace:*",
1715
- ai: "^6.0.0",
1716
1445
  "@types/node": "^20.11.17",
1446
+ ai: "^6.0.0",
1717
1447
  msw: "^2.12.8",
1718
1448
  tsup: "^8.4.0",
1719
1449
  tsx: "^4.20.3",
@@ -1722,6 +1452,7 @@ var package_default = {
1722
1452
  vitest: "^4.0.10"
1723
1453
  },
1724
1454
  dependencies: {
1455
+ "@jitl/quickjs-singlefile-cjs-release-sync": "0.32.0",
1725
1456
  "@opentelemetry/api": "^1.9.0",
1726
1457
  "@opentelemetry/core": "^1.30.1",
1727
1458
  "@opentelemetry/exporter-trace-otlp-http": "^0.57.2",
@@ -1732,16 +1463,17 @@ var package_default = {
1732
1463
  "@opentelemetry/sdk-trace-node": "^1.30.1",
1733
1464
  "@traceloop/ai-semantic-conventions": "0.19.0-otel-v1",
1734
1465
  "@traceloop/instrumentation-anthropic": "0.19.0-otel-v1",
1735
- "@traceloop/instrumentation-openai": "0.19.0-otel-v1",
1736
- "@traceloop/instrumentation-cohere": "0.19.0-otel-v1",
1737
1466
  "@traceloop/instrumentation-bedrock": "0.19.0-otel-v1",
1738
- "@traceloop/instrumentation-vertexai": "0.19.0-otel-v1",
1739
- "@traceloop/instrumentation-pinecone": "0.19.0-otel-v1",
1740
1467
  "@traceloop/instrumentation-chromadb": "0.19.0-otel-v1",
1741
- "@traceloop/instrumentation-qdrant": "0.19.0-otel-v1",
1742
- "@traceloop/instrumentation-together": "0.19.0-otel-v1",
1468
+ "@traceloop/instrumentation-cohere": "0.19.0-otel-v1",
1743
1469
  "@traceloop/instrumentation-langchain": "0.19.0-otel-v1",
1744
1470
  "@traceloop/instrumentation-llamaindex": "0.19.0-otel-v1",
1471
+ "@traceloop/instrumentation-openai": "0.19.0-otel-v1",
1472
+ "@traceloop/instrumentation-pinecone": "0.19.0-otel-v1",
1473
+ "@traceloop/instrumentation-qdrant": "0.19.0-otel-v1",
1474
+ "@traceloop/instrumentation-together": "0.19.0-otel-v1",
1475
+ "@traceloop/instrumentation-vertexai": "0.19.0-otel-v1",
1476
+ "quickjs-emscripten-core": "0.32.0",
1745
1477
  weakref: "^0.2.1",
1746
1478
  zod: "^3.23.8"
1747
1479
  },
@@ -1831,520 +1563,1063 @@ function buildExportTraceServiceRequest2(spans) {
1831
1563
  scope: { name: SERVICE_NAME, version: libraryVersion },
1832
1564
  spans
1833
1565
  }
1834
- ]
1566
+ ]
1567
+ }
1568
+ ]
1569
+ };
1570
+ }
1571
+
1572
+ // src/tracing/direct/context.ts
1573
+ var import_api = require("@opentelemetry/api");
1574
+ var INVALID_TRACE_ID = "00000000000000000000000000000000";
1575
+ var INVALID_SPAN_ID = "0000000000000000";
1576
+ function hexToBase64(hex) {
1577
+ const bytes = new Uint8Array(hex.length / 2);
1578
+ for (let i = 0; i < hex.length; i += 2) {
1579
+ bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
1580
+ }
1581
+ return base64Encode2(bytes);
1582
+ }
1583
+ function getExplicitTraceContext(traceId, parentSpanId) {
1584
+ if (!traceId || !parentSpanId || !(0, import_api.isValidTraceId)(traceId) || !(0, import_api.isValidSpanId)(parentSpanId)) {
1585
+ return void 0;
1586
+ }
1587
+ return {
1588
+ traceIdB64: hexToBase64(traceId),
1589
+ parentSpanIdB64: hexToBase64(parentSpanId)
1590
+ };
1591
+ }
1592
+ function getActiveTraceContext() {
1593
+ const activeSpan = import_api.trace.getSpan(import_api.context.active());
1594
+ if (!activeSpan) return {};
1595
+ const spanContext = activeSpan.spanContext();
1596
+ const traceIdHex = spanContext.traceId;
1597
+ const spanIdHex = spanContext.spanId;
1598
+ if (traceIdHex === INVALID_TRACE_ID) return {};
1599
+ return {
1600
+ traceIdB64: hexToBase64(traceIdHex),
1601
+ parentSpanIdB64: spanIdHex !== INVALID_SPAN_ID ? hexToBase64(spanIdHex) : void 0
1602
+ };
1603
+ }
1604
+
1605
+ // src/tracing/multi-project.ts
1606
+ var import_node_crypto = require("crypto");
1607
+ var import_exporter_trace_otlp_proto2 = require("@opentelemetry/exporter-trace-otlp-proto");
1608
+
1609
+ // src/tracing/replay-routing.ts
1610
+ var import_exporter_trace_otlp_proto = require("@opentelemetry/exporter-trace-otlp-proto");
1611
+ var EXPORT_SUCCESS = 0;
1612
+ var EXPORT_FAILED = 1;
1613
+ function recordExportedSpan(destination, span) {
1614
+ if (typeof span !== "object" && typeof span !== "function" || span === null) return;
1615
+ const spanContext = span.spanContext;
1616
+ if (typeof spanContext !== "function") return;
1617
+ const context7 = spanContext.call(span);
1618
+ if (typeof (context7 == null ? void 0 : context7.spanId) === "string" && typeof context7.traceId === "string") {
1619
+ recordReplayExportedSpan(destination, context7.spanId, context7.traceId);
1620
+ }
1621
+ }
1622
+ function createReplayExporter(destination) {
1623
+ var _a;
1624
+ if (destination.kind === "workshop") {
1625
+ return new import_exporter_trace_otlp_proto.OTLPTraceExporter({
1626
+ url: replayTraceUrl(destination.url)
1627
+ });
1628
+ }
1629
+ return new import_exporter_trace_otlp_proto.OTLPTraceExporter({
1630
+ url: replayTraceUrl(destination.url),
1631
+ headers: {
1632
+ Authorization: `Bearer ${destination.apiKey}`,
1633
+ "X-Raindrop-Replay-Id": destination.replayId,
1634
+ "X-Raindrop-Project-Id": (_a = destination.projectId) != null ? _a : "default"
1635
+ }
1636
+ });
1637
+ }
1638
+ var ReplayRoutingSpanExporter = class {
1639
+ constructor(normal, replayExporter = createReplayExporter) {
1640
+ this.normal = normal;
1641
+ this.replayExporter = replayExporter;
1642
+ }
1643
+ export(spans, resultCallback) {
1644
+ const replayGroups = /* @__PURE__ */ new Map();
1645
+ const normalSpans = [];
1646
+ for (const span of spans) {
1647
+ const destination = replayTraceDestinationFor(span);
1648
+ if (!destination) {
1649
+ normalSpans.push(span);
1650
+ continue;
1651
+ }
1652
+ const group = replayGroups.get(destination);
1653
+ recordExportedSpan(destination, span);
1654
+ if (group) group.push(span);
1655
+ else replayGroups.set(destination, [span]);
1656
+ }
1657
+ if (replayGroups.size === 0) {
1658
+ this.normal.export(spans, resultCallback);
1659
+ return;
1660
+ }
1661
+ let remaining = replayGroups.size + (normalSpans.length > 0 ? 1 : 0);
1662
+ let failed = false;
1663
+ let firstError;
1664
+ const finish = (result) => {
1665
+ if (result.code !== EXPORT_SUCCESS) {
1666
+ failed = true;
1667
+ firstError != null ? firstError : firstError = result.error;
1668
+ }
1669
+ remaining -= 1;
1670
+ if (remaining === 0) {
1671
+ resultCallback(
1672
+ firstError ? { code: EXPORT_FAILED, error: firstError } : { code: failed ? EXPORT_FAILED : EXPORT_SUCCESS }
1673
+ );
1674
+ }
1675
+ };
1676
+ if (normalSpans.length > 0) {
1677
+ try {
1678
+ this.normal.export(normalSpans, finish);
1679
+ } catch (cause) {
1680
+ finish({
1681
+ code: EXPORT_FAILED,
1682
+ error: cause instanceof Error ? cause : new Error(String(cause))
1683
+ });
1684
+ }
1685
+ }
1686
+ for (const [destination, replaySpans] of replayGroups) {
1687
+ let exporter;
1688
+ try {
1689
+ exporter = this.replayExporter(destination);
1690
+ } catch (cause) {
1691
+ finish({
1692
+ code: EXPORT_FAILED,
1693
+ error: cause instanceof Error ? cause : new Error(String(cause))
1694
+ });
1695
+ continue;
1696
+ }
1697
+ try {
1698
+ exporter.export(replaySpans, (result) => {
1699
+ finish(result);
1700
+ void exporter.shutdown().catch(() => {
1701
+ });
1702
+ });
1703
+ } catch (cause) {
1704
+ finish({
1705
+ code: EXPORT_FAILED,
1706
+ error: cause instanceof Error ? cause : new Error(String(cause))
1707
+ });
1708
+ void exporter.shutdown().catch(() => {
1709
+ });
1710
+ }
1711
+ }
1712
+ }
1713
+ forceFlush() {
1714
+ return this.normal.forceFlush ? this.normal.forceFlush() : Promise.resolve();
1715
+ }
1716
+ shutdown() {
1717
+ return this.normal.shutdown();
1718
+ }
1719
+ };
1720
+
1721
+ // src/tracing/multi-project.ts
1722
+ var PROJECT_ID_SPAN_ATTRIBUTE = "raindrop.project_id";
1723
+ var AUTH_HINT_SPAN_ATTRIBUTE = "raindrop.auth_hint";
1724
+ var EXPORT_SUCCESS2 = 0;
1725
+ var EXPORT_FAILED2 = 1;
1726
+ var SPAN_STATUS_ERROR = 2;
1727
+ function authHintForKey(writeKey) {
1728
+ if (!writeKey) return void 0;
1729
+ return (0, import_node_crypto.createHash)("sha256").update(writeKey, "utf8").digest("hex").slice(0, 8);
1730
+ }
1731
+ var STATE_KEY2 = /* @__PURE__ */ Symbol.for("raindrop.tracing.multiProjectState");
1732
+ function getState() {
1733
+ const holder = globalThis;
1734
+ let state2 = holder[STATE_KEY2];
1735
+ if (!state2) {
1736
+ state2 = {
1737
+ foreignClientSeen: false,
1738
+ seenClientHints: /* @__PURE__ */ new Set(),
1739
+ ownerAuthHint: void 0,
1740
+ ownerProjectId: void 0,
1741
+ pipelineClaimed: false,
1742
+ traceloopConfiguredWithoutClaim: false,
1743
+ multiKeyWarned: false,
1744
+ pendingMultiKeyWarning: false
1745
+ };
1746
+ holder[STATE_KEY2] = state2;
1747
+ }
1748
+ return state2;
1749
+ }
1750
+ function emitMultiKeyWarningOnce() {
1751
+ const state2 = getState();
1752
+ if (state2.multiKeyWarned) return;
1753
+ state2.multiKeyWarned = true;
1754
+ state2.pendingMultiKeyWarning = false;
1755
+ console.warn(
1756
+ "[raindrop] Multiple API keys detected in one process. The OTel export guard now requires positive attribution: spans not bound to any client (no begin()/asCurrent()) are dropped, and spans bound to a non-owner key are dropped. Manual events are unaffected."
1757
+ );
1758
+ }
1759
+ function registerClientKey(authHint, tracingEnabled = false) {
1760
+ if (!authHint) return;
1761
+ const state2 = getState();
1762
+ state2.seenClientHints.add(authHint);
1763
+ if (state2.seenClientHints.size > 1) {
1764
+ state2.foreignClientSeen = true;
1765
+ if (tracingEnabled || state2.pipelineClaimed) {
1766
+ emitMultiKeyWarningOnce();
1767
+ } else {
1768
+ state2.pendingMultiKeyWarning = true;
1769
+ }
1770
+ }
1771
+ }
1772
+ function markForeignClient() {
1773
+ getState().foreignClientSeen = true;
1774
+ }
1775
+ function foreignClientSeen() {
1776
+ return getState().foreignClientSeen;
1777
+ }
1778
+ function stampSpan(span, projectId, authHint) {
1779
+ try {
1780
+ if (projectId) {
1781
+ span.setAttribute(PROJECT_ID_SPAN_ATTRIBUTE, projectId);
1782
+ }
1783
+ if (authHint && foreignClientSeen()) {
1784
+ span.setAttribute(AUTH_HINT_SPAN_ATTRIBUTE, authHint);
1785
+ }
1786
+ } catch (e) {
1787
+ }
1788
+ }
1789
+ function stampContextAttributes(span) {
1790
+ try {
1791
+ applySpanAttributeFrames(span, (key, value) => span.setAttribute(key, value));
1792
+ for (const [key, value] of Object.entries(evalScopeAttributes())) {
1793
+ span.setAttribute(key, value);
1794
+ }
1795
+ } catch (e) {
1796
+ }
1797
+ }
1798
+ var RaindropContextSpanProcessor = class {
1799
+ onStart(span) {
1800
+ try {
1801
+ stampContextAttributes(span);
1802
+ rememberReplayTraceDestination(span);
1803
+ const bound = currentRoutingBinding();
1804
+ if (!bound) return;
1805
+ stampSpan(span, bound.projectId, bound.authHint);
1806
+ } catch (e) {
1807
+ }
1808
+ }
1809
+ onEnd(span) {
1810
+ var _a;
1811
+ try {
1812
+ if (((_a = span == null ? void 0 : span.status) == null ? void 0 : _a.code) !== SPAN_STATUS_ERROR) return;
1813
+ markErrorSpanSeen(span);
1814
+ } catch (e) {
1815
+ }
1816
+ }
1817
+ async forceFlush() {
1818
+ }
1819
+ async shutdown() {
1820
+ }
1821
+ };
1822
+ var GuardedSpanExporter = class {
1823
+ constructor(inner, ownerAuthHint) {
1824
+ this.droppedTotal = 0;
1825
+ this.inner = inner;
1826
+ this.ownerAuthHint = ownerAuthHint;
1827
+ }
1828
+ partition(spans) {
1829
+ var _a;
1830
+ const allowed = [];
1831
+ let dropped = 0;
1832
+ const requirePositive = foreignClientSeen();
1833
+ for (const span of spans) {
1834
+ const attrs = (_a = span.attributes) != null ? _a : {};
1835
+ const hint = attrs[AUTH_HINT_SPAN_ATTRIBUTE];
1836
+ const keep = requirePositive ? hint === this.ownerAuthHint : hint === void 0 || hint === this.ownerAuthHint;
1837
+ if (keep) {
1838
+ allowed.push(span);
1839
+ } else {
1840
+ dropped += 1;
1841
+ }
1842
+ }
1843
+ return { allowed, dropped };
1844
+ }
1845
+ warnDropped(dropped) {
1846
+ this.droppedTotal += dropped;
1847
+ const total = this.droppedTotal;
1848
+ rateLimitedLog(
1849
+ "js-sdk.multi-project.dropped",
1850
+ () => console.warn(
1851
+ `[raindrop] Dropped ${dropped} span(s) produced under a different API key than the tracing pipeline's (total dropped: ${total}). One process has ONE OTel pipeline authenticating with the first tracing-enabled client's key; tracing for a different key/org in the same process is unsupported \u2014 run it in its own process. Manual events (track_ai/begin/finish/signals/identify) are unaffected.`
1852
+ )
1853
+ );
1854
+ }
1855
+ export(spans, resultCallback) {
1856
+ let allowed;
1857
+ let dropped;
1858
+ try {
1859
+ ({ allowed, dropped } = this.partition(spans));
1860
+ } catch (e) {
1861
+ if (foreignClientSeen()) {
1862
+ this.warnDropped(spans.length);
1863
+ resultCallback({ code: EXPORT_FAILED2 });
1864
+ return;
1865
+ }
1866
+ this.inner.export(spans, resultCallback);
1867
+ return;
1868
+ }
1869
+ if (dropped) {
1870
+ this.warnDropped(dropped);
1871
+ }
1872
+ if (allowed.length === 0) {
1873
+ resultCallback({ code: EXPORT_SUCCESS2 });
1874
+ return;
1875
+ }
1876
+ this.inner.export(allowed, resultCallback);
1877
+ }
1878
+ shutdown() {
1879
+ return this.inner.shutdown();
1880
+ }
1881
+ forceFlush() {
1882
+ return this.inner.forceFlush ? this.inner.forceFlush() : Promise.resolve();
1883
+ }
1884
+ };
1885
+ function buildGuardedExporter(baseUrl, headers, ownerAuthHint) {
1886
+ const inner = new import_exporter_trace_otlp_proto2.OTLPTraceExporter({
1887
+ url: `${baseUrl}/v1/traces`,
1888
+ headers
1889
+ });
1890
+ return new GuardedSpanExporter(inner, ownerAuthHint);
1891
+ }
1892
+ function pipelineOwnerHint() {
1893
+ return getState().ownerAuthHint;
1894
+ }
1895
+ function claimPipeline(authHint, projectId) {
1896
+ const state2 = getState();
1897
+ if (state2.pipelineClaimed) {
1898
+ return false;
1899
+ }
1900
+ state2.pipelineClaimed = true;
1901
+ state2.ownerAuthHint = authHint;
1902
+ state2.ownerProjectId = projectId;
1903
+ if (state2.foreignClientSeen && state2.pendingMultiKeyWarning) {
1904
+ emitMultiKeyWarningOnce();
1905
+ }
1906
+ return true;
1907
+ }
1908
+ function releasePipelineClaim() {
1909
+ const state2 = getState();
1910
+ state2.pipelineClaimed = false;
1911
+ state2.ownerAuthHint = void 0;
1912
+ state2.ownerProjectId = void 0;
1913
+ }
1914
+ function markTraceloopConfiguredWithoutClaim() {
1915
+ getState().traceloopConfiguredWithoutClaim = true;
1916
+ }
1917
+ function traceloopConfiguredWithoutClaim() {
1918
+ return getState().traceloopConfiguredWithoutClaim;
1919
+ }
1920
+
1921
+ // src/tracing/direct/shipper.ts
1922
+ function serializeAssociationValue(value) {
1923
+ return stringifyBounded(value);
1924
+ }
1925
+ var DirectTraceShipper = class {
1926
+ constructor(opts) {
1927
+ this.queue = [];
1928
+ this.inFlight = /* @__PURE__ */ new Set();
1929
+ /**
1930
+ * Set once `shutdown()` begins and never cleared. Sends issued after the
1931
+ * drain window (stragglers, or flush work the deadline abandoned
1932
+ * mid-drain) run as a single short attempt instead of regaining the full
1933
+ * retry schedule.
1934
+ */
1935
+ this.hasShutdown = false;
1936
+ var _a, _b, _c, _d, _e, _f;
1937
+ this.writeKey = opts.writeKey;
1938
+ this.baseUrl = (_a = formatEndpoint2(opts.endpoint)) != null ? _a : "https://api.raindrop.ai/v1/";
1939
+ this.enabled = (_b = opts.enabled) != null ? _b : true;
1940
+ this.cloudEnabled = (_c = opts.cloudEnabled) != null ? _c : true;
1941
+ this.debug = opts.debug;
1942
+ this.projectId = opts.projectId;
1943
+ this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
1944
+ this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
1945
+ this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
1946
+ const resolved = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl);
1947
+ if (resolved && resolved !== this.baseUrl) {
1948
+ this.localDebuggerUrl = resolved;
1949
+ }
1950
+ }
1951
+ /**
1952
+ * Build and enqueue an OTLP span for a trackTool call.
1953
+ *
1954
+ * Reads the active OTEL context if traceId/parentSpanId are not provided,
1955
+ * so spans still appear as children in the trace tree.
1956
+ */
1957
+ sendSpan(params) {
1958
+ var _a, _b, _c;
1959
+ if (!this.enabled) return;
1960
+ let traceIdB64 = params.traceId;
1961
+ let parentSpanIdB64 = params.parentSpanId;
1962
+ if (!traceIdB64) {
1963
+ const activeCtx = getActiveTraceContext();
1964
+ traceIdB64 = activeCtx.traceIdB64;
1965
+ parentSpanIdB64 = activeCtx.parentSpanIdB64;
1966
+ }
1967
+ const spanIdB64 = (_a = params.spanId) != null ? _a : base64Encode2(randomBytes2(8));
1968
+ if (!traceIdB64) {
1969
+ traceIdB64 = base64Encode2(randomBytes2(16));
1970
+ }
1971
+ const startTimeUnixNano = String(params.startTimeMs * 1e6);
1972
+ const endTimeUnixNano = String(params.endTimeMs * 1e6);
1973
+ const attributes = [
1974
+ // Required: passes hasAIOperation() filter in backend (parseSpan.ts)
1975
+ attrString2("traceloop.span.kind", (_b = params.spanKind) != null ? _b : "tool"),
1976
+ // Parsed by backend for input/output payloads
1977
+ attrString2("traceloop.entity.input", params.input),
1978
+ attrString2("traceloop.entity.output", params.output),
1979
+ // Duration tracking
1980
+ attrInt2("traceloop.entity.duration_ms", params.durationMs),
1981
+ // Per-span project routing: the ingest boundary routes on this attribute
1982
+ // (org-validated) and falls back to the request's project header. Direct
1983
+ // spans ship on this instance's own key, so no cross-key auth hint.
1984
+ attrString2(PROJECT_ID_SPAN_ATTRIBUTE, this.projectId)
1985
+ ];
1986
+ for (const [key, value] of Object.entries(params.properties)) {
1987
+ if (value === void 0) {
1988
+ continue;
1989
+ }
1990
+ attributes.push(
1991
+ attrString2(`traceloop.association.properties.${key}`, serializeAssociationValue(value))
1992
+ );
1993
+ }
1994
+ const spanIdentity = { spanIdB64 };
1995
+ claimSpanForFrames(spanIdentity);
1996
+ for (const [key, value] of Object.entries({
1997
+ ...currentSpanAttributes(),
1998
+ ...params.attributes,
1999
+ // Last, so neither a bound frame nor an explicit caller attribute can
2000
+ // shadow the replay row a span belongs to.
2001
+ ...evalScopeAttributes()
2002
+ })) {
2003
+ attributes.push(attrString2(key, value));
2004
+ }
2005
+ attributes.push(...(_c = params.otlpAttributes) != null ? _c : []);
2006
+ let status;
2007
+ if (params.error) {
2008
+ status = { code: 2, message: params.error };
2009
+ markErrorSpanSeen(spanIdentity);
2010
+ } else {
2011
+ status = {
2012
+ code: 1
2013
+ /* STATUS_CODE_OK */
2014
+ };
2015
+ }
2016
+ const span = buildOtlpSpan2({
2017
+ ids: {
2018
+ traceIdB64,
2019
+ spanIdB64,
2020
+ parentSpanIdB64
2021
+ },
2022
+ name: params.name,
2023
+ startTimeUnixNano,
2024
+ endTimeUnixNano,
2025
+ attributes,
2026
+ status
2027
+ });
2028
+ const replayDestination = currentReplayTraceDestination();
2029
+ recordReplayExportedSpan(
2030
+ replayDestination,
2031
+ base64ToHex2(span.spanId),
2032
+ base64ToHex2(span.traceId)
2033
+ );
2034
+ const mirrorUrl = (replayDestination == null ? void 0 : replayDestination.kind) === "workshop" ? replayDestination.url : replayDestination ? void 0 : this.localDebuggerUrl;
2035
+ if (mirrorUrl) {
2036
+ const body = buildExportTraceServiceRequest2([span]);
2037
+ const mirror = mirrorTraceExportToLocalDebugger(body, {
2038
+ baseUrl: mirrorUrl,
2039
+ debug: false,
2040
+ sdkName: "js-sdk"
2041
+ });
2042
+ this.inFlight.add(mirror);
2043
+ void mirror.finally(() => this.inFlight.delete(mirror));
2044
+ }
2045
+ this.enqueue({ span, replayDestination });
2046
+ if (this.debug) {
2047
+ console.log(`[raindrop] direct shipper: enqueued span "${params.name}"`);
2048
+ }
2049
+ }
2050
+ sendToolSpan(params) {
2051
+ this.sendSpan({
2052
+ ...params,
2053
+ spanKind: "tool"
2054
+ });
2055
+ }
2056
+ enqueue(queued) {
2057
+ if (!this.enabled) return;
2058
+ if (this.queue.length >= this.maxQueueSize) {
2059
+ this.queue.shift();
2060
+ }
2061
+ this.queue.push(queued);
2062
+ if (this.queue.length >= this.maxBatchSize) {
2063
+ void this.flush().catch(() => {
2064
+ });
2065
+ return;
2066
+ }
2067
+ if (!this.timer) {
2068
+ this.timer = setTimeout(() => {
2069
+ this.timer = void 0;
2070
+ void this.flush().catch(() => {
2071
+ });
2072
+ }, this.flushIntervalMs);
2073
+ }
2074
+ }
2075
+ async flush() {
2076
+ var _a;
2077
+ if (!this.enabled) return;
2078
+ if (this.timer) {
2079
+ clearTimeout(this.timer);
2080
+ this.timer = void 0;
2081
+ }
2082
+ while (this.queue.length > 0) {
2083
+ const batch = this.queue.splice(0, this.maxBatchSize);
2084
+ const opts = this.requestOpts();
2085
+ if (!opts) {
2086
+ rateLimitedLog(
2087
+ "js-sdk.direct.shutdown_deadline",
2088
+ () => console.warn(
2089
+ `[raindrop] direct: shutdown flush deadline exceeded; dropping ${batch.length} spans`
2090
+ )
2091
+ );
2092
+ continue;
2093
+ }
2094
+ const groups = /* @__PURE__ */ new Map();
2095
+ for (const queued of batch) {
2096
+ const spans = groups.get(queued.replayDestination);
2097
+ if (spans) spans.push(queued.span);
2098
+ else groups.set(queued.replayDestination, [queued.span]);
2099
+ }
2100
+ for (const [replayDestination, spans] of groups) {
2101
+ if (!replayDestination && !this.cloudEnabled) continue;
2102
+ if ((replayDestination == null ? void 0 : replayDestination.kind) === "workshop") continue;
2103
+ const body = buildExportTraceServiceRequest2(spans);
2104
+ const url = replayDestination ? replayTraceUrl(replayDestination.url) : `${this.baseUrl}traces`;
2105
+ const headers = replayDestination ? {
2106
+ Authorization: `Bearer ${replayDestination.apiKey}`,
2107
+ "X-Raindrop-Replay-Id": replayDestination.replayId,
2108
+ "X-Raindrop-Project-Id": (_a = replayDestination.projectId) != null ? _a : "default"
2109
+ } : { Authorization: `Bearer ${this.writeKey}`, ...projectIdHeaders(this.projectId) };
2110
+ const p = postJson2(url, body, headers, opts);
2111
+ this.inFlight.add(p);
2112
+ try {
2113
+ try {
2114
+ await p;
2115
+ if (this.debug) console.log(`[raindrop] direct: sent ${spans.length} spans`);
2116
+ } catch (err) {
2117
+ if (this.debug) {
2118
+ const msg = err instanceof Error ? err.message : String(err);
2119
+ console.warn(`[raindrop] direct: failed to send spans (dropping): ${msg}`);
2120
+ }
2121
+ }
2122
+ } finally {
2123
+ this.inFlight.delete(p);
2124
+ }
1835
2125
  }
1836
- ]
1837
- };
1838
- }
1839
-
1840
- // src/tracing/direct/context.ts
1841
- var import_api2 = require("@opentelemetry/api");
1842
- var INVALID_TRACE_ID = "00000000000000000000000000000000";
1843
- var INVALID_SPAN_ID = "0000000000000000";
1844
- function hexToBase64(hex) {
1845
- const bytes = new Uint8Array(hex.length / 2);
1846
- for (let i = 0; i < hex.length; i += 2) {
1847
- bytes[i / 2] = parseInt(hex.substring(i, i + 2), 16);
2126
+ }
1848
2127
  }
1849
- return base64Encode2(bytes);
1850
- }
1851
- function getExplicitTraceContext(traceId, parentSpanId) {
1852
- if (!traceId || !parentSpanId || !(0, import_api2.isValidTraceId)(traceId) || !(0, import_api2.isValidSpanId)(parentSpanId)) {
1853
- return void 0;
2128
+ /**
2129
+ * Retry/timeout options for one batch POST, honoring the shutdown budget:
2130
+ * outside shutdown, the normal 3-attempt schedule; during shutdown, a
2131
+ * single attempt clamped to the remaining window; `null` once the window
2132
+ * is exhausted (caller drops the batch). After shutdown() returns,
2133
+ * stragglers run as a single short attempt.
2134
+ */
2135
+ requestOpts() {
2136
+ if (this.shutdownDeadlineAt !== void 0) {
2137
+ const remainingMs = this.shutdownDeadlineAt - Date.now();
2138
+ if (remainingMs <= 0) return null;
2139
+ return {
2140
+ maxAttempts: 1,
2141
+ debug: this.debug,
2142
+ timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
2143
+ };
2144
+ }
2145
+ if (this.hasShutdown) {
2146
+ return { maxAttempts: 1, debug: this.debug, timeoutMs: POST_SHUTDOWN_TIMEOUT_MS };
2147
+ }
2148
+ return { maxAttempts: 3, debug: this.debug };
1854
2149
  }
1855
- return {
1856
- traceIdB64: hexToBase64(traceId),
1857
- parentSpanIdB64: hexToBase64(parentSpanId)
1858
- };
1859
- }
1860
- function getActiveTraceContext() {
1861
- const activeSpan = import_api2.trace.getSpan(import_api2.context.active());
1862
- if (!activeSpan) return {};
1863
- const spanContext = activeSpan.spanContext();
1864
- const traceIdHex = spanContext.traceId;
1865
- const spanIdHex = spanContext.spanId;
1866
- if (traceIdHex === INVALID_TRACE_ID) return {};
1867
- return {
1868
- traceIdB64: hexToBase64(traceIdHex),
1869
- parentSpanIdB64: spanIdHex !== INVALID_SPAN_ID ? hexToBase64(spanIdHex) : void 0
1870
- };
1871
- }
2150
+ async shutdown() {
2151
+ this.hasShutdown = true;
2152
+ this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
2153
+ try {
2154
+ if (this.timer) {
2155
+ clearTimeout(this.timer);
2156
+ this.timer = void 0;
2157
+ }
2158
+ const drain = async () => {
2159
+ await this.flush();
2160
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
2161
+ })));
2162
+ };
2163
+ const settled = await raceWithTimeout(drain(), SHUTDOWN_DEADLINE_MS);
2164
+ if (!settled && this.debug) {
2165
+ console.warn("[raindrop] direct: shutdown deadline exceeded; abandoning in-flight spans");
2166
+ }
2167
+ } finally {
2168
+ this.shutdownDeadlineAt = void 0;
2169
+ }
2170
+ }
2171
+ };
1872
2172
 
1873
- // src/tracing/multi-project.ts
1874
- var import_node_crypto = require("crypto");
1875
- var import_exporter_trace_otlp_proto2 = require("@opentelemetry/exporter-trace-otlp-proto");
1876
- var PROJECT_ID_SPAN_ATTRIBUTE = "raindrop.project_id";
1877
- var AUTH_HINT_SPAN_ATTRIBUTE = "raindrop.auth_hint";
1878
- var EXPORT_SUCCESS = 0;
1879
- var EXPORT_FAILED = 1;
1880
- var SPAN_STATUS_ERROR = 2;
1881
- function authHintForKey(writeKey) {
1882
- if (!writeKey) return void 0;
1883
- return (0, import_node_crypto.createHash)("sha256").update(writeKey, "utf8").digest("hex").slice(0, 8);
1884
- }
1885
- var STATE_KEY2 = /* @__PURE__ */ Symbol.for("raindrop.tracing.multiProjectState");
2173
+ // src/tracing/otel-core/index.ts
2174
+ var import_api2 = require("@opentelemetry/api");
2175
+ var import_core6 = require("@opentelemetry/core");
2176
+ var import_exporter_trace_otlp_proto3 = require("@opentelemetry/exporter-trace-otlp-proto");
2177
+ var import_instrumentation = require("@opentelemetry/instrumentation");
2178
+ var resourceModule = __toESM(require("@opentelemetry/resources"));
2179
+ var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
2180
+ var import_sdk_trace_node = require("@opentelemetry/sdk-trace-node");
2181
+ var import_ai_semantic_conventions = require("@traceloop/ai-semantic-conventions");
2182
+ var ALL_INSTRUMENTATION_LIBRARIES = "all";
2183
+ var TRACER_NAME = "@traceloop/node-server-sdk";
2184
+ var WORKFLOW_NAME_KEY = /* @__PURE__ */ Symbol.for("raindrop.otelCore.workflowName");
2185
+ var ENTITY_NAME_KEY = /* @__PURE__ */ Symbol.for("raindrop.otelCore.entityName");
2186
+ var ASSOCIATION_PROPERTIES_KEY = /* @__PURE__ */ Symbol.for("raindrop.otelCore.associationProperties");
2187
+ var INSTRUMENTATION_LIBRARIES = [
2188
+ "ai",
2189
+ "@traceloop/node-server-sdk",
2190
+ "@traceloop/instrumentation-openai",
2191
+ "@traceloop/instrumentation-langchain",
2192
+ "@traceloop/instrumentation-chroma",
2193
+ "@traceloop/instrumentation-chromadb",
2194
+ "@traceloop/instrumentation-anthropic",
2195
+ "@traceloop/instrumentation-llamaindex",
2196
+ "@traceloop/instrumentation-vertexai",
2197
+ "@traceloop/instrumentation-bedrock",
2198
+ "@traceloop/instrumentation-cohere",
2199
+ "@traceloop/instrumentation-pinecone",
2200
+ "@traceloop/instrumentation-qdrant",
2201
+ "@traceloop/instrumentation-together",
2202
+ TRACER_NAME,
2203
+ "traceloop.tracer"
2204
+ ];
2205
+ var AI_GENERATE_TEXT = "ai.generateText.doGenerate";
2206
+ var AI_STREAM_TEXT = "ai.streamText.doStream";
2207
+ var AI_RESPONSE_TEXT = "ai.response.text";
2208
+ var AI_PROMPT_MESSAGES = "ai.prompt.messages";
2209
+ var AI_PROMPT_TOKENS = "ai.usage.promptTokens";
2210
+ var AI_COMPLETION_TOKENS = "ai.usage.completionTokens";
2211
+ var AI_MODEL_PROVIDER = "ai.model.provider";
2212
+ var STATE_KEY3 = /* @__PURE__ */ Symbol.for("raindrop.otelCore.state");
1886
2213
  function getState2() {
2214
+ var _a;
1887
2215
  const holder = globalThis;
1888
- let state = holder[STATE_KEY2];
1889
- if (!state) {
1890
- state = {
1891
- foreignClientSeen: false,
1892
- seenClientHints: /* @__PURE__ */ new Set(),
1893
- ownerAuthHint: void 0,
1894
- ownerProjectId: void 0,
1895
- pipelineClaimed: false,
1896
- traceloopConfiguredWithoutClaim: false,
1897
- multiKeyWarned: false,
1898
- pendingMultiKeyWarning: false
1899
- };
1900
- holder[STATE_KEY2] = state;
1901
- }
1902
- return state;
2216
+ (_a = holder[STATE_KEY3]) != null ? _a : holder[STATE_KEY3] = {};
2217
+ return holder[STATE_KEY3];
1903
2218
  }
1904
- function emitMultiKeyWarningOnce() {
1905
- const state = getState2();
1906
- if (state.multiKeyWarned) return;
1907
- state.multiKeyWarned = true;
1908
- state.pendingMultiKeyWarning = false;
1909
- console.warn(
1910
- "[raindrop] Multiple API keys detected in one process. The OTel export guard now requires positive attribution: spans not bound to any client (no begin()/asCurrent()) are dropped, and spans bound to a non-owner key are dropped. Manual events are unaffected."
1911
- );
1912
- }
1913
- function registerClientKey(authHint, tracingEnabled = false) {
1914
- if (!authHint) return;
1915
- const state = getState2();
1916
- state.seenClientHints.add(authHint);
1917
- if (state.seenClientHints.size > 1) {
1918
- state.foreignClientSeen = true;
1919
- if (tracingEnabled || state.pipelineClaimed) {
1920
- emitMultiKeyWarningOnce();
1921
- } else {
1922
- state.pendingMultiKeyWarning = true;
2219
+ function parseHeaders(value) {
2220
+ const headers = {};
2221
+ if (!value) return headers;
2222
+ for (const pair of value.split(",")) {
2223
+ const separator = pair.indexOf("=");
2224
+ if (separator <= 0) continue;
2225
+ try {
2226
+ const key = decodeURIComponent(pair.slice(0, separator).trim());
2227
+ const val = decodeURIComponent(pair.slice(separator + 1).trim());
2228
+ if (key && val) headers[key] = val;
2229
+ } catch (e) {
1923
2230
  }
1924
2231
  }
2232
+ return headers;
1925
2233
  }
1926
- function markForeignClient() {
1927
- getState2().foreignClientSeen = true;
1928
- }
1929
- function foreignClientSeen() {
1930
- return getState2().foreignClientSeen;
1931
- }
1932
- function stampSpan(span, projectId, authHint) {
2234
+ function safeStringify(value) {
1933
2235
  try {
1934
- if (projectId) {
1935
- span.setAttribute(PROJECT_ID_SPAN_ATTRIBUTE, projectId);
1936
- }
1937
- if (authHint && foreignClientSeen()) {
1938
- span.setAttribute(AUTH_HINT_SPAN_ATTRIBUTE, authHint);
1939
- }
2236
+ const result = JSON.stringify(value);
2237
+ return result === void 0 ? String(value) : result;
1940
2238
  } catch (e) {
2239
+ return "[unserializable]";
1941
2240
  }
1942
2241
  }
1943
- function stampContextAttributes(span) {
2242
+ function createResource(attributes) {
2243
+ if ("resourceFromAttributes" in resourceModule) {
2244
+ const factory = resourceModule.resourceFromAttributes;
2245
+ if (typeof factory === "function") return factory(attributes);
2246
+ }
2247
+ return new resourceModule.Resource(attributes);
2248
+ }
2249
+ function detectRuntimeResource() {
1944
2250
  try {
1945
- applySpanAttributeFrames(span, (key, value) => span.setAttribute(key, value));
2251
+ if ("detectResourcesSync" in resourceModule && typeof resourceModule.detectResourcesSync === "function" && "envDetectorSync" in resourceModule) {
2252
+ return resourceModule.detectResourcesSync({
2253
+ detectors: [
2254
+ resourceModule.envDetectorSync,
2255
+ resourceModule.processDetectorSync,
2256
+ resourceModule.hostDetectorSync
2257
+ ]
2258
+ });
2259
+ }
2260
+ if ("detectResources" in resourceModule && typeof resourceModule.detectResources === "function" && "envDetector" in resourceModule) {
2261
+ const detected = resourceModule.detectResources({
2262
+ detectors: [
2263
+ resourceModule.envDetector,
2264
+ resourceModule.processDetector,
2265
+ resourceModule.hostDetector
2266
+ ]
2267
+ });
2268
+ if (!(detected instanceof Promise)) {
2269
+ return detected;
2270
+ }
2271
+ }
1946
2272
  } catch (e) {
1947
2273
  }
2274
+ return void 0;
1948
2275
  }
1949
- var RaindropContextSpanProcessor = class {
1950
- onStart(span) {
1951
- try {
1952
- stampContextAttributes(span);
1953
- const bound = currentRoutingBinding();
1954
- if (!bound) return;
1955
- stampSpan(span, bound.projectId, bound.authHint);
1956
- } catch (e) {
2276
+ function logLevel(level) {
2277
+ switch (level) {
2278
+ case "debug":
2279
+ return import_api2.DiagLogLevel.DEBUG;
2280
+ case "info":
2281
+ return import_api2.DiagLogLevel.INFO;
2282
+ case "warn":
2283
+ return import_api2.DiagLogLevel.WARN;
2284
+ default:
2285
+ return import_api2.DiagLogLevel.ERROR;
2286
+ }
2287
+ }
2288
+ function transformAiSdkSpan(span) {
2289
+ const names = {
2290
+ [AI_GENERATE_TEXT]: "ai.generateText.generate",
2291
+ [AI_STREAM_TEXT]: "ai.streamText.stream"
2292
+ };
2293
+ if (!(span.name in names)) return span;
2294
+ const attributes = span.attributes;
2295
+ if (AI_RESPONSE_TEXT in attributes) {
2296
+ const response = attributes[AI_RESPONSE_TEXT];
2297
+ if (typeof response === "string") {
2298
+ attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_COMPLETIONS}.0.content`] = response;
1957
2299
  }
2300
+ attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_COMPLETIONS}.0.role`] = "assistant";
2301
+ delete attributes[AI_RESPONSE_TEXT];
1958
2302
  }
1959
- onEnd(span) {
1960
- var _a;
2303
+ if (AI_PROMPT_MESSAGES in attributes) {
1961
2304
  try {
1962
- if (((_a = span == null ? void 0 : span.status) == null ? void 0 : _a.code) !== SPAN_STATUS_ERROR) return;
1963
- markErrorSpanSeen(span);
2305
+ const parsed = JSON.parse(String(attributes[AI_PROMPT_MESSAGES]));
2306
+ if (Array.isArray(parsed)) {
2307
+ parsed.forEach((message, index) => {
2308
+ if (!message || typeof message !== "object") return;
2309
+ const content = "content" in message ? message.content : void 0;
2310
+ const role = "role" in message ? message.role : void 0;
2311
+ attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_PROMPTS}.${index}.content`] = typeof content === "string" ? content : safeStringify(content);
2312
+ if (typeof role === "string") {
2313
+ attributes[`${import_ai_semantic_conventions.SpanAttributes.LLM_PROMPTS}.${index}.role`] = role;
2314
+ }
2315
+ });
2316
+ }
2317
+ delete attributes[AI_PROMPT_MESSAGES];
1964
2318
  } catch (e) {
1965
2319
  }
1966
2320
  }
1967
- async forceFlush() {
1968
- }
1969
- async shutdown() {
1970
- }
1971
- };
1972
- var GuardedSpanExporter = class {
1973
- constructor(inner, ownerAuthHint) {
1974
- this.droppedTotal = 0;
1975
- this.inner = inner;
1976
- this.ownerAuthHint = ownerAuthHint;
1977
- }
1978
- partition(spans) {
1979
- var _a;
1980
- const allowed = [];
1981
- let dropped = 0;
1982
- const requirePositive = foreignClientSeen();
1983
- for (const span of spans) {
1984
- const attrs = (_a = span.attributes) != null ? _a : {};
1985
- const hint = attrs[AUTH_HINT_SPAN_ATTRIBUTE];
1986
- const keep = requirePositive ? hint === this.ownerAuthHint : hint === void 0 || hint === this.ownerAuthHint;
1987
- if (keep) {
1988
- allowed.push(span);
1989
- } else {
1990
- dropped += 1;
1991
- }
1992
- }
1993
- return { allowed, dropped };
2321
+ if (AI_PROMPT_TOKENS in attributes) {
2322
+ attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_PROMPT_TOKENS] = Number(attributes[AI_PROMPT_TOKENS]);
2323
+ delete attributes[AI_PROMPT_TOKENS];
1994
2324
  }
1995
- warnDropped(dropped) {
1996
- this.droppedTotal += dropped;
1997
- const total = this.droppedTotal;
1998
- rateLimitedLog(
1999
- "js-sdk.multi-project.dropped",
2000
- () => console.warn(
2001
- `[raindrop] Dropped ${dropped} span(s) produced under a different API key than the tracing pipeline's (total dropped: ${total}). One process has ONE OTel pipeline authenticating with the first tracing-enabled client's key; tracing for a different key/org in the same process is unsupported \u2014 run it in its own process. Manual events (track_ai/begin/finish/signals/identify) are unaffected.`
2002
- )
2325
+ if (AI_COMPLETION_TOKENS in attributes) {
2326
+ attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_COMPLETION_TOKENS] = Number(
2327
+ attributes[AI_COMPLETION_TOKENS]
2003
2328
  );
2329
+ delete attributes[AI_COMPLETION_TOKENS];
2004
2330
  }
2005
- export(spans, resultCallback) {
2006
- let allowed;
2007
- let dropped;
2008
- try {
2009
- ({ allowed, dropped } = this.partition(spans));
2010
- } catch (e) {
2011
- if (foreignClientSeen()) {
2012
- this.warnDropped(spans.length);
2013
- resultCallback({ code: EXPORT_FAILED });
2014
- return;
2015
- }
2016
- this.inner.export(spans, resultCallback);
2017
- return;
2018
- }
2019
- if (dropped) {
2020
- this.warnDropped(dropped);
2021
- }
2022
- if (allowed.length === 0) {
2023
- resultCallback({ code: EXPORT_SUCCESS });
2024
- return;
2025
- }
2026
- this.inner.export(allowed, resultCallback);
2027
- }
2028
- shutdown() {
2029
- return this.inner.shutdown();
2331
+ const prompt = attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_PROMPT_TOKENS];
2332
+ const completion = attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_COMPLETION_TOKENS];
2333
+ if (prompt !== void 0 && completion !== void 0) {
2334
+ attributes[import_ai_semantic_conventions.SpanAttributes.LLM_USAGE_TOTAL_TOKENS] = Number(prompt) + Number(completion);
2030
2335
  }
2031
- forceFlush() {
2032
- return this.inner.forceFlush ? this.inner.forceFlush() : Promise.resolve();
2336
+ if (AI_MODEL_PROVIDER in attributes) {
2337
+ const vendor = String(attributes[AI_MODEL_PROVIDER]);
2338
+ attributes[import_ai_semantic_conventions.SpanAttributes.LLM_SYSTEM] = vendor.startsWith("openai") ? "OpenAI" : vendor;
2339
+ delete attributes[AI_MODEL_PROVIDER];
2033
2340
  }
2034
- };
2035
- function buildGuardedExporter(baseUrl, headers, ownerAuthHint) {
2036
- const inner = new import_exporter_trace_otlp_proto2.OTLPTraceExporter({
2037
- url: `${baseUrl}/v1/traces`,
2038
- headers
2341
+ Object.defineProperty(span, "name", {
2342
+ configurable: true,
2343
+ value: names[span.name],
2344
+ writable: true
2039
2345
  });
2040
- return new GuardedSpanExporter(inner, ownerAuthHint);
2041
- }
2042
- function pipelineOwnerHint() {
2043
- return getState2().ownerAuthHint;
2346
+ return span;
2044
2347
  }
2045
- function claimPipeline(authHint, projectId) {
2046
- const state = getState2();
2047
- if (state.pipelineClaimed) {
2048
- return false;
2049
- }
2050
- state.pipelineClaimed = true;
2051
- state.ownerAuthHint = authHint;
2052
- state.ownerProjectId = projectId;
2053
- if (state.foreignClientSeen && state.pendingMultiKeyWarning) {
2054
- emitMultiKeyWarningOnce();
2348
+ function scopeName(span) {
2349
+ var _a;
2350
+ if ("instrumentationScope" in span) {
2351
+ const scope = span.instrumentationScope;
2352
+ if (scope && typeof scope === "object" && "name" in scope && typeof scope.name === "string") {
2353
+ return scope.name;
2354
+ }
2055
2355
  }
2056
- return true;
2057
- }
2058
- function releasePipelineClaim() {
2059
- const state = getState2();
2060
- state.pipelineClaimed = false;
2061
- state.ownerAuthHint = void 0;
2062
- state.ownerProjectId = void 0;
2063
- }
2064
- function markTraceloopConfiguredWithoutClaim() {
2065
- getState2().traceloopConfiguredWithoutClaim = true;
2066
- }
2067
- function traceloopConfiguredWithoutClaim() {
2068
- return getState2().traceloopConfiguredWithoutClaim;
2356
+ return (_a = span.instrumentationLibrary) == null ? void 0 : _a.name;
2069
2357
  }
2070
-
2071
- // src/tracing/direct/shipper.ts
2072
- function serializeAssociationValue(value) {
2073
- return stringifyBounded(value);
2358
+ function contentCaptureDisabled(options) {
2359
+ return options.traceContent === false || (process.env.TRACELOOP_TRACE_CONTENT || "true").toLowerCase() === "false";
2074
2360
  }
2075
- var DirectTraceShipper = class {
2076
- constructor(opts) {
2077
- this.queue = [];
2078
- this.inFlight = /* @__PURE__ */ new Set();
2079
- /**
2080
- * Set once `shutdown()` begins and never cleared. Sends issued after the
2081
- * drain window (stragglers, or flush work the deadline abandoned
2082
- * mid-drain) run as a single short attempt instead of regaining the full
2083
- * retry schedule.
2084
- */
2085
- this.hasShutdown = false;
2086
- var _a, _b, _c, _d, _e, _f;
2087
- this.writeKey = opts.writeKey;
2088
- this.baseUrl = (_a = formatEndpoint2(opts.endpoint)) != null ? _a : "https://api.raindrop.ai/v1/";
2089
- this.enabled = (_b = opts.enabled) != null ? _b : true;
2090
- this.cloudEnabled = (_c = opts.cloudEnabled) != null ? _c : true;
2091
- this.debug = opts.debug;
2092
- this.projectId = opts.projectId;
2093
- this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
2094
- this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
2095
- this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
2096
- const resolved = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl);
2097
- if (resolved && resolved !== this.baseUrl) {
2098
- this.localDebuggerUrl = resolved;
2099
- }
2100
- }
2101
- /**
2102
- * Build and enqueue an OTLP span for a trackTool call.
2103
- *
2104
- * Reads the active OTEL context if traceId/parentSpanId are not provided,
2105
- * so spans still appear as children in the trace tree.
2106
- */
2107
- sendSpan(params) {
2108
- var _a, _b, _c;
2109
- if (!this.enabled) return;
2110
- let traceIdB64 = params.traceId;
2111
- let parentSpanIdB64 = params.parentSpanId;
2112
- if (!traceIdB64) {
2113
- const activeCtx = getActiveTraceContext();
2114
- traceIdB64 = activeCtx.traceIdB64;
2115
- parentSpanIdB64 = activeCtx.parentSpanIdB64;
2116
- }
2117
- const spanIdB64 = (_a = params.spanId) != null ? _a : base64Encode2(randomBytes2(8));
2118
- if (!traceIdB64) {
2119
- traceIdB64 = base64Encode2(randomBytes2(16));
2120
- }
2121
- const startTimeUnixNano = String(params.startTimeMs * 1e6);
2122
- const endTimeUnixNano = String(params.endTimeMs * 1e6);
2123
- const attributes = [
2124
- // Required: passes hasAIOperation() filter in backend (parseSpan.ts)
2125
- attrString2("traceloop.span.kind", (_b = params.spanKind) != null ? _b : "tool"),
2126
- // Parsed by backend for input/output payloads
2127
- attrString2("traceloop.entity.input", params.input),
2128
- attrString2("traceloop.entity.output", params.output),
2129
- // Duration tracking
2130
- attrInt2("traceloop.entity.duration_ms", params.durationMs),
2131
- // Per-span project routing: the ingest boundary routes on this attribute
2132
- // (org-validated) and falls back to the request's project header. Direct
2133
- // spans ship on this instance's own key, so no cross-key auth hint.
2134
- attrString2(PROJECT_ID_SPAN_ATTRIBUTE, this.projectId)
2135
- ];
2136
- for (const [key, value] of Object.entries(params.properties)) {
2137
- if (value === void 0) {
2138
- continue;
2139
- }
2140
- attributes.push(
2141
- attrString2(`traceloop.association.properties.${key}`, serializeAssociationValue(value))
2142
- );
2143
- }
2144
- const spanIdentity = { spanIdB64 };
2145
- claimSpanForFrames(spanIdentity);
2146
- for (const [key, value] of Object.entries({
2147
- ...currentSpanAttributes(),
2148
- ...params.attributes
2149
- })) {
2150
- attributes.push(attrString2(key, value));
2151
- }
2152
- attributes.push(...(_c = params.otlpAttributes) != null ? _c : []);
2153
- let status;
2154
- if (params.error) {
2155
- status = { code: 2, message: params.error };
2156
- markErrorSpanSeen(spanIdentity);
2157
- } else {
2158
- status = {
2159
- code: 1
2160
- /* STATUS_CODE_OK */
2161
- };
2162
- }
2163
- const span = buildOtlpSpan2({
2164
- ids: {
2165
- traceIdB64,
2166
- spanIdB64,
2167
- parentSpanIdB64
2168
- },
2169
- name: params.name,
2170
- startTimeUnixNano,
2171
- endTimeUnixNano,
2172
- attributes,
2173
- status
2174
- });
2175
- if (this.localDebuggerUrl) {
2176
- const body = buildExportTraceServiceRequest2([span]);
2177
- mirrorTraceExportToLocalDebugger(body, {
2178
- baseUrl: this.localDebuggerUrl,
2179
- debug: false,
2180
- sdkName: "js-sdk"
2181
- });
2182
- }
2183
- this.enqueue(span);
2184
- if (this.debug) {
2185
- console.log(`[raindrop] direct shipper: enqueued span "${params.name}"`);
2361
+ function shouldSendTraceContent() {
2362
+ var _a;
2363
+ const contextual = import_api2.context.active().getValue(import_ai_semantic_conventions.CONTEXT_KEY_ALLOW_TRACE_CONTENT);
2364
+ if (typeof contextual === "boolean") return contextual;
2365
+ if (((_a = getState2().configuration) == null ? void 0 : _a.traceContent) === false) return false;
2366
+ return (process.env.TRACELOOP_TRACE_CONTENT || "true").toLowerCase() !== "false";
2367
+ }
2368
+ function enrichStart(span) {
2369
+ const active = import_api2.context.active();
2370
+ const workflow = active.getValue(WORKFLOW_NAME_KEY);
2371
+ if (typeof workflow === "string")
2372
+ span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_WORKFLOW_NAME, workflow);
2373
+ const entity = active.getValue(ENTITY_NAME_KEY);
2374
+ if (typeof entity === "string") span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_PATH, entity);
2375
+ const properties = active.getValue(ASSOCIATION_PROPERTIES_KEY);
2376
+ if (properties && typeof properties === "object") {
2377
+ for (const [key, value] of Object.entries(properties)) {
2378
+ if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
2379
+ span.setAttribute(`${import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ASSOCIATION_PROPERTIES}.${key}`, value);
2380
+ }
2186
2381
  }
2187
2382
  }
2188
- sendToolSpan(params) {
2189
- this.sendSpan({
2190
- ...params,
2191
- spanKind: "tool"
2192
- });
2193
- }
2194
- enqueue(span) {
2195
- if (!this.enabled) return;
2196
- if (this.queue.length >= this.maxQueueSize) {
2197
- this.queue.shift();
2383
+ }
2384
+ function createSpanProcessor(options) {
2385
+ var _a, _b;
2386
+ const baseUrl = options.baseUrl || process.env.TRACELOOP_BASE_URL || "https://api.traceloop.com";
2387
+ const apiKey = options.apiKey || process.env.TRACELOOP_API_KEY;
2388
+ const resolvedHeaders = (_a = options.headers) != null ? _a : process.env.TRACELOOP_HEADERS ? parseHeaders(process.env.TRACELOOP_HEADERS) : { Authorization: `Bearer ${apiKey}` };
2389
+ const baseExporter = (_b = options.exporter) != null ? _b : new import_exporter_trace_otlp_proto3.OTLPTraceExporter({ url: `${baseUrl}/v1/traces`, headers: resolvedHeaders });
2390
+ const exporter = options.routeReplayTraces ? new ReplayRoutingSpanExporter(baseExporter) : baseExporter;
2391
+ const processor = options.disableBatch ? new import_sdk_trace_base.SimpleSpanProcessor(exporter) : new import_sdk_trace_base.BatchSpanProcessor(exporter);
2392
+ const originalOnStart = processor.onStart.bind(processor);
2393
+ const originalOnEnd = processor.onEnd.bind(processor);
2394
+ processor.onStart = (span, parentContext) => {
2395
+ try {
2396
+ enrichStart(span);
2397
+ originalOnStart(span, parentContext);
2398
+ } catch (e) {
2198
2399
  }
2199
- this.queue.push(span);
2200
- if (this.queue.length >= this.maxBatchSize) {
2201
- void this.flush().catch(() => {
2202
- });
2203
- return;
2400
+ };
2401
+ processor.onEnd = (span) => {
2402
+ var _a2;
2403
+ let outgoing = span;
2404
+ try {
2405
+ const allowed = options.allowedInstrumentationLibraries;
2406
+ if (allowed !== ALL_INSTRUMENTATION_LIBRARIES && ![...INSTRUMENTATION_LIBRARIES, ...allowed != null ? allowed : []].includes((_a2 = scopeName(span)) != null ? _a2 : "")) {
2407
+ return;
2408
+ }
2409
+ outgoing = transformAiSdkSpan(span);
2410
+ if (outgoing !== span) copyReplayTraceDestination(span, outgoing);
2411
+ } catch (e) {
2204
2412
  }
2205
- if (!this.timer) {
2206
- this.timer = setTimeout(() => {
2207
- this.timer = void 0;
2208
- void this.flush().catch(() => {
2209
- });
2210
- }, this.flushIntervalMs);
2413
+ try {
2414
+ originalOnEnd(outgoing);
2415
+ } catch (e) {
2211
2416
  }
2212
- }
2213
- async flush() {
2214
- if (!this.enabled) return;
2215
- if (this.timer) {
2216
- clearTimeout(this.timer);
2217
- this.timer = void 0;
2417
+ };
2418
+ return processor;
2419
+ }
2420
+ function initialize(options = {}) {
2421
+ var _a;
2422
+ const state2 = getState2();
2423
+ if (state2.configuration) return;
2424
+ state2.configuration = Object.freeze({ ...options });
2425
+ if (options.logLevel) import_api2.diag.setLogger(new import_api2.DiagConsoleLogger(), logLevel(options.logLevel));
2426
+ if (options.tracingEnabled === false) return;
2427
+ const baseUrl = options.baseUrl || process.env.TRACELOOP_BASE_URL || "https://api.traceloop.com";
2428
+ state2.defaultProcessor = createSpanProcessor({
2429
+ ...options,
2430
+ baseUrl,
2431
+ allowedInstrumentationLibraries: ALL_INSTRUMENTATION_LIBRARIES
2432
+ });
2433
+ const serviceResource = createResource({
2434
+ "service.name": options.appName || process.env.npm_package_name || "unknown_service"
2435
+ });
2436
+ const detectedResource = detectRuntimeResource();
2437
+ state2.provider = new import_sdk_trace_node.NodeTracerProvider({
2438
+ // Detected attributes win over the configured resource, matching
2439
+ // sdk-node's `this._resource.merge(detectResourcesSync(...))` so
2440
+ // OTEL_SERVICE_NAME / OTEL_RESOURCE_ATTRIBUTES can still override appName.
2441
+ resource: detectedResource ? serviceResource.merge(detectedResource) : serviceResource,
2442
+ spanProcessors: [state2.defaultProcessor, ...options.processor ? [options.processor] : []]
2443
+ });
2444
+ state2.provider.register({
2445
+ contextManager: options.contextManager,
2446
+ propagator: options.propagator
2447
+ });
2448
+ const instrumentations = (_a = options.instrumentations) != null ? _a : [];
2449
+ if (contentCaptureDisabled(options)) {
2450
+ for (const instrumentation of instrumentations) {
2451
+ try {
2452
+ const config = {
2453
+ ...instrumentation.getConfig(),
2454
+ traceContent: false
2455
+ };
2456
+ instrumentation.setConfig(config);
2457
+ } catch (e) {
2458
+ }
2218
2459
  }
2219
- while (this.queue.length > 0) {
2220
- const batch = this.queue.splice(0, this.maxBatchSize);
2221
- if (!this.cloudEnabled) {
2222
- if (this.debug) console.log(`[raindrop] direct: dropped ${batch.length} cloud spans (local-only)`);
2223
- continue;
2460
+ }
2461
+ (0, import_instrumentation.registerInstrumentations)({ instrumentations });
2462
+ }
2463
+ async function forceFlush() {
2464
+ var _a, _b;
2465
+ const state2 = getState2();
2466
+ try {
2467
+ await ((_a = state2.provider) == null ? void 0 : _a.forceFlush());
2468
+ await ((_b = state2.defaultProcessor) == null ? void 0 : _b.forceFlush());
2469
+ } catch (e) {
2470
+ }
2471
+ }
2472
+ function withEntity(type, config, fn, args) {
2473
+ let entityContext = import_api2.context.active();
2474
+ if (type === import_ai_semantic_conventions.TraceloopSpanKindValues.WORKFLOW) {
2475
+ entityContext = entityContext.setValue(WORKFLOW_NAME_KEY, config.name);
2476
+ }
2477
+ const parentPath = entityContext.getValue(ENTITY_NAME_KEY);
2478
+ if (type === import_ai_semantic_conventions.TraceloopSpanKindValues.TASK || type === import_ai_semantic_conventions.TraceloopSpanKindValues.TOOL) {
2479
+ entityContext = entityContext.setValue(
2480
+ ENTITY_NAME_KEY,
2481
+ `${typeof parentPath === "string" ? `${parentPath}.` : ""}${config.name}`
2482
+ );
2483
+ }
2484
+ if (config.traceContent !== void 0) {
2485
+ entityContext = entityContext.setValue(import_ai_semantic_conventions.CONTEXT_KEY_ALLOW_TRACE_CONTENT, config.traceContent);
2486
+ }
2487
+ if (config.associationProperties) {
2488
+ entityContext = entityContext.setValue(
2489
+ ASSOCIATION_PROPERTIES_KEY,
2490
+ config.associationProperties
2491
+ );
2492
+ }
2493
+ if (config.suppressTracing) {
2494
+ entityContext = (0, import_core6.suppressTracing)(entityContext);
2495
+ }
2496
+ let callbackStarted = false;
2497
+ const run = (span) => {
2498
+ var _a;
2499
+ try {
2500
+ span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_NAME, config.name);
2501
+ span.setAttribute(
2502
+ import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_PATH,
2503
+ typeof parentPath === "string" ? parentPath : ""
2504
+ );
2505
+ span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_SPAN_KIND, type);
2506
+ if (type === import_ai_semantic_conventions.TraceloopSpanKindValues.WORKFLOW) {
2507
+ span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_WORKFLOW_NAME, config.name);
2224
2508
  }
2225
- const opts = this.requestOpts();
2226
- if (!opts) {
2227
- rateLimitedLog(
2228
- "js-sdk.direct.shutdown_deadline",
2229
- () => console.warn(
2230
- `[raindrop] direct: shutdown flush deadline exceeded; dropping ${batch.length} spans`
2509
+ if (config.version !== void 0)
2510
+ span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_VERSION, config.version);
2511
+ const input = (_a = config.inputParameters) != null ? _a : args;
2512
+ if (shouldSendTraceContent()) {
2513
+ span.setAttribute(
2514
+ import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_INPUT,
2515
+ safeStringify(
2516
+ input.length === 1 && input[0] !== null && typeof input[0] === "object" && !(input[0] instanceof Map) ? { args: [], kwargs: input[0] } : { args: input, kwargs: {} }
2231
2517
  )
2232
2518
  );
2233
- continue;
2234
2519
  }
2235
- const body = buildExportTraceServiceRequest2(batch);
2236
- const url = `${this.baseUrl}traces`;
2237
- const p = postJson2(
2238
- url,
2239
- body,
2240
- { Authorization: `Bearer ${this.writeKey}`, ...projectIdHeaders(this.projectId) },
2241
- opts
2242
- );
2243
- this.inFlight.add(p);
2520
+ } catch (e) {
2521
+ }
2522
+ let result;
2523
+ try {
2524
+ callbackStarted = true;
2525
+ result = fn(...args);
2526
+ } catch (error) {
2244
2527
  try {
2245
- try {
2246
- await p;
2247
- if (this.debug) console.log(`[raindrop] direct: sent ${batch.length} spans`);
2248
- } catch (err) {
2249
- if (this.debug) {
2250
- const msg = err instanceof Error ? err.message : String(err);
2251
- console.warn(`[raindrop] direct: failed to send spans (dropping): ${msg}`);
2252
- }
2253
- }
2254
- } finally {
2255
- this.inFlight.delete(p);
2528
+ span.end();
2529
+ } catch (e) {
2256
2530
  }
2531
+ throw error;
2257
2532
  }
2258
- }
2259
- /**
2260
- * Retry/timeout options for one batch POST, honoring the shutdown budget:
2261
- * outside shutdown, the normal 3-attempt schedule; during shutdown, a
2262
- * single attempt clamped to the remaining window; `null` once the window
2263
- * is exhausted (caller drops the batch). After shutdown() returns,
2264
- * stragglers run as a single short attempt.
2265
- */
2266
- requestOpts() {
2267
- if (this.shutdownDeadlineAt !== void 0) {
2268
- const remainingMs = this.shutdownDeadlineAt - Date.now();
2269
- if (remainingMs <= 0) return null;
2270
- return {
2271
- maxAttempts: 1,
2272
- debug: this.debug,
2273
- timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
2274
- };
2275
- }
2276
- if (this.hasShutdown) {
2277
- return { maxAttempts: 1, debug: this.debug, timeoutMs: POST_SHUTDOWN_TIMEOUT_MS };
2533
+ if (result instanceof Promise) {
2534
+ return result.then(
2535
+ (value) => {
2536
+ try {
2537
+ if (shouldSendTraceContent())
2538
+ span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_OUTPUT, safeStringify(value));
2539
+ span.end();
2540
+ } catch (e) {
2541
+ }
2542
+ return value;
2543
+ },
2544
+ (error) => {
2545
+ try {
2546
+ span.end();
2547
+ } catch (e) {
2548
+ }
2549
+ throw error;
2550
+ }
2551
+ );
2278
2552
  }
2279
- return { maxAttempts: 3, debug: this.debug };
2280
- }
2281
- async shutdown() {
2282
- this.hasShutdown = true;
2283
- this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
2284
2553
  try {
2285
- if (this.timer) {
2286
- clearTimeout(this.timer);
2287
- this.timer = void 0;
2288
- }
2289
- const drain = async () => {
2290
- await this.flush();
2291
- await Promise.all([...this.inFlight].map((p) => p.catch(() => {
2292
- })));
2293
- };
2294
- const settled = await raceWithTimeout(drain(), SHUTDOWN_DEADLINE_MS);
2295
- if (!settled && this.debug) {
2296
- console.warn("[raindrop] direct: shutdown deadline exceeded; abandoning in-flight spans");
2297
- }
2298
- } finally {
2299
- this.shutdownDeadlineAt = void 0;
2554
+ if (shouldSendTraceContent())
2555
+ span.setAttribute(import_ai_semantic_conventions.SpanAttributes.TRACELOOP_ENTITY_OUTPUT, safeStringify(result));
2556
+ span.end();
2557
+ } catch (e) {
2300
2558
  }
2559
+ return result;
2560
+ };
2561
+ try {
2562
+ const tracer = import_api2.trace.getTracer(TRACER_NAME);
2563
+ return import_api2.context.with(
2564
+ entityContext,
2565
+ () => tracer.startActiveSpan(`${config.name}.${type}`, {}, entityContext, run)
2566
+ );
2567
+ } catch (error) {
2568
+ if (callbackStarted) throw error;
2569
+ return fn(...args);
2301
2570
  }
2302
- };
2571
+ }
2572
+ function withTask(config, fn, ...args) {
2573
+ return withEntity(import_ai_semantic_conventions.TraceloopSpanKindValues.TASK, config, fn, args);
2574
+ }
2575
+ function withTool(config, fn, ...args) {
2576
+ return withEntity(import_ai_semantic_conventions.TraceloopSpanKindValues.TOOL, config, fn, args);
2577
+ }
2303
2578
 
2304
2579
  // src/tracing/exit-flush.ts
2305
- var STATE_KEY3 = /* @__PURE__ */ Symbol.for("raindrop.tracing.exitFlushState");
2580
+ var STATE_KEY4 = /* @__PURE__ */ Symbol.for("raindrop.tracing.exitFlushState");
2306
2581
  function getState3() {
2307
2582
  const holder = globalThis;
2308
- let state = holder[STATE_KEY3];
2309
- if (!state) {
2310
- state = {
2583
+ let state2 = holder[STATE_KEY4];
2584
+ if (!state2) {
2585
+ state2 = {
2311
2586
  clientFlushers: /* @__PURE__ */ new Set(),
2312
2587
  pipelineFlushNeeded: false,
2313
2588
  handlerRegistered: false
2314
2589
  };
2315
- holder[STATE_KEY3] = state;
2590
+ holder[STATE_KEY4] = state2;
2316
2591
  }
2317
- return state;
2592
+ return state2;
2318
2593
  }
2319
- function ensureExitHandler(state) {
2320
- if (state.handlerRegistered) return;
2594
+ function ensureExitHandler(state2) {
2595
+ if (state2.handlerRegistered) return;
2321
2596
  if (typeof process === "undefined" || typeof process.once !== "function") return;
2322
- state.handlerRegistered = true;
2597
+ state2.handlerRegistered = true;
2323
2598
  process.once("beforeExit", () => {
2324
2599
  void flushAll();
2325
2600
  });
2326
2601
  }
2327
2602
  function registerClientFlusher(flush) {
2328
- const state = getState3();
2329
- state.clientFlushers.add(flush);
2330
- ensureExitHandler(state);
2603
+ const state2 = getState3();
2604
+ state2.clientFlushers.add(flush);
2605
+ ensureExitHandler(state2);
2331
2606
  return () => {
2332
- state.clientFlushers.delete(flush);
2607
+ state2.clientFlushers.delete(flush);
2333
2608
  };
2334
2609
  }
2335
2610
  function markPipelineForExitFlush() {
2336
- const state = getState3();
2337
- state.pipelineFlushNeeded = true;
2338
- ensureExitHandler(state);
2611
+ const state2 = getState3();
2612
+ state2.pipelineFlushNeeded = true;
2613
+ ensureExitHandler(state2);
2339
2614
  }
2340
2615
  async function flushAll() {
2341
- const state = getState3();
2616
+ const state2 = getState3();
2342
2617
  const tasks = [];
2343
- for (const flush of state.clientFlushers) {
2618
+ for (const flush of state2.clientFlushers) {
2344
2619
  tasks.push(Promise.resolve().then(flush).catch(() => {
2345
2620
  }));
2346
2621
  }
2347
- if (state.pipelineFlushNeeded) {
2622
+ if (state2.pipelineFlushNeeded) {
2348
2623
  tasks.push(
2349
2624
  Promise.resolve().then(() => forceFlush()).catch(() => {
2350
2625
  })
@@ -3686,6 +3961,14 @@ if (localDebuggerEnabled()) {
3686
3961
  process.env.OTEL_EXPORTER_OTLP_TRACES_PROTOCOL = "http/json";
3687
3962
  }
3688
3963
  }
3964
+ var DropSpanExporter = class {
3965
+ export(_spans, resultCallback) {
3966
+ resultCallback({ code: 0 });
3967
+ }
3968
+ shutdown() {
3969
+ return Promise.resolve();
3970
+ }
3971
+ };
3689
3972
  var CompositeSpanProcessor = class {
3690
3973
  constructor(requiredProcessors, bestEffortProcessors) {
3691
3974
  this.requiredProcessors = requiredProcessors;
@@ -3817,10 +4100,24 @@ function createLocalDebuggerSpanProcessor(options) {
3817
4100
  url: `${localDebuggerUrl}traces`,
3818
4101
  headers: {}
3819
4102
  });
4103
+ if (!options.routeReplayTraces) {
4104
+ const exportLocal = localExporter.export.bind(localExporter);
4105
+ localExporter.export = (spans, callback) => {
4106
+ const localSpans = spans.filter(
4107
+ (span) => {
4108
+ var _a;
4109
+ return ((_a = replayTraceDestinationFor(span)) == null ? void 0 : _a.kind) !== "raindrop";
4110
+ }
4111
+ );
4112
+ if (localSpans.length === 0) callback({ code: 0 });
4113
+ else exportLocal(localSpans, callback);
4114
+ };
4115
+ }
3820
4116
  try {
3821
4117
  return createSpanProcessor({
3822
4118
  apiKey: options.writeKey,
3823
4119
  baseUrl: localDebuggerUrl,
4120
+ routeReplayTraces: options.routeReplayTraces,
3824
4121
  disableBatch: options.disableBatching,
3825
4122
  exporter: localExporter,
3826
4123
  headers: {},
@@ -4234,7 +4531,8 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
4234
4531
  writeKey,
4235
4532
  disableBatching,
4236
4533
  allowedInstrumentationLibraries: ALL_INSTRUMENTATION_LIBRARIES,
4237
- localDebuggerUrlOpt: localDebuggerUrl
4534
+ localDebuggerUrlOpt: localDebuggerUrl,
4535
+ routeReplayTraces: !cloudEnabledResolved
4238
4536
  });
4239
4537
  if (!cloudEnabledResolved) {
4240
4538
  if (localDebuggerProcessor) {
@@ -4242,22 +4540,40 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
4242
4540
  baseUrl: apiUrl,
4243
4541
  apiKey: writeKey,
4244
4542
  ...otherOptions,
4543
+ exporter: new DropSpanExporter(),
4245
4544
  logLevel: logLevel2,
4246
4545
  silenceInitializationMessage: true,
4247
4546
  tracingEnabled: tracingEnabled !== false,
4248
4547
  disableBatch: disableBatching,
4249
- processor: localDebuggerProcessor,
4548
+ processor: new CompositeSpanProcessor(
4549
+ [new RaindropContextSpanProcessor(), localDebuggerProcessor],
4550
+ []
4551
+ ),
4250
4552
  instrumentations: createConfiguredInstrumentations(otherOptions)
4251
4553
  });
4252
4554
  traceloopInitialized = true;
4253
4555
  markTraceloopConfiguredWithoutClaim();
4254
4556
  } else {
4557
+ const replayOnlyProcessor = createSpanProcessor({
4558
+ exporter: new DropSpanExporter(),
4559
+ routeReplayTraces: true,
4560
+ disableBatch: disableBatching,
4561
+ allowedInstrumentationLibraries: ALL_INSTRUMENTATION_LIBRARIES
4562
+ });
4255
4563
  initialize({
4256
4564
  baseUrl: apiUrl,
4257
4565
  apiKey: writeKey,
4566
+ ...otherOptions,
4567
+ exporter: new DropSpanExporter(),
4258
4568
  logLevel: logLevel2,
4259
4569
  silenceInitializationMessage: true,
4260
- tracingEnabled: false
4570
+ tracingEnabled: tracingEnabled !== false,
4571
+ disableBatch: disableBatching,
4572
+ processor: new CompositeSpanProcessor(
4573
+ [new RaindropContextSpanProcessor(), replayOnlyProcessor],
4574
+ []
4575
+ ),
4576
+ instrumentations: createConfiguredInstrumentations(otherOptions)
4261
4577
  });
4262
4578
  traceloopInitialized = true;
4263
4579
  markTraceloopConfiguredWithoutClaim();
@@ -4285,7 +4601,8 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
4285
4601
  let guardedExporter;
4286
4602
  try {
4287
4603
  const callerExporter = otherOptions.exporter;
4288
- guardedExporter = callerExporter ? new GuardedSpanExporter(callerExporter, ownerHint) : buildGuardedExporter(apiUrl, exporterHeaders, ownerHint);
4604
+ const guarded = callerExporter ? new GuardedSpanExporter(callerExporter, ownerHint) : buildGuardedExporter(apiUrl, exporterHeaders, ownerHint);
4605
+ guardedExporter = new ReplayRoutingSpanExporter(guarded);
4289
4606
  } catch (guardError) {
4290
4607
  releasePipelineClaim();
4291
4608
  claimedPipeline = false;
@@ -4536,7 +4853,8 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
4536
4853
  writeKey,
4537
4854
  disableBatching,
4538
4855
  allowedInstrumentationLibraries: processorOptions == null ? void 0 : processorOptions.allowedInstrumentationLibraries,
4539
- localDebuggerUrlOpt: localDebuggerUrl
4856
+ localDebuggerUrlOpt: localDebuggerUrl,
4857
+ routeReplayTraces: true
4540
4858
  });
4541
4859
  return withV2SpanCompat(
4542
4860
  localOnlyProcessor != null ? localOnlyProcessor : {
@@ -4557,6 +4875,7 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
4557
4875
  apiKey: writeKey,
4558
4876
  disableBatch: disableBatching,
4559
4877
  ...processorOptions != null ? processorOptions : {},
4878
+ routeReplayTraces: true,
4560
4879
  ...headers ? { headers } : {}
4561
4880
  });
4562
4881
  const localDebuggerProcessor = createLocalDebuggerSpanProcessor({