@langfuse/otel 4.0.0-beta.4 → 4.0.0-beta.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -20,219 +20,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- LangfuseMedia: () => LangfuseMedia,
24
23
  LangfuseSpanProcessor: () => LangfuseSpanProcessor
25
24
  });
26
25
  module.exports = __toCommonJS(index_exports);
27
26
 
28
27
  // src/span-processor.ts
29
- var import_core3 = require("@langfuse/core");
30
- var import_core4 = require("@opentelemetry/core");
28
+ var import_core = require("@langfuse/core");
29
+ var import_core2 = require("@opentelemetry/core");
31
30
  var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
32
31
  var import_sdk_trace_base = require("@opentelemetry/sdk-trace-base");
33
-
34
- // src/hash.ts
35
- var import_core = require("@langfuse/core");
36
- var cryptoModule;
37
- var isCryptoAvailable = false;
38
- var _a;
39
- try {
40
- if (typeof globalThis.Deno !== "undefined") {
41
- cryptoModule = require("crypto");
42
- isCryptoAvailable = true;
43
- } else if (typeof process !== "undefined" && ((_a = process.versions) == null ? void 0 : _a.node)) {
44
- cryptoModule = require("crypto");
45
- isCryptoAvailable = true;
46
- } else if (typeof crypto !== "undefined") {
47
- cryptoModule = crypto;
48
- isCryptoAvailable = true;
49
- }
50
- } catch (error) {
51
- (0, import_core.getGlobalLogger)().warn(
52
- "Crypto module not available. Media handling will be disabled.",
53
- error
54
- );
55
- isCryptoAvailable = false;
56
- }
57
- function sha256(data) {
58
- if (!isCryptoAvailable || !cryptoModule) {
59
- throw new Error("Crypto module not available");
60
- }
61
- return cryptoModule.createHash("sha256").update(data).digest();
62
- }
63
- function getSha256HashFromBytes(data) {
64
- if (!isCryptoAvailable) {
65
- throw new Error("Crypto module not available");
66
- }
67
- const hash = sha256(data);
68
- return (0, import_core.uint8ArrayToBase64)(hash);
69
- }
70
-
71
- // src/media.ts
72
- var import_core2 = require("@langfuse/core");
73
- var LangfuseMedia = class {
74
- /**
75
- * Creates a new LangfuseMedia instance.
76
- *
77
- * @param params - Media parameters specifying the source and content
78
- *
79
- * @example
80
- * ```typescript
81
- * // Create from base64 data URI
82
- * const media = new LangfuseMedia({
83
- * source: "base64_data_uri",
84
- * base64DataUri: "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQ..."
85
- * });
86
- * ```
87
- */
88
- constructor(params) {
89
- const { source } = params;
90
- this._source = source;
91
- if (source === "base64_data_uri") {
92
- const [contentBytesParsed, contentTypeParsed] = this.parseBase64DataUri(
93
- params.base64DataUri
94
- );
95
- this._contentBytes = contentBytesParsed;
96
- this._contentType = contentTypeParsed;
97
- } else {
98
- this._contentBytes = params.contentBytes;
99
- this._contentType = params.contentType;
100
- }
101
- }
102
- /**
103
- * Parses a base64 data URI to extract content bytes and type.
104
- *
105
- * @param data - The base64 data URI string
106
- * @returns Tuple of [contentBytes, contentType] or [undefined, undefined] on error
107
- * @private
108
- */
109
- parseBase64DataUri(data) {
110
- try {
111
- if (!data || typeof data !== "string") {
112
- throw new Error("Data URI is not a string");
113
- }
114
- if (!data.startsWith("data:")) {
115
- throw new Error("Data URI does not start with 'data:'");
116
- }
117
- const [header, actualData] = data.slice(5).split(",", 2);
118
- if (!header || !actualData) {
119
- throw new Error("Invalid URI");
120
- }
121
- const headerParts = header.split(";");
122
- if (!headerParts.includes("base64")) {
123
- throw new Error("Data is not base64 encoded");
124
- }
125
- const contentType = headerParts[0];
126
- if (!contentType) {
127
- throw new Error("Content type is empty");
128
- }
129
- return [
130
- Buffer.from(actualData, "base64"),
131
- contentType
132
- ];
133
- } catch (error) {
134
- (0, import_core2.getGlobalLogger)().error("Error parsing base64 data URI", error);
135
- return [void 0, void 0];
136
- }
137
- }
138
- /**
139
- * Gets a unique identifier for this media based on its content hash.
140
- *
141
- * The ID is derived from the first 22 characters of the URL-safe base64-encoded
142
- * SHA-256 hash of the content.
143
- *
144
- * @returns The unique media ID, or null if hash generation failed
145
- *
146
- * @example
147
- * ```typescript
148
- * const media = new LangfuseMedia({...});
149
- * console.log(media.id); // "A1B2C3D4E5F6G7H8I9J0K1"
150
- * ```
151
- */
152
- get id() {
153
- if (!this.contentSha256Hash) return null;
154
- const urlSafeContentHash = this.contentSha256Hash.replaceAll("+", "-").replaceAll("/", "_");
155
- return urlSafeContentHash.slice(0, 22);
156
- }
157
- /**
158
- * Gets the length of the media content in bytes.
159
- *
160
- * @returns The content length in bytes, or undefined if no content is available
161
- */
162
- get contentLength() {
163
- var _a2;
164
- return (_a2 = this._contentBytes) == null ? void 0 : _a2.length;
165
- }
166
- /**
167
- * Gets the SHA-256 hash of the media content.
168
- *
169
- * The hash is used for content integrity verification and generating unique media IDs.
170
- * Returns undefined if crypto is not available or hash generation fails.
171
- *
172
- * @returns The base64-encoded SHA-256 hash, or undefined if unavailable
173
- */
174
- get contentSha256Hash() {
175
- if (!this._contentBytes || !isCryptoAvailable) {
176
- return void 0;
177
- }
178
- try {
179
- return getSha256HashFromBytes(this._contentBytes);
180
- } catch (error) {
181
- (0, import_core2.getGlobalLogger)().warn(
182
- "[Langfuse] Failed to generate SHA-256 hash for media content:",
183
- error
184
- );
185
- return void 0;
186
- }
187
- }
188
- /**
189
- * Gets the media reference tag for embedding in trace data.
190
- *
191
- * The tag format is: `@@@langfuseMedia:type=<contentType>|id=<mediaId>|source=<source>@@@`
192
- * This tag can be embedded in trace attributes and will be replaced with actual
193
- * media content when the trace is viewed in Langfuse.
194
- *
195
- * @returns The media reference tag, or null if required data is missing
196
- *
197
- * @example
198
- * ```typescript
199
- * const media = new LangfuseMedia({...});
200
- * console.log(media.tag);
201
- * // "@@@langfuseMedia:type=image/png|id=A1B2C3D4E5F6G7H8I9J0K1|source=base64_data_uri@@@"
202
- * ```
203
- */
204
- get tag() {
205
- if (!this._contentType || !this._source || !this.id) return null;
206
- return `@@@langfuseMedia:type=${this._contentType}|id=${this.id}|source=${this._source}@@@`;
207
- }
208
- /**
209
- * Gets the media content as a base64 data URI.
210
- *
211
- * @returns The complete data URI string, or null if no content is available
212
- *
213
- * @example
214
- * ```typescript
215
- * const media = new LangfuseMedia({...});
216
- * console.log(media.base64DataUri);
217
- * // "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAAB..."
218
- * ```
219
- */
220
- get base64DataUri() {
221
- if (!this._contentBytes) return null;
222
- return `data:${this._contentType};base64,${Buffer.from(this._contentBytes).toString("base64")}`;
223
- }
224
- /**
225
- * Serializes the media to JSON (returns the base64 data URI).
226
- *
227
- * @returns The base64 data URI, or null if no content is available
228
- */
229
- toJSON() {
230
- return this.base64DataUri;
231
- }
232
- };
233
-
234
- // src/span-processor.ts
235
- var LangfuseSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcessor {
32
+ var LangfuseSpanProcessor = class {
236
33
  /**
237
34
  * Creates a new LangfuseSpanProcessor instance.
238
35
  *
@@ -260,11 +57,13 @@ var LangfuseSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcess
260
57
  * ```
261
58
  */
262
59
  constructor(params) {
263
- var _a2, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
264
- const logger = (0, import_core3.getGlobalLogger)();
265
- const publicKey = (_a2 = params == null ? void 0 : params.publicKey) != null ? _a2 : (0, import_core3.getEnv)("LANGFUSE_PUBLIC_KEY");
266
- const secretKey = (_b = params == null ? void 0 : params.secretKey) != null ? _b : (0, import_core3.getEnv)("LANGFUSE_SECRET_KEY");
267
- const baseUrl = (_e = (_d = (_c = params == null ? void 0 : params.baseUrl) != null ? _c : (0, import_core3.getEnv)("LANGFUSE_BASE_URL")) != null ? _d : (0, import_core3.getEnv)("LANGFUSE_BASEURL")) != null ? _e : (
60
+ this.pendingMediaUploads = /* @__PURE__ */ new Set();
61
+ this.pendingEndedSpans = /* @__PURE__ */ new Set();
62
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
63
+ const logger = (0, import_core.getGlobalLogger)();
64
+ const publicKey = (_a = params == null ? void 0 : params.publicKey) != null ? _a : (0, import_core.getEnv)("LANGFUSE_PUBLIC_KEY");
65
+ const secretKey = (_b = params == null ? void 0 : params.secretKey) != null ? _b : (0, import_core.getEnv)("LANGFUSE_SECRET_KEY");
66
+ const baseUrl = (_e = (_d = (_c = params == null ? void 0 : params.baseUrl) != null ? _c : (0, import_core.getEnv)("LANGFUSE_BASE_URL")) != null ? _d : (0, import_core.getEnv)("LANGFUSE_BASEURL")) != null ? _e : (
268
67
  // legacy v2
269
68
  "https://cloud.langfuse.com"
270
69
  );
@@ -278,40 +77,37 @@ var LangfuseSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcess
278
77
  "No exporter configured and no secret key provided in constructor or as LANGFUSE_SECRET_KEY env var. Span exports will fail."
279
78
  );
280
79
  }
281
- const flushAt = (_f = params == null ? void 0 : params.flushAt) != null ? _f : (0, import_core3.getEnv)("LANGFUSE_FLUSH_AT");
282
- const flushIntervalSeconds = (_g = params == null ? void 0 : params.flushInterval) != null ? _g : (0, import_core3.getEnv)("LANGFUSE_FLUSH_INTERVAL");
283
- const authHeaderValue = (0, import_core3.uint8ArrayToBase64)(
284
- new TextEncoder().encode(`${publicKey}:${secretKey}`)
285
- );
286
- const timeoutSeconds = (_i = params == null ? void 0 : params.timeout) != null ? _i : Number((_h = (0, import_core3.getEnv)("LANGFUSE_TIMEOUT")) != null ? _h : 5);
80
+ const flushAt = (_f = params == null ? void 0 : params.flushAt) != null ? _f : (0, import_core.getEnv)("LANGFUSE_FLUSH_AT");
81
+ const flushIntervalSeconds = (_g = params == null ? void 0 : params.flushInterval) != null ? _g : (0, import_core.getEnv)("LANGFUSE_FLUSH_INTERVAL");
82
+ const authHeaderValue = (0, import_core.base64Encode)(`${publicKey}:${secretKey}`);
83
+ const timeoutSeconds = (_i = params == null ? void 0 : params.timeout) != null ? _i : Number((_h = (0, import_core.getEnv)("LANGFUSE_TIMEOUT")) != null ? _h : 5);
287
84
  const exporter = (_j = params == null ? void 0 : params.exporter) != null ? _j : new import_exporter_trace_otlp_http.OTLPTraceExporter({
288
85
  url: `${baseUrl}/api/public/otel/v1/traces`,
289
86
  headers: {
290
87
  Authorization: `Basic ${authHeaderValue}`,
291
88
  x_langfuse_sdk_name: "javascript",
292
- x_langfuse_sdk_version: import_core3.LANGFUSE_SDK_VERSION,
89
+ x_langfuse_sdk_version: import_core.LANGFUSE_SDK_VERSION,
293
90
  x_langfuse_public_key: publicKey != null ? publicKey : "<missing>",
294
91
  ...params == null ? void 0 : params.additionalHeaders
295
92
  },
296
93
  timeoutMillis: timeoutSeconds * 1e3
297
94
  });
298
- super(exporter, {
95
+ this.processor = (params == null ? void 0 : params.exportMode) === "immediate" ? new import_sdk_trace_base.SimpleSpanProcessor(exporter) : new import_sdk_trace_base.BatchSpanProcessor(exporter, {
299
96
  maxExportBatchSize: flushAt ? Number(flushAt) : void 0,
300
97
  scheduledDelayMillis: flushIntervalSeconds ? Number(flushIntervalSeconds) * 1e3 : void 0
301
98
  });
302
- this.pendingMediaUploads = {};
303
99
  this.publicKey = publicKey;
304
100
  this.baseUrl = baseUrl;
305
- this.environment = (_k = params == null ? void 0 : params.environment) != null ? _k : (0, import_core3.getEnv)("LANGFUSE_TRACING_ENVIRONMENT");
306
- this.release = (_l = params == null ? void 0 : params.release) != null ? _l : (0, import_core3.getEnv)("LANGFUSE_RELEASE");
101
+ this.environment = (_k = params == null ? void 0 : params.environment) != null ? _k : (0, import_core.getEnv)("LANGFUSE_TRACING_ENVIRONMENT");
102
+ this.release = (_l = params == null ? void 0 : params.release) != null ? _l : (0, import_core.getEnv)("LANGFUSE_RELEASE");
307
103
  this.mask = params == null ? void 0 : params.mask;
308
104
  this.shouldExportSpan = params == null ? void 0 : params.shouldExportSpan;
309
- this.apiClient = new import_core3.LangfuseAPIClient({
105
+ this.apiClient = new import_core.LangfuseAPIClient({
310
106
  baseUrl: this.baseUrl,
311
107
  username: this.publicKey,
312
108
  password: secretKey,
313
109
  xLangfusePublicKey: this.publicKey,
314
- xLangfuseSdkVersion: import_core3.LANGFUSE_SDK_VERSION,
110
+ xLangfuseSdkVersion: import_core.LANGFUSE_SDK_VERSION,
315
111
  xLangfuseSdkName: "javascript",
316
112
  environment: "",
317
113
  // noop as baseUrl is set
@@ -326,14 +122,9 @@ var LangfuseSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcess
326
122
  flushAt,
327
123
  flushIntervalSeconds
328
124
  });
329
- if (!isCryptoAvailable) {
330
- logger.warn(
331
- "[Langfuse] Crypto module not available in this runtime. Media upload functionality will be disabled. Spans will still be processed normally, but any media content in base64 data URIs will not be uploaded to Langfuse."
332
- );
333
- }
334
125
  }
335
126
  get logger() {
336
- return (0, import_core3.getGlobalLogger)();
127
+ return (0, import_core.getGlobalLogger)();
337
128
  }
338
129
  /**
339
130
  * Called when a span is started. Adds environment and release attributes to the span.
@@ -345,10 +136,10 @@ var LangfuseSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcess
345
136
  */
346
137
  onStart(span, parentContext) {
347
138
  span.setAttributes({
348
- [import_core3.LangfuseOtelSpanAttributes.ENVIRONMENT]: this.environment,
349
- [import_core3.LangfuseOtelSpanAttributes.RELEASE]: this.release
139
+ [import_core.LangfuseOtelSpanAttributes.ENVIRONMENT]: this.environment,
140
+ [import_core.LangfuseOtelSpanAttributes.RELEASE]: this.release
350
141
  });
351
- return super.onStart(span, parentContext);
142
+ return this.processor.onStart(span, parentContext);
352
143
  }
353
144
  /**
354
145
  * Called when a span ends. Processes the span for export to Langfuse.
@@ -365,7 +156,16 @@ var LangfuseSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcess
365
156
  * @override
366
157
  */
367
158
  onEnd(span) {
368
- var _a2, _b;
159
+ const processEndedSpanPromise = this.processEndedSpan(span).catch((err) => {
160
+ this.logger.error(err);
161
+ });
162
+ this.pendingEndedSpans.add(processEndedSpanPromise);
163
+ void processEndedSpanPromise.finally(
164
+ () => this.pendingEndedSpans.delete(processEndedSpanPromise)
165
+ );
166
+ }
167
+ async processEndedSpan(span) {
168
+ var _a, _b;
369
169
  if (this.shouldExportSpan) {
370
170
  try {
371
171
  if (this.shouldExportSpan({ otelSpan: span }) === false) return;
@@ -378,7 +178,7 @@ var LangfuseSpanProcessor = class extends import_sdk_trace_base.BatchSpanProcess
378
178
  }
379
179
  }
380
180
  this.applyMaskInPlace(span);
381
- this.handleMediaInPlace(span);
181
+ await this.handleMediaInPlace(span);
382
182
  this.logger.debug(
383
183
  `Processed span:
384
184
  ${JSON.stringify(
@@ -386,11 +186,11 @@ ${JSON.stringify(
386
186
  name: span.name,
387
187
  traceId: span.spanContext().traceId,
388
188
  spanId: span.spanContext().spanId,
389
- parentSpanId: (_b = (_a2 = span.parentSpanContext) == null ? void 0 : _a2.spanId) != null ? _b : null,
189
+ parentSpanId: (_b = (_a = span.parentSpanContext) == null ? void 0 : _a.spanId) != null ? _b : null,
390
190
  attributes: span.attributes,
391
- startTime: new Date((0, import_core4.hrTimeToMilliseconds)(span.startTime)),
392
- endTime: new Date((0, import_core4.hrTimeToMilliseconds)(span.endTime)),
393
- durationMs: (0, import_core4.hrTimeToMilliseconds)(span.duration),
191
+ startTime: new Date((0, import_core2.hrTimeToMilliseconds)(span.startTime)),
192
+ endTime: new Date((0, import_core2.hrTimeToMilliseconds)(span.endTime)),
193
+ durationMs: (0, import_core2.hrTimeToMilliseconds)(span.duration),
394
194
  kind: span.kind,
395
195
  status: span.status,
396
196
  resource: span.resource.attributes,
@@ -400,14 +200,11 @@ ${JSON.stringify(
400
200
  2
401
201
  )}`
402
202
  );
403
- super.onEnd(span);
203
+ this.processor.onEnd(span);
404
204
  }
405
205
  async flush() {
406
- await Promise.all(Object.values(this.pendingMediaUploads)).catch((e) => {
407
- this.logger.error(
408
- e instanceof Error ? e.message : "Unhandled media upload error"
409
- );
410
- });
206
+ await Promise.all(Array.from(this.pendingEndedSpans));
207
+ await Promise.all(Array.from(this.pendingMediaUploads));
411
208
  }
412
209
  /**
413
210
  * Forces an immediate flush of all pending spans and media uploads.
@@ -418,7 +215,7 @@ ${JSON.stringify(
418
215
  */
419
216
  async forceFlush() {
420
217
  await this.flush();
421
- return super.forceFlush();
218
+ return this.processor.forceFlush();
422
219
  }
423
220
  /**
424
221
  * Gracefully shuts down the processor, ensuring all pending operations are completed.
@@ -429,23 +226,17 @@ ${JSON.stringify(
429
226
  */
430
227
  async shutdown() {
431
228
  await this.flush();
432
- return super.shutdown();
229
+ return this.processor.shutdown();
433
230
  }
434
- handleMediaInPlace(span) {
435
- var _a2;
436
- if (!isCryptoAvailable) {
437
- this.logger.debug(
438
- "[Langfuse] Crypto not available, skipping media processing"
439
- );
440
- return;
441
- }
231
+ async handleMediaInPlace(span) {
232
+ var _a;
442
233
  const mediaAttributes = [
443
- import_core3.LangfuseOtelSpanAttributes.OBSERVATION_INPUT,
444
- import_core3.LangfuseOtelSpanAttributes.TRACE_INPUT,
445
- import_core3.LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT,
446
- import_core3.LangfuseOtelSpanAttributes.TRACE_OUTPUT,
447
- import_core3.LangfuseOtelSpanAttributes.OBSERVATION_METADATA,
448
- import_core3.LangfuseOtelSpanAttributes.TRACE_METADATA
234
+ import_core.LangfuseOtelSpanAttributes.OBSERVATION_INPUT,
235
+ import_core.LangfuseOtelSpanAttributes.TRACE_INPUT,
236
+ import_core.LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT,
237
+ import_core.LangfuseOtelSpanAttributes.TRACE_OUTPUT,
238
+ import_core.LangfuseOtelSpanAttributes.OBSERVATION_METADATA,
239
+ import_core.LangfuseOtelSpanAttributes.TRACE_METADATA
449
240
  ];
450
241
  for (const mediaAttribute of mediaAttributes) {
451
242
  const mediaRelevantAttributeKeys = Object.keys(span.attributes).filter(
@@ -461,14 +252,15 @@ ${JSON.stringify(
461
252
  }
462
253
  let mediaReplacedValue = value;
463
254
  const regex = /data:[^;]+;base64,[A-Za-z0-9+/]+=*/g;
464
- const foundMedia = [...new Set((_a2 = value.match(regex)) != null ? _a2 : [])];
255
+ const foundMedia = [...new Set((_a = value.match(regex)) != null ? _a : [])];
465
256
  if (foundMedia.length === 0) continue;
466
257
  for (const mediaDataUri of foundMedia) {
467
- const media = new LangfuseMedia({
258
+ const media = new import_core.LangfuseMedia({
468
259
  base64DataUri: mediaDataUri,
469
260
  source: "base64_data_uri"
470
261
  });
471
- if (!media.tag) {
262
+ const langfuseMediaTag = await media.getTag();
263
+ if (!langfuseMediaTag) {
472
264
  this.logger.warn(
473
265
  "Failed to create Langfuse media tag. Skipping media item."
474
266
  );
@@ -480,15 +272,16 @@ ${JSON.stringify(
480
272
  observationId: span.spanContext().spanId,
481
273
  field: mediaAttribute.includes("input") ? "input" : mediaAttribute.includes("output") ? "output" : "metadata"
482
274
  // todo: make more robust
275
+ }).catch((err) => {
276
+ this.logger.error("Media upload failed with error: ", err);
483
277
  });
484
- const promiseId = (0, import_core3.generateUUID)();
485
- this.pendingMediaUploads[promiseId] = uploadPromise;
278
+ this.pendingMediaUploads.add(uploadPromise);
486
279
  uploadPromise.finally(() => {
487
- delete this.pendingMediaUploads[promiseId];
280
+ this.pendingMediaUploads.delete(uploadPromise);
488
281
  });
489
282
  mediaReplacedValue = mediaReplacedValue.replaceAll(
490
283
  mediaDataUri,
491
- media.tag
284
+ langfuseMediaTag
492
285
  );
493
286
  }
494
287
  span.attributes[key] = mediaReplacedValue;
@@ -497,12 +290,12 @@ ${JSON.stringify(
497
290
  }
498
291
  applyMaskInPlace(span) {
499
292
  const maskCandidates = [
500
- import_core3.LangfuseOtelSpanAttributes.OBSERVATION_INPUT,
501
- import_core3.LangfuseOtelSpanAttributes.TRACE_INPUT,
502
- import_core3.LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT,
503
- import_core3.LangfuseOtelSpanAttributes.TRACE_OUTPUT,
504
- import_core3.LangfuseOtelSpanAttributes.OBSERVATION_METADATA,
505
- import_core3.LangfuseOtelSpanAttributes.TRACE_METADATA
293
+ import_core.LangfuseOtelSpanAttributes.OBSERVATION_INPUT,
294
+ import_core.LangfuseOtelSpanAttributes.TRACE_INPUT,
295
+ import_core.LangfuseOtelSpanAttributes.OBSERVATION_OUTPUT,
296
+ import_core.LangfuseOtelSpanAttributes.TRACE_OUTPUT,
297
+ import_core.LangfuseOtelSpanAttributes.OBSERVATION_METADATA,
298
+ import_core.LangfuseOtelSpanAttributes.TRACE_METADATA
506
299
  ];
507
300
  for (const maskCandidate of maskCandidates) {
508
301
  if (maskCandidate in span.attributes) {
@@ -530,7 +323,8 @@ ${JSON.stringify(
530
323
  field
531
324
  }) {
532
325
  try {
533
- if (!media.contentLength || !media._contentType || !media.contentSha256Hash || !media._contentBytes) {
326
+ const contentSha256Hash = await media.getSha256Hash();
327
+ if (!media.contentLength || !media._contentType || !contentSha256Hash || !media._contentBytes) {
534
328
  return;
535
329
  }
536
330
  const { uploadUrl, mediaId } = await this.apiClient.media.getUploadUrl({
@@ -539,17 +333,18 @@ ${JSON.stringify(
539
333
  observationId,
540
334
  field,
541
335
  contentType: media._contentType,
542
- sha256Hash: media.contentSha256Hash
336
+ sha256Hash: contentSha256Hash
543
337
  });
544
338
  if (!uploadUrl) {
545
339
  this.logger.debug(
546
- `Media status: Media with ID ${media.id} already uploaded. Skipping duplicate upload.`
340
+ `Media status: Media with ID ${mediaId} already uploaded. Skipping duplicate upload.`
547
341
  );
548
342
  return;
549
343
  }
550
- if (media.id !== mediaId) {
344
+ const clientSideMediaId = await media.getId();
345
+ if (clientSideMediaId !== mediaId) {
551
346
  this.logger.error(
552
- `Media integrity error: Media ID mismatch between SDK (${media.id}) and Server (${mediaId}). Upload cancelled. Please check media ID generation logic.`
347
+ `Media integrity error: Media ID mismatch between SDK (${clientSideMediaId}) and Server (${mediaId}). Upload cancelled. Please check media ID generation logic.`
553
348
  );
554
349
  return;
555
350
  }
@@ -559,7 +354,7 @@ ${JSON.stringify(
559
354
  uploadUrl,
560
355
  contentBytes: media._contentBytes,
561
356
  contentType: media._contentType,
562
- contentSha256Hash: media.contentSha256Hash,
357
+ contentSha256Hash,
563
358
  maxRetries: 3,
564
359
  baseDelay: 1e3
565
360
  });
@@ -614,7 +409,6 @@ ${JSON.stringify(
614
409
  };
615
410
  // Annotate the CommonJS export names for ESM import in node:
616
411
  0 && (module.exports = {
617
- LangfuseMedia,
618
412
  LangfuseSpanProcessor
619
413
  });
620
414
  //# sourceMappingURL=index.cjs.map