@raindrop-ai/eve 0.0.23 → 0.0.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -4,11 +4,794 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var api = require('@opentelemetry/api');
6
6
  var aiSdk = require('@raindrop-ai/ai-sdk');
7
- var module$1 = require('module');
8
7
  var async_hooks = require('async_hooks');
8
+ var child_process = require('child_process');
9
+ var path = require('path');
10
+ var module$1 = require('module');
9
11
 
10
12
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
11
13
  // src/index.ts
14
+
15
+ // ../core/dist/chunk-WJOR6M7H.js
16
+ function getAsyncLocalStorageCtor() {
17
+ return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
18
+ }
19
+ var MAX_BINDING_STACK = 128;
20
+ var EMPTY_STACK = [];
21
+ var ContextStackStorage = class {
22
+ /** Emitted once when this runtime cannot support an ambient push. */
23
+ constructor(noAmbientBindWarning) {
24
+ this.noAmbientBindWarning = noAmbientBindWarning;
25
+ this._als = null;
26
+ this._enterWithUsable = false;
27
+ this._syncStack = EMPTY_STACK;
28
+ this._adoptionChecked = false;
29
+ this._warnedNoAmbientBind = false;
30
+ }
31
+ maybeAdoptAsyncLocalStorage() {
32
+ if (this._adoptionChecked) return;
33
+ this._adoptionChecked = true;
34
+ const Ctor = getAsyncLocalStorageCtor();
35
+ if (!Ctor) return;
36
+ const als = new Ctor();
37
+ try {
38
+ als.run(EMPTY_STACK, () => {
39
+ });
40
+ } catch (e) {
41
+ return;
42
+ }
43
+ this._als = als;
44
+ if (typeof als.enterWith === "function") {
45
+ try {
46
+ als.enterWith(EMPTY_STACK);
47
+ this._enterWithUsable = true;
48
+ } catch (e) {
49
+ this._enterWithUsable = false;
50
+ }
51
+ }
52
+ }
53
+ getStack() {
54
+ var _a;
55
+ this.maybeAdoptAsyncLocalStorage();
56
+ if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
57
+ return this._syncStack;
58
+ }
59
+ /**
60
+ * Persist an ambient stack mutation. Returns false when an ALS is adopted but
61
+ * `enterWith` is unusable (workerd): callers must NOT fall back to the
62
+ * process-shared sync stack, since concurrent isolates would cross-stamp.
63
+ */
64
+ setAmbientStack(stack) {
65
+ if (this._als) {
66
+ if (!this._enterWithUsable) return false;
67
+ this._als.enterWith(stack);
68
+ return true;
69
+ }
70
+ this._syncStack = stack;
71
+ return true;
72
+ }
73
+ push(binding) {
74
+ this.maybeAdoptAsyncLocalStorage();
75
+ if (this._als && !this._enterWithUsable) {
76
+ this.warnNoAmbientBindOnce();
77
+ return;
78
+ }
79
+ let stack = this.getStack();
80
+ if (stack.length >= MAX_BINDING_STACK) {
81
+ stack = stack.filter((b) => b.isLive());
82
+ if (stack.length >= MAX_BINDING_STACK) {
83
+ stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
84
+ }
85
+ }
86
+ this.setAmbientStack([...stack, binding]);
87
+ }
88
+ remove(binding) {
89
+ binding.markDead();
90
+ const stack = this.getStack();
91
+ const pruned = stack.filter((b) => b !== binding && b.isLive());
92
+ if (pruned.length !== stack.length) {
93
+ this.setAmbientStack(pruned);
94
+ }
95
+ }
96
+ runWith(binding, callback) {
97
+ this.maybeAdoptAsyncLocalStorage();
98
+ if (this._als) {
99
+ return this._als.run([...this.getStack(), binding], callback);
100
+ }
101
+ const previous = this._syncStack;
102
+ this._syncStack = [...previous, binding];
103
+ try {
104
+ return callback();
105
+ } finally {
106
+ this._syncStack = previous;
107
+ }
108
+ }
109
+ current() {
110
+ const stack = this.getStack();
111
+ if (stack.length === 0) return void 0;
112
+ const top = stack[stack.length - 1];
113
+ if (top.isLive()) return top;
114
+ const pruned = stack.filter((b) => b.isLive());
115
+ this.setAmbientStack(pruned);
116
+ return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
117
+ }
118
+ warnNoAmbientBindOnce() {
119
+ if (this._warnedNoAmbientBind) return;
120
+ this._warnedNoAmbientBind = true;
121
+ console.warn(this.noAmbientBindWarning);
122
+ }
123
+ };
124
+ var NO_AMBIENT_ROUTING_BIND_WARNING = "[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so begin()/finish() cannot scope auto-instrumented spans to a project without cross-contaminating concurrent requests. Manual events and explicit span routing are unaffected; use asCurrent()/withSpan (run-based) to route auto-instrumented spans on this runtime.";
125
+ var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
126
+ function routingStorage() {
127
+ const holder = globalThis;
128
+ let storage = holder[ROUTING_STORAGE_KEY];
129
+ if (!storage) {
130
+ storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
131
+ holder[ROUTING_STORAGE_KEY] = storage;
132
+ }
133
+ return storage;
134
+ }
135
+ function currentRoutingBinding() {
136
+ const bound = routingStorage().current();
137
+ if (!bound) return void 0;
138
+ return {
139
+ projectId: bound.projectId,
140
+ authHint: bound.authHint,
141
+ ...bound.appGit ? { appGit: bound.appGit } : {},
142
+ ...bound.appGitSource ? { appGitSource: bound.appGitSource } : {}
143
+ };
144
+ }
145
+ var APP_COMMIT_SHA = "raindrop.app.commit_sha";
146
+ var APP_COMMIT_DIRTY = "raindrop.app.commit_dirty";
147
+ var APP_BRANCH = "raindrop.app.branch";
148
+ var APP_GIT_KEYS = [APP_COMMIT_SHA, APP_COMMIT_DIRTY, APP_BRANCH];
149
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
150
+ function appGitExplicitKeys(properties) {
151
+ const keys = /* @__PURE__ */ new Set();
152
+ if (!properties) return keys;
153
+ for (const key of APP_GIT_KEYS) {
154
+ if (own(properties, key)) keys.add(key);
155
+ }
156
+ return keys;
157
+ }
158
+ function mergeAppGitSnapshot(base, properties, explicitKeys = /* @__PURE__ */ new Set()) {
159
+ try {
160
+ const result = { ...base };
161
+ if (properties && own(properties, APP_COMMIT_SHA) && properties[APP_COMMIT_SHA] !== result[APP_COMMIT_SHA]) {
162
+ if (!explicitKeys.has(APP_COMMIT_DIRTY) && !own(properties, APP_COMMIT_DIRTY)) {
163
+ delete result[APP_COMMIT_DIRTY];
164
+ }
165
+ if (!explicitKeys.has(APP_BRANCH) && !own(properties, APP_BRANCH)) {
166
+ delete result[APP_BRANCH];
167
+ }
168
+ }
169
+ for (const key of APP_GIT_KEYS) {
170
+ if (properties && own(properties, key)) result[key] = properties[key];
171
+ }
172
+ return Object.freeze(result);
173
+ } catch (e) {
174
+ return Object.freeze({});
175
+ }
176
+ }
177
+ function validAppCommitSha(value) {
178
+ if (typeof value !== "string" || value.length > 128) return void 0;
179
+ const cleaned = value.trim();
180
+ return /^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(cleaned) ? cleaned.toLowerCase() : void 0;
181
+ }
182
+ function shortString(value) {
183
+ if (typeof value !== "string" || value.length > 1024) return void 0;
184
+ const cleaned = value.trim();
185
+ return cleaned.length > 0 ? cleaned : void 0;
186
+ }
187
+ function flag(value) {
188
+ if (value === true || value === "true" || value === "1") return true;
189
+ if (value === false || value === "false" || value === "0") return false;
190
+ return void 0;
191
+ }
192
+ function environment() {
193
+ try {
194
+ return typeof process === "undefined" ? {} : process.env;
195
+ } catch (e) {
196
+ return {};
197
+ }
198
+ }
199
+ var DEPLOYMENTS = [
200
+ ["VERCEL", "VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF"],
201
+ ["NETLIFY", "COMMIT_REF", "BRANCH"],
202
+ ["RAILWAY_ENVIRONMENT_NAME", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
203
+ ["RAILWAY_ENVIRONMENT", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
204
+ ["RENDER", "RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH"],
205
+ ["DYNO", "HEROKU_BUILD_COMMIT", ""],
206
+ ["DYNO", "HEROKU_SLUG_COMMIT", ""],
207
+ ["AWS_APP_ID", "AWS_COMMIT_ID", "AWS_BRANCH"],
208
+ ["WORKERS_CI", "WORKERS_CI_COMMIT_SHA", "WORKERS_CI_BRANCH"]
209
+ ];
210
+ var CI_SOURCES = [
211
+ ["GITHUB_ACTIONS", "GITHUB_SHA", "GITHUB_REF_NAME"],
212
+ ["GITLAB_CI", "CI_COMMIT_SHA", "CI_COMMIT_REF_NAME"],
213
+ ["CIRCLECI", "CIRCLE_SHA1", "CIRCLE_BRANCH"]
214
+ ];
215
+ function detectedSource(env, table, detectBranch) {
216
+ for (const row of table) {
217
+ const [marker, shaKey, branchKey] = row;
218
+ if (!marker || !shaKey || !shortString(env[marker]) || flag(env[marker]) === false) continue;
219
+ const commitSha = validAppCommitSha(env[shaKey]);
220
+ if (commitSha)
221
+ return {
222
+ commitSha,
223
+ ...detectBranch && branchKey ? { branch: shortString(env[branchKey]) } : {}
224
+ };
225
+ }
226
+ return {};
227
+ }
228
+ var AppGitContextImpl = class {
229
+ constructor(options, runtime = {}) {
230
+ this.defaults = {};
231
+ this.explicit = {};
232
+ this.explicitKeys = /* @__PURE__ */ new Set();
233
+ this.disposed = false;
234
+ this.operations = /* @__PURE__ */ new Map();
235
+ this.operationOverflow = false;
236
+ this.detectBranch = false;
237
+ this.disabled = false;
238
+ var _a, _b, _c, _d, _e, _f;
239
+ try {
240
+ if (options === false) {
241
+ this.disabled = true;
242
+ return;
243
+ }
244
+ const opts = options != null ? options : {};
245
+ const env = (_a = runtime.env) != null ? _a : environment();
246
+ const detectBranch = (_c = (_b = flag(opts.detectBranch)) != null ? _b : flag(env.RAINDROP_GIT_DETECT_BRANCH)) != null ? _c : false;
247
+ this.detectBranch = detectBranch;
248
+ const collectBranch = detectBranch || runtime.captureLegacyReplayBranch === true;
249
+ const autoDetect = runtime.allowDiscovery === false ? false : (_e = (_d = flag(opts.autoDetect)) != null ? _d : flag(env.RAINDROP_GIT_AUTO_DETECT)) != null ? _e : true;
250
+ const configuredSha = opts.commitSha;
251
+ const explicitSha = configuredSha === void 0 ? env.RAINDROP_COMMIT_SHA : configuredSha;
252
+ if (explicitSha === null) this.explicit[APP_COMMIT_SHA] = null;
253
+ else if (typeof explicitSha === "string" && validAppCommitSha(explicitSha))
254
+ this.explicit[APP_COMMIT_SHA] = explicitSha;
255
+ const configuredDirty = opts.commitDirty;
256
+ const explicitDirty = configuredDirty === void 0 ? flag(env.RAINDROP_COMMIT_DIRTY) : configuredDirty;
257
+ if (explicitDirty === null || typeof explicitDirty === "boolean")
258
+ this.explicit[APP_COMMIT_DIRTY] = explicitDirty;
259
+ const configuredBranch = opts.branch;
260
+ const explicitBranch = configuredBranch === void 0 ? env.RAINDROP_BRANCH : configuredBranch;
261
+ if (explicitBranch === null) this.explicit[APP_BRANCH] = null;
262
+ else if (typeof explicitBranch === "string" && explicitBranch.length <= 1024)
263
+ this.explicit[APP_BRANCH] = explicitBranch;
264
+ this.explicitKeys = appGitExplicitKeys(this.explicit);
265
+ this.defaults = { ...this.explicit };
266
+ if (!autoDetect || explicitSha !== void 0) return;
267
+ const sourceDirectory = (_f = shortString(opts.sourceDirectory)) != null ? _f : shortString(env.RAINDROP_GIT_SOURCE_DIRECTORY);
268
+ if (runtime.allowLocalGit === false && !sourceDirectory) return;
269
+ const deploy = sourceDirectory ? {} : detectedSource(env, DEPLOYMENTS, collectBranch);
270
+ if (deploy.commitSha) {
271
+ this.accept(deploy);
272
+ return;
273
+ }
274
+ const fallback = sourceDirectory ? {} : detectedSource(env, CI_SOURCES, collectBranch);
275
+ if (runtime.resolveLocal && (runtime.allowLocalGit !== false || sourceDirectory)) {
276
+ this.cancel = runtime.resolveLocal(sourceDirectory, collectBranch, (result) => {
277
+ try {
278
+ if (!this.disposed) this.accept(result.commitSha ? result : fallback);
279
+ } catch (e) {
280
+ }
281
+ });
282
+ } else this.accept(fallback);
283
+ } catch (e) {
284
+ }
285
+ }
286
+ accept(result) {
287
+ const sha = validAppCommitSha(result.commitSha);
288
+ if (!sha) return;
289
+ this.replayBranch = shortString(result.branch);
290
+ this.defaults = {
291
+ [APP_COMMIT_SHA]: sha,
292
+ ...typeof result.commitDirty === "boolean" ? { [APP_COMMIT_DIRTY]: result.commitDirty } : {},
293
+ ...this.detectBranch && this.replayBranch ? { [APP_BRANCH]: this.replayBranch } : {},
294
+ ...this.explicit
295
+ };
296
+ }
297
+ snapshot(properties) {
298
+ var _a;
299
+ try {
300
+ const binding = currentRoutingBinding();
301
+ const base = this.disabled && (binding == null ? void 0 : binding.appGitSource) !== "replay-override" ? {} : (_a = binding == null ? void 0 : binding.appGit) != null ? _a : this.defaults;
302
+ return this.mergeSnapshot(base, properties);
303
+ } catch (e) {
304
+ return Object.freeze({});
305
+ }
306
+ }
307
+ /** Safe defaults when no operation/span start was observed; never infer identity. */
308
+ snapshotExplicit(properties, eventId) {
309
+ try {
310
+ const base = { ...this.explicit };
311
+ const operation = eventId ? this.operations.get(eventId) : void 0;
312
+ if (operation) {
313
+ for (const key of operation.explicitKeys) base[key] = operation.snapshot[key];
314
+ }
315
+ return this.mergeSnapshot(base, properties, new Set(Object.keys(base)));
316
+ } catch (e) {
317
+ return mergeAppGitSnapshot({}, properties);
318
+ }
319
+ }
320
+ /** Existing replay branch reporting stays separate from opt-in event properties. */
321
+ snapshotForReplay() {
322
+ const snapshot = this.snapshot();
323
+ if (this.replayBranch && !own(snapshot, APP_BRANCH) && snapshot[APP_COMMIT_SHA] === this.defaults[APP_COMMIT_SHA]) {
324
+ return Object.freeze({ ...snapshot, [APP_BRANCH]: this.replayBranch });
325
+ }
326
+ return snapshot;
327
+ }
328
+ /** Merge a frozen span snapshot without losing client-authored provenance. */
329
+ mergeSnapshot(base, properties, explicitKeys = this.explicitKeys) {
330
+ return mergeAppGitSnapshot(base, properties, /* @__PURE__ */ new Set([...this.explicitKeys, ...explicitKeys]));
331
+ }
332
+ /** Shippers belonging to one client share this bounded operation registry. */
333
+ forOperation(eventId, properties, owner) {
334
+ if (!eventId) return this.snapshot(properties);
335
+ let operation = this.operations.get(eventId);
336
+ if (!operation) {
337
+ if (this.operations.size >= 1e4) this.operationOverflow = true;
338
+ if (this.operationOverflow) return this.mergeSnapshot({}, properties);
339
+ operation = {
340
+ snapshot: this.snapshot(properties),
341
+ owners: /* @__PURE__ */ new Set(),
342
+ unowned: owner === void 0,
343
+ explicitKeys: appGitExplicitKeys(properties)
344
+ };
345
+ this.operations.set(eventId, operation);
346
+ } else if (properties && APP_GIT_KEYS.some((key) => own(properties, key))) {
347
+ const explicitKeys = /* @__PURE__ */ new Set([...this.explicitKeys, ...operation.explicitKeys]);
348
+ operation.snapshot = this.mergeSnapshot(operation.snapshot, properties, explicitKeys);
349
+ for (const key of appGitExplicitKeys(properties)) operation.explicitKeys.add(key);
350
+ }
351
+ if (!owner) operation.unowned = true;
352
+ if (owner) operation.owners.add(owner);
353
+ return operation.snapshot;
354
+ }
355
+ releaseOperation(eventId, owner) {
356
+ const operation = this.operations.get(eventId);
357
+ if (!operation) return;
358
+ operation.owners.delete(owner);
359
+ if (operation.owners.size === 0 && !operation.unowned) this.operations.delete(eventId);
360
+ }
361
+ finishOperation(eventId) {
362
+ this.operations.delete(eventId);
363
+ }
364
+ dispose() {
365
+ var _a;
366
+ this.disposed = true;
367
+ try {
368
+ (_a = this.cancel) == null ? void 0 : _a.call(this);
369
+ } catch (e) {
370
+ }
371
+ }
372
+ };
373
+ var AppGitContext = AppGitContextImpl;
374
+ function withAppGitAttributes(attributes, snapshot) {
375
+ try {
376
+ const present = new Set(attributes.flatMap((attr) => attr ? [attr.key] : []));
377
+ const added = [];
378
+ for (const key of APP_GIT_KEYS) {
379
+ if (present.has(key) || present.has(`ai.telemetry.metadata.${key}`) || present.has(`traceloop.association.properties.${key}`))
380
+ continue;
381
+ const value = snapshot[key];
382
+ if (typeof value === "string") added.push({ key, value: { stringValue: value } });
383
+ else if (typeof value === "boolean") added.push({ key, value: { boolValue: value } });
384
+ }
385
+ return added.length ? [...attributes, ...added] : attributes;
386
+ } catch (e) {
387
+ return attributes;
388
+ }
389
+ }
390
+ function getCrypto() {
391
+ const c = globalThis.crypto;
392
+ return c;
393
+ }
394
+ function randomBytes(length) {
395
+ const cryptoObj = getCrypto();
396
+ const out = new Uint8Array(length);
397
+ if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
398
+ cryptoObj.getRandomValues(out);
399
+ return out;
400
+ }
401
+ for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
402
+ return out;
403
+ }
404
+ function randomUUID() {
405
+ const cryptoObj = getCrypto();
406
+ if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
407
+ return cryptoObj.randomUUID();
408
+ }
409
+ const b = randomBytes(16);
410
+ b[6] = b[6] & 15 | 64;
411
+ b[8] = b[8] & 63 | 128;
412
+ const hex = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
413
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
414
+ }
415
+ function runWithTracingSuppressed(fn) {
416
+ const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
417
+ if (typeof hook !== "function") return fn();
418
+ let started = false;
419
+ try {
420
+ return hook(() => {
421
+ started = true;
422
+ return fn();
423
+ });
424
+ } catch (err) {
425
+ if (started) throw err;
426
+ return fn();
427
+ }
428
+ }
429
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
430
+ var MAX_RETRY_DELAY_MS = 3e4;
431
+ function wait(ms) {
432
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
433
+ }
434
+ function formatEndpoint(endpoint) {
435
+ if (!endpoint) return void 0;
436
+ return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
437
+ }
438
+ function redactUrlForLog(url) {
439
+ try {
440
+ const parsed = new URL(url);
441
+ parsed.username = "";
442
+ parsed.password = "";
443
+ parsed.search = "";
444
+ parsed.hash = "";
445
+ return parsed.toString();
446
+ } catch (e) {
447
+ return "<unparseable-url>";
448
+ }
449
+ }
450
+ function parseRetryAfter(headers) {
451
+ var _a;
452
+ const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
453
+ if (!value) return void 0;
454
+ const asNumber = Number(value);
455
+ if (value.trim() !== "" && !Number.isNaN(asNumber)) return asNumber * 1e3;
456
+ const asDate = new Date(value).getTime();
457
+ if (!Number.isNaN(asDate)) {
458
+ const delta = asDate - Date.now();
459
+ return delta > 0 ? delta : 0;
460
+ }
461
+ return void 0;
462
+ }
463
+ function getRetryDelayMs(attemptNumber, previousError) {
464
+ if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
465
+ const v = previousError.retryAfterMs;
466
+ if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
467
+ }
468
+ if (attemptNumber <= 1) return 0;
469
+ const base = 500;
470
+ const factor = Math.pow(2, attemptNumber - 2);
471
+ return Math.min(base * factor, MAX_RETRY_DELAY_MS);
472
+ }
473
+ async function withRetry(operation, opName, opts) {
474
+ const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
475
+ let lastError = void 0;
476
+ for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
477
+ if (attemptNumber > 1) {
478
+ const delay = getRetryDelayMs(attemptNumber, lastError);
479
+ if (opts.debug) {
480
+ console.warn(
481
+ `${prefix} ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
482
+ );
483
+ }
484
+ if (delay > 0) await wait(delay);
485
+ } else if (opts.debug) {
486
+ console.log(`${prefix} ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
487
+ }
488
+ try {
489
+ return await operation();
490
+ } catch (err) {
491
+ lastError = err;
492
+ if (opts.debug) {
493
+ const msg = err instanceof Error ? err.message : String(err);
494
+ console.warn(
495
+ `${prefix} ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
496
+ );
497
+ }
498
+ if (lastError && typeof lastError === "object" && "retryable" in lastError && !lastError.retryable)
499
+ break;
500
+ if (attemptNumber === opts.maxAttempts) break;
501
+ }
502
+ }
503
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
504
+ }
505
+ async function postJson(url, body, headers, opts) {
506
+ var _a;
507
+ const opName = `POST ${redactUrlForLog(url)}`;
508
+ const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
509
+ await withRetry(
510
+ async () => {
511
+ const resp = await runWithTracingSuppressed(
512
+ () => fetch(url, {
513
+ method: "POST",
514
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
515
+ headers: {
516
+ "Content-Type": "application/json",
517
+ ...headers
518
+ },
519
+ body: JSON.stringify(body),
520
+ signal: AbortSignal.timeout(timeoutMs)
521
+ })
522
+ );
523
+ if (!resp.ok) {
524
+ const text = await resp.text().catch(() => "");
525
+ const err = new Error(
526
+ `HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
527
+ );
528
+ const retryAfterMs = parseRetryAfter(resp.headers);
529
+ if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
530
+ err.retryable = resp.status === 429 || resp.status >= 500;
531
+ throw err;
532
+ }
533
+ },
534
+ opName,
535
+ opts
536
+ );
537
+ }
538
+ var SpanStatusCode = {
539
+ UNSET: 0,
540
+ OK: 1,
541
+ ERROR: 2
542
+ };
543
+ function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", serviceVersion = "0.0.0") {
544
+ return {
545
+ resourceSpans: [
546
+ {
547
+ resource: {
548
+ attributes: [{ key: "service.name", value: { stringValue: serviceName } }]
549
+ },
550
+ scopeSpans: [
551
+ {
552
+ scope: { name: serviceName, version: serviceVersion },
553
+ spans
554
+ }
555
+ ]
556
+ }
557
+ ]
558
+ };
559
+ }
560
+ var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
561
+ var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
562
+ var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
563
+ function readEnvVar(name) {
564
+ var _a;
565
+ try {
566
+ const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
567
+ if (env && typeof env[name] === "string" && env[name].length > 0) {
568
+ return env[name];
569
+ }
570
+ } catch (e) {
571
+ }
572
+ return void 0;
573
+ }
574
+ function readWorkshopEnv() {
575
+ const raw = readEnvVar(WORKSHOP_ENV_VAR);
576
+ if (raw === void 0) return void 0;
577
+ const trimmed = raw.trim();
578
+ if (trimmed.length === 0) return void 0;
579
+ if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
580
+ if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
581
+ if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
582
+ return void 0;
583
+ }
584
+ function isLocalDevHost(hostname) {
585
+ if (!hostname) return false;
586
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
587
+ return true;
588
+ }
589
+ if (hostname.endsWith(".localhost")) return true;
590
+ return false;
591
+ }
592
+ function readRuntimeHostname() {
593
+ try {
594
+ const loc = globalThis == null ? void 0 : globalThis.location;
595
+ if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
596
+ return loc.hostname;
597
+ }
598
+ } catch (e) {
599
+ }
600
+ return void 0;
601
+ }
602
+ function shouldAutoEnableLocalWorkshop() {
603
+ if (isLocalDevHost(readRuntimeHostname())) return true;
604
+ if (readEnvVar("NODE_ENV") === "development") return true;
605
+ return false;
606
+ }
607
+ function resolveLocalDebuggerBaseUrl(baseUrl) {
608
+ var _a, _b, _c;
609
+ if (baseUrl === null) return null;
610
+ if (typeof baseUrl === "string" && baseUrl.length > 0) {
611
+ return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
612
+ }
613
+ const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
614
+ if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
615
+ const workshopEnv = readWorkshopEnv();
616
+ if (workshopEnv === "disable") return null;
617
+ if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
618
+ if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
619
+ if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
620
+ return null;
621
+ }
622
+ var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
623
+ function mirrorTraceExportToLocalDebugger(body, options = {}) {
624
+ var _a;
625
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
626
+ if (!baseUrl) return Promise.resolve();
627
+ return postJson(`${baseUrl}traces`, body, {}, {
628
+ maxAttempts: 1,
629
+ debug: (_a = options.debug) != null ? _a : false,
630
+ sdkName: options.sdkName,
631
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
632
+ }).catch(() => {
633
+ });
634
+ }
635
+ var PROJECT_ID_HEADER = "X-Raindrop-Project-Id";
636
+ var PROJECT_ID_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
637
+ function isValidProjectIdSlug(value) {
638
+ return PROJECT_ID_SLUG_PATTERN.test(value);
639
+ }
640
+ function normalizeProjectId(raw, opts) {
641
+ if (typeof raw !== "string") return void 0;
642
+ const trimmed = raw.trim();
643
+ if (!trimmed) return void 0;
644
+ if (!isValidProjectIdSlug(trimmed) && opts.debug) {
645
+ console.warn(
646
+ `${opts.prefix} projectId "${trimmed}" does not match slug ${PROJECT_ID_SLUG_PATTERN.source}; sending anyway \u2014 backend may reject with HTTP 400`
647
+ );
648
+ }
649
+ return trimmed;
650
+ }
651
+ function projectIdHeaders(projectId) {
652
+ return projectId ? { [PROJECT_ID_HEADER]: projectId } : {};
653
+ }
654
+ var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
655
+ "ai.request.providerOptions",
656
+ "ai.response.providerMetadata"
657
+ ];
658
+ new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
659
+ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
660
+ const cwd = sourceDirectory ? path.resolve(sourceDirectory) : process.cwd();
661
+ let cancelled = false;
662
+ let active;
663
+ let deadlineTimer;
664
+ const deadline = Date.now() + 1e3;
665
+ const run = (args, done) => {
666
+ if (cancelled) return;
667
+ const remaining = deadline - Date.now();
668
+ if (remaining <= 0) {
669
+ done(void 0);
670
+ return;
671
+ }
672
+ try {
673
+ active = child_process.execFile(
674
+ "git",
675
+ args,
676
+ {
677
+ cwd,
678
+ encoding: "utf8",
679
+ maxBuffer: 4096,
680
+ windowsHide: true,
681
+ env: {
682
+ ...process.env,
683
+ // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
684
+ GIT_DIR: void 0,
685
+ GIT_WORK_TREE: void 0,
686
+ GIT_COMMON_DIR: void 0,
687
+ GIT_NAMESPACE: void 0,
688
+ GIT_INDEX_FILE: void 0,
689
+ GIT_OBJECT_DIRECTORY: void 0,
690
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
691
+ GIT_CONFIG_PARAMETERS: void 0,
692
+ GIT_CONFIG_COUNT: "0",
693
+ GIT_TERMINAL_PROMPT: "0",
694
+ GIT_OPTIONAL_LOCKS: "0"
695
+ }
696
+ },
697
+ (error, stdout) => {
698
+ clearTimeout(deadlineTimer);
699
+ deadlineTimer = void 0;
700
+ active = void 0;
701
+ if (!cancelled) {
702
+ try {
703
+ done(error ? void 0 : stdout.trim());
704
+ } catch (e) {
705
+ }
706
+ }
707
+ }
708
+ );
709
+ active.unref();
710
+ if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
711
+ active.stdout.unref();
712
+ if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
713
+ active.stderr.unref();
714
+ deadlineTimer = setTimeout(() => {
715
+ try {
716
+ active == null ? void 0 : active.kill("SIGKILL");
717
+ } catch (e) {
718
+ }
719
+ }, remaining);
720
+ deadlineTimer.unref();
721
+ } catch (e) {
722
+ try {
723
+ done(void 0);
724
+ } catch (e2) {
725
+ }
726
+ }
727
+ };
728
+ const scheduled = setTimeout(() => {
729
+ try {
730
+ run(["rev-parse", "HEAD"], (rawSha) => {
731
+ const commitSha = validAppCommitSha(rawSha);
732
+ if (!commitSha) {
733
+ completed({});
734
+ return;
735
+ }
736
+ run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
737
+ const finish = (branch) => {
738
+ run(["rev-parse", "HEAD"], (finalSha) => {
739
+ const coherent = validAppCommitSha(finalSha) === commitSha;
740
+ completed({
741
+ commitSha,
742
+ ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
743
+ ...coherent && branch && branch !== "HEAD" ? { branch } : {}
744
+ });
745
+ });
746
+ };
747
+ if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
748
+ else finish();
749
+ });
750
+ });
751
+ } catch (e) {
752
+ completed({});
753
+ }
754
+ }, 0);
755
+ scheduled.unref();
756
+ return () => {
757
+ cancelled = true;
758
+ clearTimeout(scheduled);
759
+ clearTimeout(deadlineTimer);
760
+ try {
761
+ active == null ? void 0 : active.kill("SIGKILL");
762
+ } catch (e) {
763
+ }
764
+ };
765
+ };
766
+ function createAppGitContext(options, runtime = {}) {
767
+ return new AppGitContext(options, { ...runtime, resolveLocal });
768
+ }
769
+ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
770
+ var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
771
+ "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
772
+ );
773
+ function findOtelContextManager() {
774
+ var _a;
775
+ for (const sym of Object.getOwnPropertySymbols(globalThis)) {
776
+ if (!((_a = sym.description) == null ? void 0 : _a.startsWith("opentelemetry.js.api."))) continue;
777
+ const api = globalThis[sym];
778
+ const cm = api == null ? void 0 : api.context;
779
+ if (cm && typeof cm.with === "function" && typeof cm.active === "function") {
780
+ return cm;
781
+ }
782
+ }
783
+ return void 0;
784
+ }
785
+ function installTracingSuppressionHook() {
786
+ if (typeof globalThis.RAINDROP_SUPPRESS_TRACING === "function") return;
787
+ const hook = (fn) => {
788
+ const cm = findOtelContextManager();
789
+ if (!cm) return fn();
790
+ return cm.with(cm.active().setValue(SUPPRESS_TRACING_KEY, true), fn);
791
+ };
792
+ globalThis.RAINDROP_SUPPRESS_TRACING = hook;
793
+ }
794
+ installTracingSuppressionHook();
12
795
  function parseEveSessionParent(value) {
13
796
  if (typeof value !== "object" || value === null) return void 0;
14
797
  const p = value;
@@ -147,344 +930,74 @@ var EveTurnRegistry = class {
147
930
  }
148
931
  /**
149
932
  * Drop all entries. Called from the SpanProcessor's `shutdown` hook
150
- * during exporter teardown.
151
- */
152
- clear() {
153
- this.stacks.clear();
154
- }
155
- /**
156
- * Total number of in-flight entries across all traces. For tests +
157
- * diagnostic logging.
158
- */
159
- get size() {
160
- let total = 0;
161
- for (const stack of this.stacks.values()) total += stack.length;
162
- return total;
163
- }
164
- };
165
- var registry = new EveTurnRegistry();
166
- function createEveTurnSpanProcessor() {
167
- return {
168
- onStart(span) {
169
- if (span.name !== EVE_TURN_SPAN_NAME) return;
170
- const attrs = span.attributes;
171
- if (!attrs) return;
172
- const ctx = span.spanContext();
173
- const continuationToken = typeof attrs[EVE_CONTINUATION_TOKEN_ATTR] === "string" ? attrs[EVE_CONTINUATION_TOKEN_ATTR] : void 0;
174
- const sessionId = typeof attrs[EVE_SESSION_ID_ATTR] === "string" ? attrs[EVE_SESSION_ID_ATTR] : void 0;
175
- registry.record(ctx.traceId, ctx.spanId, {
176
- continuationToken,
177
- sessionId
178
- });
179
- },
180
- onEnd(span) {
181
- if (span.name !== EVE_TURN_SPAN_NAME) return;
182
- const ctx = span.spanContext();
183
- registry.releaseAfterTick(ctx.traceId, ctx.spanId);
184
- },
185
- forceFlush() {
186
- return Promise.resolve();
187
- },
188
- shutdown() {
189
- registry.clear();
190
- return Promise.resolve();
191
- }
192
- };
193
- }
194
- function lookupEveTurn(traceId) {
195
- return registry.lookup(traceId);
196
- }
197
- function installEveTurnSpanProcessor(traceApi) {
198
- if (installState.installed) return true;
199
- try {
200
- let provider = traceApi.getTracerProvider();
201
- const proxyProvider = provider;
202
- if (typeof proxyProvider.getDelegate === "function") {
203
- const delegate = proxyProvider.getDelegate();
204
- if (delegate) provider = delegate;
205
- }
206
- const tp = provider;
207
- if (typeof tp.addSpanProcessor !== "function") {
208
- return false;
209
- }
210
- tp.addSpanProcessor(createEveTurnSpanProcessor());
211
- installState.installed = true;
212
- return true;
213
- } catch {
214
- return false;
215
- }
216
- }
217
- var installState = { installed: false };
218
- function runWithTracingSuppressed(fn) {
219
- const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
220
- if (typeof hook !== "function") return fn();
221
- let started = false;
222
- try {
223
- return hook(() => {
224
- started = true;
225
- return fn();
226
- });
227
- } catch (err) {
228
- if (started) throw err;
229
- return fn();
230
- }
231
- }
232
- var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
233
- var MAX_RETRY_DELAY_MS = 3e4;
234
- function wait(ms) {
235
- return new Promise((resolve) => setTimeout(resolve, ms));
236
- }
237
- function formatEndpoint(endpoint) {
238
- if (!endpoint) return void 0;
239
- return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
240
- }
241
- function redactUrlForLog(url) {
242
- try {
243
- const parsed = new URL(url);
244
- parsed.username = "";
245
- parsed.password = "";
246
- parsed.search = "";
247
- parsed.hash = "";
248
- return parsed.toString();
249
- } catch (e) {
250
- return "<unparseable-url>";
251
- }
252
- }
253
- function parseRetryAfter(headers) {
254
- var _a;
255
- const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
256
- if (!value) return void 0;
257
- const asNumber = Number(value);
258
- if (value.trim() !== "" && !Number.isNaN(asNumber)) return asNumber * 1e3;
259
- const asDate = new Date(value).getTime();
260
- if (!Number.isNaN(asDate)) {
261
- const delta = asDate - Date.now();
262
- return delta > 0 ? delta : 0;
263
- }
264
- return void 0;
265
- }
266
- function getRetryDelayMs(attemptNumber, previousError) {
267
- if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
268
- const v = previousError.retryAfterMs;
269
- if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
270
- }
271
- if (attemptNumber <= 1) return 0;
272
- const base = 500;
273
- const factor = Math.pow(2, attemptNumber - 2);
274
- return Math.min(base * factor, MAX_RETRY_DELAY_MS);
275
- }
276
- async function withRetry(operation, opName, opts) {
277
- const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
278
- let lastError = void 0;
279
- for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
280
- if (attemptNumber > 1) {
281
- const delay = getRetryDelayMs(attemptNumber, lastError);
282
- if (opts.debug) {
283
- console.warn(
284
- `${prefix} ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
285
- );
286
- }
287
- if (delay > 0) await wait(delay);
288
- } else if (opts.debug) {
289
- console.log(`${prefix} ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
290
- }
291
- try {
292
- return await operation();
293
- } catch (err) {
294
- lastError = err;
295
- if (opts.debug) {
296
- const msg = err instanceof Error ? err.message : String(err);
297
- console.warn(
298
- `${prefix} ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
299
- );
300
- }
301
- if (lastError && typeof lastError === "object" && "retryable" in lastError && !lastError.retryable)
302
- break;
303
- if (attemptNumber === opts.maxAttempts) break;
304
- }
305
- }
306
- throw lastError instanceof Error ? lastError : new Error(String(lastError));
307
- }
308
- async function postJson(url, body, headers, opts) {
309
- var _a;
310
- const opName = `POST ${redactUrlForLog(url)}`;
311
- const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
312
- await withRetry(
313
- async () => {
314
- const resp = await runWithTracingSuppressed(
315
- () => fetch(url, {
316
- method: "POST",
317
- redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
318
- headers: {
319
- "Content-Type": "application/json",
320
- ...headers
321
- },
322
- body: JSON.stringify(body),
323
- signal: AbortSignal.timeout(timeoutMs)
324
- })
325
- );
326
- if (!resp.ok) {
327
- const text = await resp.text().catch(() => "");
328
- const err = new Error(
329
- `HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
330
- );
331
- const retryAfterMs = parseRetryAfter(resp.headers);
332
- if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
333
- err.retryable = resp.status === 429 || resp.status >= 500;
334
- throw err;
335
- }
336
- },
337
- opName,
338
- opts
339
- );
340
- }
341
- var SpanStatusCode = {
342
- UNSET: 0,
343
- OK: 1,
344
- ERROR: 2
933
+ * during exporter teardown.
934
+ */
935
+ clear() {
936
+ this.stacks.clear();
937
+ }
938
+ /**
939
+ * Total number of in-flight entries across all traces. For tests +
940
+ * diagnostic logging.
941
+ */
942
+ get size() {
943
+ let total = 0;
944
+ for (const stack of this.stacks.values()) total += stack.length;
945
+ return total;
946
+ }
345
947
  };
346
- function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", serviceVersion = "0.0.0") {
948
+ var registry = new EveTurnRegistry();
949
+ function createEveTurnSpanProcessor() {
347
950
  return {
348
- resourceSpans: [
349
- {
350
- resource: {
351
- attributes: [{ key: "service.name", value: { stringValue: serviceName } }]
352
- },
353
- scopeSpans: [
354
- {
355
- scope: { name: serviceName, version: serviceVersion },
356
- spans
357
- }
358
- ]
359
- }
360
- ]
361
- };
362
- }
363
- var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
364
- var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
365
- var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
366
- function readEnvVar(name) {
367
- var _a;
368
- try {
369
- const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
370
- if (env && typeof env[name] === "string" && env[name].length > 0) {
371
- return env[name];
951
+ onStart(span) {
952
+ if (span.name !== EVE_TURN_SPAN_NAME) return;
953
+ const attrs = span.attributes;
954
+ if (!attrs) return;
955
+ const ctx = span.spanContext();
956
+ const continuationToken = typeof attrs[EVE_CONTINUATION_TOKEN_ATTR] === "string" ? attrs[EVE_CONTINUATION_TOKEN_ATTR] : void 0;
957
+ const sessionId = typeof attrs[EVE_SESSION_ID_ATTR] === "string" ? attrs[EVE_SESSION_ID_ATTR] : void 0;
958
+ registry.record(ctx.traceId, ctx.spanId, {
959
+ continuationToken,
960
+ sessionId
961
+ });
962
+ },
963
+ onEnd(span) {
964
+ if (span.name !== EVE_TURN_SPAN_NAME) return;
965
+ const ctx = span.spanContext();
966
+ registry.releaseAfterTick(ctx.traceId, ctx.spanId);
967
+ },
968
+ forceFlush() {
969
+ return Promise.resolve();
970
+ },
971
+ shutdown() {
972
+ registry.clear();
973
+ return Promise.resolve();
372
974
  }
373
- } catch (e) {
374
- }
375
- return void 0;
376
- }
377
- function readWorkshopEnv() {
378
- const raw = readEnvVar(WORKSHOP_ENV_VAR);
379
- if (raw === void 0) return void 0;
380
- const trimmed = raw.trim();
381
- if (trimmed.length === 0) return void 0;
382
- if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
383
- if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
384
- if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
385
- return void 0;
975
+ };
386
976
  }
387
- function isLocalDevHost(hostname) {
388
- if (!hostname) return false;
389
- if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
390
- return true;
391
- }
392
- if (hostname.endsWith(".localhost")) return true;
393
- return false;
977
+ function lookupEveTurn(traceId) {
978
+ return registry.lookup(traceId);
394
979
  }
395
- function readRuntimeHostname() {
980
+ function installEveTurnSpanProcessor(traceApi) {
981
+ if (installState.installed) return true;
396
982
  try {
397
- const loc = globalThis == null ? void 0 : globalThis.location;
398
- if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
399
- return loc.hostname;
983
+ let provider = traceApi.getTracerProvider();
984
+ const proxyProvider = provider;
985
+ if (typeof proxyProvider.getDelegate === "function") {
986
+ const delegate = proxyProvider.getDelegate();
987
+ if (delegate) provider = delegate;
400
988
  }
401
- } catch (e) {
402
- }
403
- return void 0;
404
- }
405
- function shouldAutoEnableLocalWorkshop() {
406
- if (isLocalDevHost(readRuntimeHostname())) return true;
407
- if (readEnvVar("NODE_ENV") === "development") return true;
408
- return false;
409
- }
410
- function resolveLocalDebuggerBaseUrl(baseUrl) {
411
- var _a, _b, _c;
412
- if (baseUrl === null) return null;
413
- if (typeof baseUrl === "string" && baseUrl.length > 0) {
414
- return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
415
- }
416
- const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
417
- if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
418
- const workshopEnv = readWorkshopEnv();
419
- if (workshopEnv === "disable") return null;
420
- if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
421
- if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
422
- if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
423
- return null;
424
- }
425
- var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
426
- function mirrorTraceExportToLocalDebugger(body, options = {}) {
427
- var _a;
428
- const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
429
- if (!baseUrl) return Promise.resolve();
430
- return postJson(`${baseUrl}traces`, body, {}, {
431
- maxAttempts: 1,
432
- debug: (_a = options.debug) != null ? _a : false,
433
- sdkName: options.sdkName,
434
- timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
435
- }).catch(() => {
436
- });
437
- }
438
- var PROJECT_ID_HEADER = "X-Raindrop-Project-Id";
439
- var PROJECT_ID_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
440
- function isValidProjectIdSlug(value) {
441
- return PROJECT_ID_SLUG_PATTERN.test(value);
442
- }
443
- function normalizeProjectId(raw, opts) {
444
- if (typeof raw !== "string") return void 0;
445
- const trimmed = raw.trim();
446
- if (!trimmed) return void 0;
447
- if (!isValidProjectIdSlug(trimmed) && opts.debug) {
448
- console.warn(
449
- `${opts.prefix} projectId "${trimmed}" does not match slug ${PROJECT_ID_SLUG_PATTERN.source}; sending anyway \u2014 backend may reject with HTTP 400`
450
- );
451
- }
452
- return trimmed;
453
- }
454
- function projectIdHeaders(projectId) {
455
- return projectId ? { [PROJECT_ID_HEADER]: projectId } : {};
456
- }
457
- var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
458
- "ai.request.providerOptions",
459
- "ai.response.providerMetadata"
460
- ];
461
- new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
462
- globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
463
- var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
464
- "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
465
- );
466
- function findOtelContextManager() {
467
- var _a;
468
- for (const sym of Object.getOwnPropertySymbols(globalThis)) {
469
- if (!((_a = sym.description) == null ? void 0 : _a.startsWith("opentelemetry.js.api."))) continue;
470
- const api = globalThis[sym];
471
- const cm = api == null ? void 0 : api.context;
472
- if (cm && typeof cm.with === "function" && typeof cm.active === "function") {
473
- return cm;
989
+ const tp = provider;
990
+ if (typeof tp.addSpanProcessor !== "function") {
991
+ return false;
474
992
  }
993
+ tp.addSpanProcessor(createEveTurnSpanProcessor());
994
+ installState.installed = true;
995
+ return true;
996
+ } catch {
997
+ return false;
475
998
  }
476
- return void 0;
477
- }
478
- function installTracingSuppressionHook() {
479
- if (typeof globalThis.RAINDROP_SUPPRESS_TRACING === "function") return;
480
- const hook = (fn) => {
481
- const cm = findOtelContextManager();
482
- if (!cm) return fn();
483
- return cm.with(cm.active().setValue(SUPPRESS_TRACING_KEY, true), fn);
484
- };
485
- globalThis.RAINDROP_SUPPRESS_TRACING = hook;
486
999
  }
487
- installTracingSuppressionHook();
1000
+ var installState = { installed: false };
488
1001
 
489
1002
  // src/internal/limits.ts
490
1003
  var DEFAULT_MAX_TEXT_FIELD_CHARS2 = 1e6;
@@ -512,6 +1025,13 @@ function truncateText(value, limit) {
512
1025
  }
513
1026
 
514
1027
  // src/internal/exporter.ts
1028
+ var EVE_APP_GIT_OWNER_PREFIX = "eve-trace";
1029
+ var MAX_EVE_APP_GIT_ACTIVE_EVENTS = 1e4;
1030
+ var APP_GIT_KEYS2 = [
1031
+ "raindrop.app.commit_sha",
1032
+ "raindrop.app.commit_dirty",
1033
+ "raindrop.app.branch"
1034
+ ];
515
1035
  function hexToBase64(hex) {
516
1036
  if (!hex) return void 0;
517
1037
  if (hex.length === 0 || /^0+$/.test(hex)) return void 0;
@@ -564,6 +1084,45 @@ function attributesToKeyValues(attrs, maxChars) {
564
1084
  }
565
1085
  return out;
566
1086
  }
1087
+ function eventIdFromAttributes(attrs) {
1088
+ if (!attrs) return void 0;
1089
+ const value = attrs["raindrop.eventId"] ?? attrs["ai.telemetry.metadata.raindrop.eventId"] ?? attrs["traceloop.association.properties.event_id"];
1090
+ return typeof value === "string" ? value : void 0;
1091
+ }
1092
+ function appGitPropertiesFromReadableAttributes(attrs) {
1093
+ const properties = {};
1094
+ if (!attrs) return properties;
1095
+ for (const key of ["raindrop.app.commit_sha", "raindrop.app.commit_dirty", "raindrop.app.branch"]) {
1096
+ for (const attributeKey of [key, `ai.telemetry.metadata.${key}`, `traceloop.association.properties.${key}`]) {
1097
+ if (Object.prototype.hasOwnProperty.call(attrs, attributeKey)) {
1098
+ properties[key] = attrs[attributeKey];
1099
+ break;
1100
+ }
1101
+ }
1102
+ }
1103
+ return properties;
1104
+ }
1105
+ function appGitExplicitKeys2(properties) {
1106
+ const keys = /* @__PURE__ */ new Set();
1107
+ for (const key of APP_GIT_KEYS2) {
1108
+ if (Object.prototype.hasOwnProperty.call(properties, key)) keys.add(key);
1109
+ }
1110
+ return keys;
1111
+ }
1112
+ function appGitOwnerId(prefix) {
1113
+ try {
1114
+ return `${prefix}:${randomUUID()}`;
1115
+ } catch {
1116
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1117
+ }
1118
+ }
1119
+ function explicitAppGitSnapshot(context, properties, eventId) {
1120
+ try {
1121
+ return context.snapshotExplicit?.(properties, eventId) ?? properties;
1122
+ } catch {
1123
+ return properties;
1124
+ }
1125
+ }
567
1126
  function statusFromReadable(span) {
568
1127
  const code = span.status?.code;
569
1128
  if (code === void 0) return void 0;
@@ -575,7 +1134,7 @@ function statusFromReadable(span) {
575
1134
  }
576
1135
  return { code: SpanStatusCode.UNSET };
577
1136
  }
578
- function readableSpanToOtlp(span, maxChars) {
1137
+ function readableSpanToOtlp(span, maxChars, appGitContext, operationEventId, appGitOwner, appGitExplicitOnly, startedAppGitSnapshot, startedAppGitExplicitKeys) {
579
1138
  const ctx = span.spanContext();
580
1139
  const parentSpanIdHex = span.parentSpanContext?.spanId ?? span.parentSpanId;
581
1140
  const traceId = hexToBase64(ctx.traceId);
@@ -586,7 +1145,17 @@ function readableSpanToOtlp(span, maxChars) {
586
1145
  );
587
1146
  }
588
1147
  const parentSpanId = hexToBase64(parentSpanIdHex);
589
- const attrs = attributesToKeyValues(span.attributes, maxChars);
1148
+ eventIdFromAttributes(span.attributes);
1149
+ const appProperties = appGitPropertiesFromReadableAttributes(span.attributes);
1150
+ const appGitSnapshot = startedAppGitSnapshot !== void 0 ? appGitContext.mergeSnapshot ? appGitContext.mergeSnapshot(startedAppGitSnapshot, appProperties, startedAppGitExplicitKeys) : mergeAppGitSnapshot(startedAppGitSnapshot, appProperties, startedAppGitExplicitKeys) : appGitExplicitOnly ? explicitAppGitSnapshot(appGitContext, appProperties, operationEventId) : appGitContext.forOperation(
1151
+ operationEventId,
1152
+ appProperties,
1153
+ operationEventId ? appGitOwner : void 0
1154
+ );
1155
+ const attrs = withAppGitAttributes(
1156
+ attributesToKeyValues(span.attributes, maxChars),
1157
+ appGitSnapshot
1158
+ ).filter((attribute) => attribute !== void 0);
590
1159
  const otlp = {
591
1160
  traceId,
592
1161
  spanId,
@@ -601,7 +1170,10 @@ function readableSpanToOtlp(span, maxChars) {
601
1170
  return otlp;
602
1171
  }
603
1172
  var RaindropEveSpanExporter = class {
604
- constructor(opts = {}) {
1173
+ constructor(opts = {}, appGitContext) {
1174
+ this.startedAppGitSpans = /* @__PURE__ */ new WeakMap();
1175
+ this.activeAppGitEvents = /* @__PURE__ */ new Map();
1176
+ this.appGitOwner = appGitOwnerId(EVE_APP_GIT_OWNER_PREFIX);
605
1177
  this.inFlight = /* @__PURE__ */ new Set();
606
1178
  this.shuttingDown = false;
607
1179
  this.auxShutdowns = [];
@@ -619,6 +1191,10 @@ var RaindropEveSpanExporter = class {
619
1191
  });
620
1192
  const explicit = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
621
1193
  this.localDebuggerUrl = resolveLocalDebuggerBaseUrl(explicit) ?? void 0;
1194
+ this.appGitContext = appGitContext ?? createAppGitContext(
1195
+ this.writeKey || this.localDebuggerUrl ? opts.appGit : false,
1196
+ { allowLocalGit: false }
1197
+ );
622
1198
  if (this.debug) {
623
1199
  console.log(
624
1200
  `${this.prefix} Initialized`,
@@ -633,6 +1209,55 @@ var RaindropEveSpanExporter = class {
633
1209
  hasDestinations() {
634
1210
  return Boolean(this.writeKey || this.localDebuggerUrl);
635
1211
  }
1212
+ captureSpanStart(span) {
1213
+ if (this.startedAppGitSpans.has(span)) return;
1214
+ const eventId = eventIdFromAttributes(span.attributes);
1215
+ const appProperties = appGitPropertiesFromReadableAttributes(span.attributes);
1216
+ const snapshot = this.appGitContext.forOperation(
1217
+ eventId,
1218
+ appProperties,
1219
+ eventId ? this.appGitOwner : void 0
1220
+ );
1221
+ if (!eventId) {
1222
+ this.startedAppGitSpans.set(span, {
1223
+ eventId: void 0,
1224
+ snapshot,
1225
+ explicitKeys: appGitExplicitKeys2(appProperties)
1226
+ });
1227
+ return;
1228
+ }
1229
+ const tracksAppGit = this.activeAppGitEvents.has(eventId) || this.activeAppGitEvents.size < MAX_EVE_APP_GIT_ACTIVE_EVENTS;
1230
+ if (tracksAppGit) {
1231
+ this.activeAppGitEvents.set(eventId, (this.activeAppGitEvents.get(eventId) ?? 0) + 1);
1232
+ this.startedAppGitSpans.set(span, {
1233
+ eventId,
1234
+ snapshot,
1235
+ explicitKeys: appGitExplicitKeys2(appProperties)
1236
+ });
1237
+ } else {
1238
+ this.appGitContext.releaseOperation?.(eventId, this.appGitOwner);
1239
+ }
1240
+ }
1241
+ releaseStartedAppGitSpan(span, eventId) {
1242
+ const started = this.startedAppGitSpans.get(span);
1243
+ const startedEventId = started?.eventId;
1244
+ this.startedAppGitSpans.delete(span);
1245
+ const trackedEventId = startedEventId ?? eventId;
1246
+ if (!trackedEventId || !this.appGitContext.releaseOperation) return;
1247
+ if (!startedEventId) {
1248
+ if (!this.activeAppGitEvents.has(trackedEventId)) {
1249
+ this.appGitContext.releaseOperation(trackedEventId, this.appGitOwner);
1250
+ }
1251
+ return;
1252
+ }
1253
+ const remaining = (this.activeAppGitEvents.get(startedEventId) ?? 1) - 1;
1254
+ if (remaining > 0) {
1255
+ this.activeAppGitEvents.set(startedEventId, remaining);
1256
+ return;
1257
+ }
1258
+ this.activeAppGitEvents.delete(startedEventId);
1259
+ this.appGitContext.releaseOperation(startedEventId, this.appGitOwner);
1260
+ }
636
1261
  /**
637
1262
  * Update the OTLP `service.name` attribute. Called by Eve's
638
1263
  * `setup({ agentName })` so the resource attribute reflects the actual
@@ -657,12 +1282,28 @@ var RaindropEveSpanExporter = class {
657
1282
  const maxChars = effectiveAttributeLimit(this.maxTextFieldChars);
658
1283
  const otlpSpans = [];
659
1284
  for (const span of spans) {
1285
+ const eventId = eventIdFromAttributes(span.attributes);
1286
+ const startedAppGit = this.startedAppGitSpans.get(span);
1287
+ const appGitExplicitOnly = startedAppGit === void 0;
660
1288
  try {
661
- otlpSpans.push(readableSpanToOtlp(span, maxChars));
1289
+ otlpSpans.push(
1290
+ readableSpanToOtlp(
1291
+ span,
1292
+ maxChars,
1293
+ this.appGitContext,
1294
+ startedAppGit?.eventId ?? eventId,
1295
+ this.appGitOwner,
1296
+ appGitExplicitOnly,
1297
+ startedAppGit?.eventId ? void 0 : startedAppGit?.snapshot,
1298
+ startedAppGit?.eventId ? void 0 : startedAppGit?.explicitKeys
1299
+ )
1300
+ );
662
1301
  } catch (err) {
663
1302
  if (this.debug) {
664
1303
  console.warn(`${this.prefix} failed to convert span`, err);
665
1304
  }
1305
+ } finally {
1306
+ this.releaseStartedAppGitSpan(span, eventId);
666
1307
  }
667
1308
  }
668
1309
  if (otlpSpans.length === 0) {
@@ -714,11 +1355,18 @@ var RaindropEveSpanExporter = class {
714
1355
  }
715
1356
  async shutdown() {
716
1357
  this.shuttingDown = true;
717
- await this.forceFlush();
718
- await Promise.all(
719
- this.auxShutdowns.map((fn) => fn().catch(() => {
720
- }))
721
- );
1358
+ try {
1359
+ await this.forceFlush();
1360
+ await Promise.all(
1361
+ this.auxShutdowns.map((fn) => fn().catch(() => {
1362
+ }))
1363
+ );
1364
+ } finally {
1365
+ try {
1366
+ this.appGitContext.dispose();
1367
+ } catch {
1368
+ }
1369
+ }
722
1370
  }
723
1371
  /**
724
1372
  * Register an extra teardown hook to run during {@link shutdown}. Used to
@@ -731,11 +1379,44 @@ var RaindropEveSpanExporter = class {
731
1379
  this.auxShutdowns.push(fn);
732
1380
  }
733
1381
  };
1382
+ function installEveAppGitSpanProcessor(traceApi, exporter) {
1383
+ try {
1384
+ let provider = traceApi.getTracerProvider();
1385
+ if (provider === null || typeof provider !== "object" && typeof provider !== "function") return false;
1386
+ if ("getDelegate" in provider && typeof provider.getDelegate === "function") {
1387
+ const delegate = provider.getDelegate();
1388
+ if (delegate) provider = delegate;
1389
+ }
1390
+ if (provider === null || typeof provider !== "object" && typeof provider !== "function" || !("addSpanProcessor" in provider) || typeof provider.addSpanProcessor !== "function") return false;
1391
+ provider.addSpanProcessor(createEveAppGitSpanProcessor(exporter));
1392
+ return true;
1393
+ } catch {
1394
+ return false;
1395
+ }
1396
+ }
1397
+ function createEveAppGitSpanProcessor(exporter) {
1398
+ return {
1399
+ onStart(span) {
1400
+ try {
1401
+ exporter.captureSpanStart(span);
1402
+ } catch {
1403
+ }
1404
+ },
1405
+ onEnd() {
1406
+ },
1407
+ forceFlush() {
1408
+ return Promise.resolve();
1409
+ },
1410
+ shutdown() {
1411
+ return Promise.resolve();
1412
+ }
1413
+ };
1414
+ }
734
1415
 
735
1416
  // package.json
736
1417
  var package_default = {
737
1418
  name: "@raindrop-ai/eve",
738
- version: "0.0.23"};
1419
+ version: "0.0.24"};
739
1420
 
740
1421
  // src/internal/version.ts
741
1422
  var libraryName = package_default.name;
@@ -1017,18 +1698,21 @@ function buildEveStepStartedResolver(opts, staticMetadata) {
1017
1698
  };
1018
1699
  }
1019
1700
  function buildEveMetadataConfig(opts, staticMetadata) {
1020
- const resolve = buildEveStepStartedResolver(opts, staticMetadata);
1021
- return { "step.started": (input) => resolve(input) };
1701
+ const resolve2 = buildEveStepStartedResolver(opts, staticMetadata);
1702
+ return { "step.started": (input) => resolve2(input) };
1022
1703
  }
1023
1704
  function buildEveEventsConfig(opts, staticMetadata) {
1024
- const resolve = buildEveStepStartedResolver(opts, staticMetadata);
1025
- return { "step.started": (input) => ({ runtimeContext: resolve(input) }) };
1705
+ const resolve2 = buildEveStepStartedResolver(opts, staticMetadata);
1706
+ return { "step.started": (input) => ({ runtimeContext: resolve2(input) }) };
1026
1707
  }
1027
1708
  function defineRaindropInstrumentation(opts = {}) {
1028
1709
  const debug = opts.debug === true || envDebug();
1029
1710
  const writeKey = opts.writeKey ?? envWriteKey();
1030
1711
  const endpoint = opts.endpoint ?? envEndpoint();
1031
1712
  const projectId = opts.projectId ?? envProjectId();
1713
+ const localWorkshopInput = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
1714
+ const hasDestination = Boolean(writeKey?.trim()) || Boolean(resolveLocalDebuggerBaseUrl(localWorkshopInput));
1715
+ const appGitContext = createAppGitContext(hasDestination ? opts.appGit : false, { allowLocalGit: false });
1032
1716
  const exporter = new RaindropEveSpanExporter({
1033
1717
  writeKey,
1034
1718
  endpoint,
@@ -1039,7 +1723,7 @@ function defineRaindropInstrumentation(opts = {}) {
1039
1723
  sdkName: "eve",
1040
1724
  debug,
1041
1725
  maxTextFieldChars: opts.maxTextFieldChars
1042
- });
1726
+ }, appGitContext);
1043
1727
  const localWorkshopUrl = opts.localWorkshopUrl === false ? false : opts.localWorkshopUrl;
1044
1728
  const raindrop = aiSdk.createRaindropAISDK({
1045
1729
  writeKey,
@@ -1047,7 +1731,8 @@ function defineRaindropInstrumentation(opts = {}) {
1047
1731
  projectId,
1048
1732
  localWorkshopUrl,
1049
1733
  events: { debug },
1050
- traces: { debug }
1734
+ traces: { debug },
1735
+ appGitContext
1051
1736
  });
1052
1737
  exporter.attachAuxShutdown(() => raindrop.shutdown());
1053
1738
  const prefix = "[raindrop-ai/eve]";
@@ -1076,8 +1761,13 @@ function defineRaindropInstrumentation(opts = {}) {
1076
1761
  if (already === void 0) {
1077
1762
  opts.registerOTel({
1078
1763
  serviceName,
1079
- traceExporter: exporter
1764
+ traceExporter: exporter,
1765
+ spanProcessors: [
1766
+ "auto",
1767
+ createEveAppGitSpanProcessor(exporter)
1768
+ ]
1080
1769
  });
1770
+ installEveAppGitSpanProcessor(api.trace, exporter);
1081
1771
  g[RAINDROP_EVE_OTEL_REGISTERED] = { exporter };
1082
1772
  if (debug) {
1083
1773
  console.log(`${prefix} registered OTel for serviceName=${serviceName}`);
@@ -1125,6 +1815,7 @@ exports.RAINDROP_EVE_SDK_NAME = RAINDROP_EVE_SDK_NAME;
1125
1815
  exports.RAINDROP_EVE_SDK_VERSION = RAINDROP_EVE_SDK_VERSION;
1126
1816
  exports.RaindropEveSpanExporter = RaindropEveSpanExporter;
1127
1817
  exports._resetCanonicalTurnIds = _resetCanonicalTurnIds;
1818
+ exports.createEveAppGitSpanProcessor = createEveAppGitSpanProcessor;
1128
1819
  exports.default = index_default;
1129
1820
  exports.defineRaindropInstrumentation = defineRaindropInstrumentation;
1130
1821
  //# sourceMappingURL=index.js.map