observa-sdk 0.0.5 → 0.0.7

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
@@ -1,4 +1,12 @@
1
1
  // src/index.ts
2
+ var contextModule = null;
3
+ try {
4
+ const requireFn = globalThis.require;
5
+ if (typeof requireFn !== "undefined") {
6
+ contextModule = requireFn("./context.js");
7
+ }
8
+ } catch {
9
+ }
2
10
  function getNodeEnv() {
3
11
  try {
4
12
  const proc = globalThis.process;
@@ -221,6 +229,20 @@ var Observa = class {
221
229
  isProduction;
222
230
  sampleRate;
223
231
  maxResponseChars;
232
+ // Buffering and retry (now stores canonical events)
233
+ eventBuffer = [];
234
+ flushPromise = null;
235
+ flushInProgress = false;
236
+ maxBufferSize = 100;
237
+ flushIntervalMs = 5e3;
238
+ // Flush every 5 seconds
239
+ flushIntervalId = null;
240
+ // Span hierarchy tracking (for manual trace management)
241
+ currentTraceId = null;
242
+ rootSpanId = null;
243
+ spanStack = [];
244
+ // Stack for tracking parent-child relationships
245
+ traceStartTime = null;
224
246
  constructor(config) {
225
247
  this.apiKey = config.apiKey;
226
248
  let apiUrlEnv;
@@ -265,35 +287,465 @@ var Observa = class {
265
287
  `\u{1F517} [Observa] Auth: ${jwtContext ? "JWT (auto-extracted)" : "Legacy (config)"}`
266
288
  );
267
289
  }
290
+ try {
291
+ if (typeof setInterval !== "undefined") {
292
+ this.flushIntervalId = setInterval(() => {
293
+ this.flush().catch((err) => {
294
+ console.error("[Observa] Periodic flush failed:", err);
295
+ });
296
+ }, this.flushIntervalMs);
297
+ }
298
+ } catch {
299
+ }
300
+ }
301
+ /**
302
+ * Flush buffered events to the API
303
+ * Returns a promise that resolves when all events are sent
304
+ */
305
+ async flush() {
306
+ if (this.flushInProgress || this.eventBuffer.length === 0) {
307
+ return this.flushPromise || Promise.resolve();
308
+ }
309
+ this.flushInProgress = true;
310
+ this.flushPromise = this._doFlush();
311
+ try {
312
+ await this.flushPromise;
313
+ } finally {
314
+ this.flushInProgress = false;
315
+ this.flushPromise = null;
316
+ }
317
+ }
318
+ /**
319
+ * Helper: Create base event properties
320
+ */
321
+ createBaseEventProperties() {
322
+ const traceId = this.currentTraceId || crypto.randomUUID();
323
+ return {
324
+ tenant_id: this.tenantId,
325
+ project_id: this.projectId,
326
+ environment: this.environment,
327
+ trace_id: traceId
328
+ };
329
+ }
330
+ /**
331
+ * Helper: Add event to buffer with proper span hierarchy
332
+ */
333
+ addEvent(eventData) {
334
+ const baseProps = this.createBaseEventProperties();
335
+ const parentSpanId = this.spanStack.length > 0 ? this.spanStack[this.spanStack.length - 1] : null;
336
+ const event = {
337
+ ...baseProps,
338
+ span_id: eventData.span_id || crypto.randomUUID(),
339
+ parent_span_id: (eventData.parent_span_id !== void 0 ? eventData.parent_span_id : parentSpanId) ?? null,
340
+ timestamp: eventData.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
341
+ event_type: eventData.event_type,
342
+ conversation_id: eventData.conversation_id ?? null,
343
+ session_id: eventData.session_id ?? null,
344
+ user_id: eventData.user_id ?? null,
345
+ agent_name: eventData.agent_name ?? null,
346
+ version: eventData.version ?? null,
347
+ route: eventData.route ?? null,
348
+ attributes: eventData.attributes
349
+ };
350
+ this.eventBuffer.push(event);
351
+ if (this.eventBuffer.length >= this.maxBufferSize) {
352
+ this.flush().catch((err) => {
353
+ console.error("[Observa] Auto-flush failed:", err);
354
+ });
355
+ }
356
+ }
357
+ /**
358
+ * Start a new trace (manual trace management)
359
+ */
360
+ startTrace(options = {}) {
361
+ if (this.currentTraceId) {
362
+ console.warn("[Observa] Ending previous trace before starting new one");
363
+ this.endTrace().catch(console.error);
364
+ }
365
+ this.currentTraceId = crypto.randomUUID();
366
+ this.rootSpanId = crypto.randomUUID();
367
+ this.spanStack = [this.rootSpanId];
368
+ this.traceStartTime = Date.now();
369
+ this.addEvent({
370
+ event_type: "trace_start",
371
+ span_id: this.rootSpanId,
372
+ parent_span_id: null,
373
+ conversation_id: options.conversationId || null,
374
+ session_id: options.sessionId || null,
375
+ user_id: options.userId || null,
376
+ attributes: {
377
+ trace_start: {
378
+ name: options.name || null,
379
+ metadata: options.metadata || null
380
+ }
381
+ }
382
+ });
383
+ return this.currentTraceId;
384
+ }
385
+ /**
386
+ * Track a tool call
387
+ */
388
+ trackToolCall(options) {
389
+ const spanId = crypto.randomUUID();
390
+ this.addEvent({
391
+ event_type: "tool_call",
392
+ span_id: spanId,
393
+ attributes: {
394
+ tool_call: {
395
+ tool_name: options.toolName,
396
+ args: options.args || null,
397
+ result: options.result || null,
398
+ result_status: options.resultStatus,
399
+ latency_ms: options.latencyMs,
400
+ error_message: options.errorMessage || null
401
+ }
402
+ }
403
+ });
404
+ return spanId;
405
+ }
406
+ /**
407
+ * Track a retrieval operation
408
+ */
409
+ trackRetrieval(options) {
410
+ const spanId = crypto.randomUUID();
411
+ this.addEvent({
412
+ event_type: "retrieval",
413
+ span_id: spanId,
414
+ attributes: {
415
+ retrieval: {
416
+ retrieval_context_ids: options.contextIds || null,
417
+ retrieval_context_hashes: options.contextHashes || null,
418
+ k: options.k || null,
419
+ top_k: options.k || null,
420
+ similarity_scores: options.similarityScores || null,
421
+ latency_ms: options.latencyMs
422
+ }
423
+ }
424
+ });
425
+ return spanId;
426
+ }
427
+ /**
428
+ * Track an error with stack trace support
429
+ */
430
+ trackError(options) {
431
+ const spanId = crypto.randomUUID();
432
+ let stackTrace = options.stackTrace;
433
+ if (!stackTrace && options.error instanceof Error && options.error.stack) {
434
+ stackTrace = options.error.stack;
435
+ }
436
+ this.addEvent({
437
+ event_type: "error",
438
+ span_id: spanId,
439
+ attributes: {
440
+ error: {
441
+ error_type: options.errorType,
442
+ error_message: options.errorMessage,
443
+ stack_trace: stackTrace || null,
444
+ context: options.context || null
445
+ }
446
+ }
447
+ });
448
+ return spanId;
449
+ }
450
+ /**
451
+ * Track user feedback
452
+ */
453
+ trackFeedback(options) {
454
+ const spanId = options.spanId || crypto.randomUUID();
455
+ const parentSpanId = options.parentSpanId ?? (this.spanStack.length > 0 ? this.spanStack[this.spanStack.length - 1] : null);
456
+ let rating = options.rating;
457
+ if (rating !== void 0 && rating !== null) {
458
+ rating = Math.max(1, Math.min(5, rating));
459
+ }
460
+ this.addEvent({
461
+ event_type: "feedback",
462
+ span_id: spanId,
463
+ parent_span_id: parentSpanId ?? null,
464
+ conversation_id: options.conversationId ?? null,
465
+ session_id: options.sessionId ?? null,
466
+ user_id: options.userId ?? null,
467
+ agent_name: options.agentName ?? null,
468
+ version: options.version ?? null,
469
+ route: options.route ?? null,
470
+ attributes: {
471
+ feedback: {
472
+ type: options.type,
473
+ rating: rating ?? null,
474
+ comment: options.comment || null,
475
+ outcome: options.outcome || null
476
+ }
477
+ }
478
+ });
479
+ return spanId;
480
+ }
481
+ /**
482
+ * Track final output
483
+ */
484
+ trackOutput(options) {
485
+ const spanId = crypto.randomUUID();
486
+ this.addEvent({
487
+ event_type: "output",
488
+ span_id: spanId,
489
+ attributes: {
490
+ output: {
491
+ final_output: options.finalOutput || null,
492
+ output_length: options.outputLength || null
493
+ }
494
+ }
495
+ });
496
+ return spanId;
497
+ }
498
+ /**
499
+ * Execute a function within a span context (for nested operations)
500
+ * This allows tool calls to be nested under LLM calls, etc.
501
+ */
502
+ withSpan(spanId, fn) {
503
+ this.spanStack.push(spanId);
504
+ try {
505
+ return fn();
506
+ } finally {
507
+ this.spanStack.pop();
508
+ }
509
+ }
510
+ /**
511
+ * Execute an async function within a span context (for nested operations)
512
+ */
513
+ async withSpanAsync(spanId, fn) {
514
+ this.spanStack.push(spanId);
515
+ try {
516
+ return await fn();
517
+ } finally {
518
+ this.spanStack.pop();
519
+ }
520
+ }
521
+ /**
522
+ * End trace and send events (manual trace management)
523
+ */
524
+ async endTrace(options = {}) {
525
+ if (!this.currentTraceId || !this.rootSpanId) {
526
+ throw new Error("[Observa] No active trace. Call startTrace() first.");
527
+ }
528
+ const traceEvents = this.eventBuffer.filter(
529
+ (e) => e.trace_id === this.currentTraceId
530
+ );
531
+ const llmEvents = traceEvents.filter((e) => e.event_type === "llm_call");
532
+ const totalTokens = llmEvents.reduce(
533
+ (sum, e) => sum + (e.attributes.llm_call?.total_tokens || 0),
534
+ 0
535
+ );
536
+ const totalCost = llmEvents.reduce(
537
+ (sum, e) => sum + (e.attributes.llm_call?.cost || 0),
538
+ 0
539
+ );
540
+ const totalLatency = this.traceStartTime !== null ? Date.now() - this.traceStartTime : null;
541
+ this.addEvent({
542
+ event_type: "trace_end",
543
+ span_id: this.rootSpanId,
544
+ parent_span_id: null,
545
+ attributes: {
546
+ trace_end: {
547
+ total_latency_ms: totalLatency,
548
+ total_tokens: totalTokens || null,
549
+ total_cost: totalCost || null,
550
+ outcome: options.outcome || "success"
551
+ }
552
+ }
553
+ });
554
+ const traceEventsToSend = this.eventBuffer.filter(
555
+ (e) => e.trace_id === this.currentTraceId
556
+ );
557
+ if (traceEventsToSend.length > 0) {
558
+ await this._sendEventsWithRetry(traceEventsToSend);
559
+ this.eventBuffer = this.eventBuffer.filter(
560
+ (e) => e.trace_id !== this.currentTraceId
561
+ );
562
+ }
563
+ const traceId = this.currentTraceId;
564
+ this.currentTraceId = null;
565
+ this.rootSpanId = null;
566
+ this.spanStack = [];
567
+ this.traceStartTime = null;
568
+ return traceId;
569
+ }
570
+ /**
571
+ * Convert legacy TraceData to canonical events
572
+ */
573
+ traceDataToCanonicalEvents(trace) {
574
+ const events = [];
575
+ const baseEvent = {
576
+ tenant_id: trace.tenantId,
577
+ project_id: trace.projectId,
578
+ environment: trace.environment,
579
+ trace_id: trace.traceId,
580
+ conversation_id: trace.conversationId || null,
581
+ session_id: trace.sessionId || null,
582
+ user_id: trace.userId || null
583
+ };
584
+ events.push({
585
+ ...baseEvent,
586
+ span_id: trace.spanId,
587
+ parent_span_id: trace.parentSpanId || null,
588
+ timestamp: trace.timestamp,
589
+ event_type: "trace_start",
590
+ attributes: {
591
+ trace_start: {
592
+ metadata: trace.metadata || null
593
+ }
594
+ }
595
+ });
596
+ if (trace.model) {
597
+ const llmSpanId = crypto.randomUUID();
598
+ events.push({
599
+ ...baseEvent,
600
+ span_id: llmSpanId,
601
+ parent_span_id: trace.spanId,
602
+ timestamp: trace.timestamp,
603
+ event_type: "llm_call",
604
+ attributes: {
605
+ llm_call: {
606
+ model: trace.model,
607
+ input: trace.query || null,
608
+ output: trace.response || null,
609
+ input_tokens: trace.tokensPrompt || null,
610
+ output_tokens: trace.tokensCompletion || null,
611
+ total_tokens: trace.tokensTotal || null,
612
+ latency_ms: trace.latencyMs,
613
+ time_to_first_token_ms: trace.timeToFirstTokenMs || null,
614
+ streaming_duration_ms: trace.streamingDurationMs || null,
615
+ finish_reason: trace.finishReason || null,
616
+ response_id: trace.responseId || null,
617
+ system_fingerprint: trace.systemFingerprint || null,
618
+ cost: null
619
+ // Cost calculation handled by backend
620
+ }
621
+ }
622
+ });
623
+ }
624
+ events.push({
625
+ ...baseEvent,
626
+ span_id: crypto.randomUUID(),
627
+ parent_span_id: trace.spanId,
628
+ timestamp: trace.timestamp,
629
+ event_type: "output",
630
+ attributes: {
631
+ output: {
632
+ final_output: trace.response || null,
633
+ output_length: trace.responseLength || null
634
+ }
635
+ }
636
+ });
637
+ events.push({
638
+ ...baseEvent,
639
+ span_id: trace.spanId,
640
+ parent_span_id: trace.parentSpanId || null,
641
+ timestamp: trace.timestamp,
642
+ event_type: "trace_end",
643
+ attributes: {
644
+ trace_end: {
645
+ total_latency_ms: trace.latencyMs,
646
+ total_tokens: trace.tokensTotal || null,
647
+ total_cost: null,
648
+ // Cost calculation handled by backend
649
+ outcome: trace.status && trace.status >= 200 && trace.status < 300 ? "success" : "error"
650
+ }
651
+ }
652
+ });
653
+ return events;
268
654
  }
269
- async track(event, action) {
655
+ /**
656
+ * Internal flush implementation
657
+ */
658
+ async _doFlush() {
659
+ const eventsToFlush = [...this.eventBuffer];
660
+ this.eventBuffer = [];
661
+ if (eventsToFlush.length === 0) {
662
+ return;
663
+ }
664
+ const eventsByTrace = /* @__PURE__ */ new Map();
665
+ for (const event of eventsToFlush) {
666
+ if (!eventsByTrace.has(event.trace_id)) {
667
+ eventsByTrace.set(event.trace_id, []);
668
+ }
669
+ eventsByTrace.get(event.trace_id).push(event);
670
+ }
671
+ for (const [traceId, events] of eventsByTrace.entries()) {
672
+ await this._sendEventsWithRetry(events);
673
+ }
674
+ }
675
+ /**
676
+ * Send canonical events with exponential backoff retry
677
+ */
678
+ async _sendEventsWithRetry(events, maxRetries = 3) {
679
+ for (let attempt = 0; attempt <= maxRetries; attempt++) {
680
+ try {
681
+ await this.sendEvents(events);
682
+ return;
683
+ } catch (error) {
684
+ if (attempt === maxRetries) {
685
+ console.error(
686
+ `[Observa] Failed to send events after ${maxRetries + 1} attempts, re-buffering:`,
687
+ error
688
+ );
689
+ this.eventBuffer.push(...events);
690
+ if (this.eventBuffer.length > this.maxBufferSize * 2) {
691
+ const toDrop = this.eventBuffer.length - this.maxBufferSize;
692
+ this.eventBuffer.splice(0, toDrop);
693
+ }
694
+ return;
695
+ }
696
+ const delayMs = 100 * Math.pow(2, attempt);
697
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
698
+ }
699
+ }
700
+ }
701
+ /**
702
+ * Cleanup (call when shutting down)
703
+ */
704
+ async end() {
705
+ if (this.flushIntervalId) {
706
+ clearInterval(this.flushIntervalId);
707
+ this.flushIntervalId = null;
708
+ }
709
+ await this.flush();
710
+ }
711
+ async track(event, action, options) {
270
712
  if (this.sampleRate < 1 && Math.random() > this.sampleRate) {
271
713
  return action();
272
714
  }
273
715
  const startTime = Date.now();
274
716
  const traceId = crypto.randomUUID();
275
717
  const spanId = traceId;
276
- const originalResponse = await action();
718
+ const runWithContext = contextModule?.runInTraceContextAsync || ((ctx, fn) => fn());
719
+ const context = contextModule?.createSpanContext?.(
720
+ traceId,
721
+ spanId,
722
+ null
723
+ ) || { traceId, spanId, parentSpanId: null };
724
+ const originalResponse = await runWithContext(context, action);
277
725
  if (!originalResponse.body) return originalResponse;
278
726
  const responseHeaders = {};
279
727
  originalResponse.headers.forEach((value, key) => {
280
728
  responseHeaders[key] = value;
281
729
  });
282
730
  const [stream1, stream2] = originalResponse.body.tee();
283
- console.log(`[Observa] Starting captureStream for trace ${traceId}`);
284
- this.captureStream({
731
+ const capturePromise = this.captureStream({
285
732
  stream: stream2,
286
733
  event,
287
734
  traceId,
288
735
  spanId,
289
- parentSpanId: null,
736
+ parentSpanId: context.parentSpanId,
290
737
  startTime,
291
738
  status: originalResponse.status,
292
739
  statusText: originalResponse.statusText,
293
740
  headers: responseHeaders
294
- }).catch((err) => {
295
- console.error("[Observa] captureStream promise rejected:", err);
296
741
  });
742
+ if (options?.trackBlocking) {
743
+ await capturePromise;
744
+ } else {
745
+ capturePromise.catch((err) => {
746
+ console.error("[Observa] captureStream promise rejected:", err);
747
+ });
748
+ }
297
749
  return new Response(stream1, {
298
750
  headers: originalResponse.headers,
299
751
  status: originalResponse.status,
@@ -393,13 +845,42 @@ var Observa = class {
393
845
  finishReason: extracted.finishReason ?? null,
394
846
  responseId: extracted.responseId ?? null,
395
847
  systemFingerprint: extracted.systemFingerprint ?? null,
396
- ...headers !== void 0 && { headers }
848
+ ...headers !== void 0 && { headers },
849
+ // Conversation tracking fields
850
+ ...event.conversationId !== void 0 && {
851
+ conversationId: event.conversationId
852
+ },
853
+ ...event.sessionId !== void 0 && { sessionId: event.sessionId },
854
+ ...event.userId !== void 0 && { userId: event.userId },
855
+ ...event.messageIndex !== void 0 && {
856
+ messageIndex: event.messageIndex
857
+ },
858
+ ...event.parentMessageId !== void 0 && {
859
+ parentMessageId: event.parentMessageId
860
+ }
397
861
  };
398
862
  console.log(
399
- `[Observa] Trace data prepared, calling sendTrace for ${traceId}, response length: ${fullResponse.length}`
863
+ `[Observa] Trace data prepared, converting to canonical events for ${traceId}, response length: ${fullResponse.length}`
400
864
  );
401
- await this.sendTrace(traceData);
402
- console.log(`[Observa] sendTrace completed for ${traceId}`);
865
+ const canonicalEvents = this.traceDataToCanonicalEvents(traceData);
866
+ this.eventBuffer.push(...canonicalEvents);
867
+ if (this.eventBuffer.length >= this.maxBufferSize) {
868
+ this.flush().catch((err) => {
869
+ console.error("[Observa] Auto-flush failed:", err);
870
+ });
871
+ } else {
872
+ this._sendEventsWithRetry(canonicalEvents).catch((err) => {
873
+ console.error("[Observa] Failed to send events:", err);
874
+ });
875
+ }
876
+ if (!this.isProduction) {
877
+ const traceUrl = `${this.apiUrl.replace(
878
+ /\/api.*$/,
879
+ ""
880
+ )}/traces/${traceId}`;
881
+ console.log(`[Observa] \u{1F54A}\uFE0F Trace captured: ${traceUrl}`);
882
+ }
883
+ console.log(`[Observa] Trace queued for sending: ${traceId}`);
403
884
  } catch (err) {
404
885
  console.error("[Observa] Error capturing stream:", err);
405
886
  if (err instanceof Error) {
@@ -411,15 +892,57 @@ var Observa = class {
411
892
  }
412
893
  }
413
894
  }
414
- async sendTrace(trace) {
415
- if (!this.isProduction) {
416
- formatBeautifulLog(trace);
895
+ /**
896
+ * Send canonical events to Observa backend
897
+ * (internal method, use _sendEventsWithRetry for retry logic)
898
+ */
899
+ async sendEvents(events) {
900
+ if (events.length === 0) {
901
+ return;
902
+ }
903
+ const traceId = events[0]?.trace_id;
904
+ if (!this.isProduction && traceId) {
905
+ const llmEvent = events.find((e) => e.event_type === "llm_call");
906
+ const outputEvent = events.find((e) => e.event_type === "output");
907
+ const traceEndEvent = events.find((e) => e.event_type === "trace_end");
908
+ if (llmEvent && outputEvent) {
909
+ const llmAttrs = llmEvent.attributes.llm_call;
910
+ const outputAttrs = outputEvent.attributes.output;
911
+ const traceData = {
912
+ traceId: llmEvent.trace_id,
913
+ spanId: llmEvent.parent_span_id || llmEvent.span_id,
914
+ parentSpanId: llmEvent.parent_span_id || null,
915
+ timestamp: llmEvent.timestamp,
916
+ tenantId: llmEvent.tenant_id,
917
+ projectId: llmEvent.project_id,
918
+ environment: llmEvent.environment,
919
+ query: llmAttrs?.input || "",
920
+ response: outputAttrs?.final_output || "",
921
+ responseLength: outputAttrs?.output_length || 0,
922
+ ...llmAttrs?.model && { model: llmAttrs.model },
923
+ tokensPrompt: llmAttrs?.input_tokens ?? null,
924
+ tokensCompletion: llmAttrs?.output_tokens ?? null,
925
+ tokensTotal: llmAttrs?.total_tokens ?? null,
926
+ latencyMs: llmAttrs?.latency_ms || 0,
927
+ timeToFirstTokenMs: llmAttrs?.time_to_first_token_ms ?? null,
928
+ streamingDurationMs: llmAttrs?.streaming_duration_ms ?? null,
929
+ finishReason: llmAttrs?.finish_reason ?? null,
930
+ responseId: llmAttrs?.response_id ?? null,
931
+ systemFingerprint: llmAttrs?.system_fingerprint ?? null,
932
+ ...llmEvent.conversation_id && {
933
+ conversationId: llmEvent.conversation_id
934
+ },
935
+ ...llmEvent.session_id && { sessionId: llmEvent.session_id },
936
+ ...llmEvent.user_id && { userId: llmEvent.user_id }
937
+ };
938
+ formatBeautifulLog(traceData);
939
+ }
417
940
  }
418
941
  try {
419
942
  const baseUrl = this.apiUrl.replace(/\/+$/, "");
420
- const url = `${baseUrl}/api/v1/traces/ingest`;
943
+ const url = `${baseUrl}/api/v1/events/ingest`;
421
944
  console.log(
422
- `[Observa] Sending trace - URL: ${url}, TraceID: ${trace.traceId}, Tenant: ${trace.tenantId}, Project: ${trace.projectId}, APIKey: ${this.apiKey ? `Yes(${this.apiKey.length} chars)` : "No"}`
945
+ `[Observa] Sending ${events.length} canonical events - URL: ${url}, TraceID: ${traceId}, Tenant: ${events[0]?.tenant_id}, Project: ${events[0]?.project_id}, APIKey: ${this.apiKey ? `Yes(${this.apiKey.length} chars)` : "No"}`
423
946
  );
424
947
  const controller = new AbortController();
425
948
  const timeoutId = setTimeout(() => controller.abort(), 1e4);
@@ -430,7 +953,7 @@ var Observa = class {
430
953
  Authorization: `Bearer ${this.apiKey}`,
431
954
  "Content-Type": "application/json"
432
955
  },
433
- body: JSON.stringify(trace),
956
+ body: JSON.stringify(events),
434
957
  signal: controller.signal
435
958
  });
436
959
  clearTimeout(timeoutId);
@@ -449,9 +972,13 @@ var Observa = class {
449
972
  `[Observa] Backend API error: ${response.status} ${response.statusText}`,
450
973
  errorJson.error || errorText
451
974
  );
975
+ throw new Error(
976
+ `Observa API error: ${response.status} ${errorJson.error?.message || errorText}`
977
+ );
452
978
  } else {
979
+ const result = await response.json().catch(() => ({}));
453
980
  console.log(
454
- `\u2705 [Observa] Trace sent successfully - Trace ID: ${trace.traceId}`
981
+ `\u2705 [Observa] Events sent successfully - Trace ID: ${traceId}, Event count: ${result.event_count || events.length}`
455
982
  );
456
983
  }
457
984
  } catch (fetchError) {
@@ -462,7 +989,7 @@ var Observa = class {
462
989
  throw fetchError;
463
990
  }
464
991
  } catch (error) {
465
- console.error("[Observa] Failed to send trace:", error);
992
+ console.error("[Observa] Failed to send events:", error);
466
993
  if (error instanceof Error) {
467
994
  console.error("[Observa] Error message:", error.message);
468
995
  console.error("[Observa] Error name:", error.name);
@@ -475,6 +1002,7 @@ var Observa = class {
475
1002
  console.error("[Observa] Error stack:", error.stack);
476
1003
  }
477
1004
  }
1005
+ throw error;
478
1006
  }
479
1007
  }
480
1008
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "observa-sdk",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Enterprise-grade observability SDK for AI applications. Track and monitor LLM interactions with zero friction.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -31,5 +31,8 @@
31
31
  "analytics"
32
32
  ],
33
33
  "author": "Nicka",
34
- "license": "MIT"
34
+ "license": "MIT",
35
+ "publishConfig": {
36
+ "access": "public"
37
+ }
35
38
  }