@spatius/avatarkit 1.3.4 → 1.3.5-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  import { n as __exportAll, r as __toESM, t as __commonJSMin } from "./rolldown-runtime-B-1-B7_t.js";
2
- import { t as logger } from "./logger-B_tTFAYq.js";
2
+ import { t as logger } from "./logger-BCrlTIt2.js";
3
3
  /** Opus granule positions are always in 48 kHz samples, regardless of input rate. */
4
4
  var OPUS_GRANULE_RATE = 48e3;
5
5
  /**
@@ -1,4 +1,4 @@
1
- import { t as logger } from "./logger-B_tTFAYq.js";
1
+ import { t as logger } from "./logger-BCrlTIt2.js";
2
2
  //#region audio/OpusDecoderProxy.ts
3
3
  var OpusDecoderProxy = class OpusDecoderProxy {
4
4
  worker = null;
@@ -21,7 +21,7 @@ var OpusDecoderProxy = class OpusDecoderProxy {
21
21
  } catch (err) {
22
22
  logger.warn("[Opus][DecoderProxy] Worker unavailable, falling back to main-thread decode:", err instanceof Error ? err.message : String(err));
23
23
  }
24
- const { OggOpusDecoder } = await import("./OpusCodec-Cib3mtQ2.js").then((n) => n.n);
24
+ const { OggOpusDecoder } = await import("./OpusCodec-BYwstcZb.js").then((n) => n.n);
25
25
  proxy.fallbackDecoder = new OggOpusDecoder();
26
26
  proxy.backend = "main-thread";
27
27
  return proxy;
@@ -32,7 +32,7 @@ var OpusDecoderProxy = class OpusDecoderProxy {
32
32
  try {
33
33
  worker = new Worker(new URL(
34
34
  /* @vite-ignore */
35
- "" + new URL("assets/OpusDecoderWorker.worker-BAd4MYA3.js", import.meta.url).href,
35
+ "" + new URL("assets/OpusDecoderWorker.worker-DkKhJmGs.js", import.meta.url).href,
36
36
  "" + import.meta.url
37
37
  ), { type: "module" });
38
38
  } catch (err) {
@@ -1,5 +1,5 @@
1
1
  import { n as __exportAll } from "./rolldown-runtime-B-1-B7_t.js";
2
- import { t as logger } from "./logger-B_tTFAYq.js";
2
+ import { t as logger } from "./logger-BCrlTIt2.js";
3
3
  //#region audio/OpusEncoderProxy.ts
4
4
  var OpusEncoderProxy_exports = /* @__PURE__ */ __exportAll({
5
5
  OpusEncoderProxy: () => OpusEncoderProxy,
@@ -43,7 +43,7 @@ var OpusEncoderProxy = class OpusEncoderProxy {
43
43
  } catch (err) {
44
44
  logger.warn("[Opus][Proxy] Worker unavailable, falling back to main-thread encode:", err instanceof Error ? err.message : String(err));
45
45
  }
46
- const { OggOpusEncoder } = await import("./OpusCodec-Cib3mtQ2.js").then((n) => n.n);
46
+ const { OggOpusEncoder } = await import("./OpusCodec-BYwstcZb.js").then((n) => n.n);
47
47
  proxy.fallbackEncoder = new OggOpusEncoder(sampleRate, bitrate);
48
48
  proxy.backend = "main-thread";
49
49
  return proxy;
@@ -54,7 +54,7 @@ var OpusEncoderProxy = class OpusEncoderProxy {
54
54
  try {
55
55
  worker = new Worker(new URL(
56
56
  /* @vite-ignore */
57
- "" + new URL("assets/OpusEncoderWorker.worker-DdhFHkno.js", import.meta.url).href,
57
+ "" + new URL("assets/OpusEncoderWorker.worker-Bu8QRO55.js", import.meta.url).href,
58
58
  "" + import.meta.url
59
59
  ), { type: "module" });
60
60
  } catch (err) {
@@ -1,5 +1,5 @@
1
- import { c as logEvent, t as logger } from "./logger-B_tTFAYq.js";
2
- import { n as APP_CONFIG, t as errorToMessage } from "./error-utils-B76Nf6d6.js";
1
+ import { c as logEvent, t as logger } from "./logger-BCrlTIt2.js";
2
+ import { n as APP_CONFIG, t as errorToMessage } from "./error-utils-CX5P3vnW.js";
3
3
  //#region audio/StreamingAudioPlayer.ts
4
4
  /**
5
5
  * Streaming Audio Player
@@ -1,5 +1,5 @@
1
- import { St as ErrorCode, _t as generateTraceId, c as logEvent, h as hostOf, ht as isDebugMode, l as logMetric, t as logger, vt as AvatarError, y as recordHttpClientDuration } from "./logger-__jZD7QG.js";
2
- import { t as AvatarSDK } from "./AvatarSDK-DX8_-oyi.js";
1
+ import { St as ErrorCode, _t as generateTraceId, c as logEvent, h as hostOf, ht as isDebugMode, l as logMetric, t as logger, vt as AvatarError, y as recordHttpClientDuration } from "./logger-CnIdJBOF.js";
2
+ import { t as AvatarSDK } from "./AvatarSDK-vQTYP0IB.js";
3
3
  //#region config/app-config.ts
4
4
  const GLOBAL_FLAME_CDN_BASE = "https://cdn.spatialwalk.cloud/public";
5
5
  const CN_FLAME_CDN_BASE = "https://cdn.spatialwalk.top/public";
@@ -393,7 +393,8 @@ var AvatarDownloader = class {
393
393
  logMetric("template_resources_load_measure", duration, {
394
394
  file_count: 1,
395
395
  cache_hit: true,
396
- cache_type: "pwa"
396
+ cache_type: "pwa",
397
+ result: "success"
397
398
  });
398
399
  return { unifiedModel: cached };
399
400
  }
@@ -419,7 +420,8 @@ var AvatarDownloader = class {
419
420
  logMetric("template_resources_load_measure", Date.now() - startTime, {
420
421
  file_count: 1,
421
422
  cache_hit: false,
422
- cache_type: "none"
423
+ cache_type: "none",
424
+ result: "success"
423
425
  });
424
426
  recordAssetTransaction(templateOutcomes, Date.now() - startTime, TEMPLATE_OPERATION);
425
427
  return { unifiedModel: buffer };
@@ -429,6 +431,16 @@ var AvatarDownloader = class {
429
431
  }
430
432
  }
431
433
  recordAssetTransaction(templateOutcomes, Date.now() - startTime, TEMPLATE_OPERATION);
434
+ const lastStatus = templateOutcomes[0]?.statusCode;
435
+ logMetric("template_resources_load_measure", Date.now() - startTime, {
436
+ file_count: 1,
437
+ cache_hit: false,
438
+ cache_type: "none",
439
+ result: lastStatus !== void 0 && lastStatus >= 200 && lastStatus < 400 ? "decode_failed" : "download_failed"
440
+ }, {
441
+ description: lastError?.message ?? "unknown",
442
+ ...lastStatus !== void 0 ? { last_status_code: lastStatus } : {}
443
+ });
432
444
  throw lastError || /* @__PURE__ */ new Error(`Failed to download unified template after ${maxRetries} attempts`);
433
445
  }
434
446
  /**
@@ -559,6 +571,19 @@ var AvatarDownloader = class {
559
571
  });
560
572
  try {
561
573
  await Promise.all(downloadPromises);
574
+ } catch (error) {
575
+ if (!(error instanceof Error && (error.name === "AbortError" || error.message === "Download cancelled"))) logMetric("download_avatar_assets_latency", Date.now() - totalStartTime, {
576
+ resolution: "default",
577
+ use_compressed_model: useCompressedModel,
578
+ file_count: filesToLoad.length,
579
+ cache_hit: false,
580
+ cache_type: "none",
581
+ result: "download_failed"
582
+ }, {
583
+ avatar_id: characterMeta.characterId ?? "unknown",
584
+ description: error instanceof Error ? error.message : String(error)
585
+ });
586
+ throw error;
562
587
  } finally {
563
588
  recordAssetTransaction(httpOutcomes, Date.now() - totalStartTime);
564
589
  }
@@ -566,6 +591,17 @@ var AvatarDownloader = class {
566
591
  const totalDuration = Date.now() - totalStartTime;
567
592
  if (!characterData.shape || !characterData.pointCloud) {
568
593
  const reason = "Failed to load character data";
594
+ logMetric("download_avatar_assets_latency", totalDuration, {
595
+ resolution: "default",
596
+ use_compressed_model: useCompressedModel,
597
+ file_count: filesToLoad.length,
598
+ cache_hit: false,
599
+ cache_type: "none",
600
+ result: "incomplete_data"
601
+ }, {
602
+ avatar_id: characterMeta.characterId ?? "unknown",
603
+ description: reason
604
+ });
569
605
  logEvent("download_avatar_assets_failed", "error", {
570
606
  avatar_id: characterMeta.characterId ?? "unknown",
571
607
  description: reason
@@ -582,7 +618,8 @@ var AvatarDownloader = class {
582
618
  use_compressed_model: useCompressedModel,
583
619
  file_count: filesToLoad.length,
584
620
  cache_hit: cacheHit,
585
- cache_type: cacheType
621
+ cache_type: cacheType,
622
+ result: "success"
586
623
  }, {
587
624
  avatar_id: characterMeta.characterId ?? "unknown",
588
625
  parallel_duration: parallelDuration,
@@ -760,7 +797,7 @@ var AvatarDownloader = class {
760
797
  const serverMessage = firstError.detail || firstError.title || firstError.message || "Unknown server error";
761
798
  throw new AvatarError(`${firstError.code || firstError.status || "SERVER_ERROR"}: ${serverMessage}`, ErrorCode.failedToFetchAvatarMetadata);
762
799
  }
763
- logMetric("fetch_avatar_metadata_latency", Date.now() - startTime, {}, {
800
+ logMetric("fetch_avatar_metadata_latency", Date.now() - startTime, { result: "success" }, {
764
801
  avatar_id: characterId,
765
802
  trace_id: traceId
766
803
  });
@@ -775,6 +812,11 @@ var AvatarDownloader = class {
775
812
  }
776
813
  logger.error("Failed to fetch character:", error);
777
814
  if (error instanceof AvatarError) {
815
+ logMetric("fetch_avatar_metadata_latency", Date.now() - startTime, { result: error.code }, {
816
+ avatar_id: characterId,
817
+ trace_id: traceId,
818
+ description: error.message
819
+ });
778
820
  logEvent("fetch_avatar_metadata_failed", "error", {
779
821
  avatar_id: characterId ?? "unknown",
780
822
  description: error.message,
@@ -784,6 +826,11 @@ var AvatarDownloader = class {
784
826
  }
785
827
  const errorMessage = error && typeof error === "object" && "message" in error ? String(error.message) : "Failed to fetch character";
786
828
  const dataMessage = error && typeof error === "object" && "data" in error && typeof error.data === "object" && error.data?.message ? String(error.data.message) : null;
829
+ logMetric("fetch_avatar_metadata_latency", Date.now() - startTime, { result: "network_error" }, {
830
+ avatar_id: characterId,
831
+ trace_id: traceId,
832
+ description: dataMessage || errorMessage
833
+ });
787
834
  logEvent("fetch_avatar_metadata_failed", "error", {
788
835
  avatar_id: characterId ?? "unknown",
789
836
  description: dataMessage || errorMessage,
@@ -1,5 +1,5 @@
1
1
  import { n as __exportAll } from "./rolldown-runtime-B-1-B7_t.js";
2
- import { $ as INVALID_SPAN_CONTEXT, A as BindOnceFuture, B as ATTR_EXCEPTION_STACKTRACE, C as JSON_ENCODER, Ct as LogLevel, D as OTLPExporterBase, E as toAttributes, F as isTimeInput, G as globalErrorHandler, H as ATTR_SERVICE_NAME, I as isTimeInputHrTime, J as trace, K as isTracingSuppressed, L as millisToHrTime, M as addHrTimes, N as hrTime, O as defaultResource, P as hrTimeDuration, Q as isValidTraceId, R as otperformance, S as createLegacyOtlpBrowserExportDelegate, T as createResource, U as getNumberFromEnv, V as ATTR_EXCEPTION_TYPE, W as getStringFromEnv, X as context, Y as diag$1, Z as isSpanContextValid, _ as cleanupOtelMetrics, a as clientContextFields, at as DiagAPI, b as getSdkPackage, c as logEvent, ct as unregisterGlobal, d as cleanupOtel, dt as OTEL_STREAM_NAME, et as TraceFlags, f as initializeOtel, ft as OTEL_TRACES_ENDPOINT, g as observeExporter, gt as idManager, i as cleanupPostHog, it as createContextKey, j as ExportResultCode, k as resourceFromAttributes, lt as OTEL_LOGS_ENDPOINT, m as fetchBootstrap, mt as OTEL_USERNAME, n as setLogLevel, nt as createNoopMeter, o as getLogsFeatureFlag, ot as getGlobal, p as clockSync, pt as OTEL_TRACES_STREAM_NAME, q as suppressTracing, r as logSink, rt as ROOT_CONTEXT, s as initializePostHog, st as registerGlobal, t as logger, tt as ContextAPI, u as updatePostHogPersonPropertiesForFlags, ut as OTEL_PASSWORD, v as initializeOtelMetrics, w as createInstrumentationScope, x as resolveSdkVersion, xt as DrivingServiceMode, z as ATTR_EXCEPTION_MESSAGE } from "./logger-__jZD7QG.js";
2
+ import { $ as INVALID_SPAN_CONTEXT, A as BindOnceFuture, B as ATTR_EXCEPTION_STACKTRACE, C as JSON_ENCODER, Ct as LogLevel, D as OTLPExporterBase, E as toAttributes, F as isTimeInput, G as globalErrorHandler, H as ATTR_SERVICE_NAME, I as isTimeInputHrTime, J as trace, K as isTracingSuppressed, L as millisToHrTime, M as addHrTimes, N as hrTime, O as defaultResource, P as hrTimeDuration, Q as isValidTraceId, R as otperformance, S as createLegacyOtlpBrowserExportDelegate, T as createResource, U as getNumberFromEnv, V as ATTR_EXCEPTION_TYPE, W as getStringFromEnv, X as context, Y as diag$1, Z as isSpanContextValid, _ as cleanupOtelMetrics, a as clientContextFields, at as DiagAPI, b as getSdkPackage, c as logEvent, ct as unregisterGlobal, d as cleanupOtel, dt as OTEL_STREAM_NAME, et as TraceFlags, f as initializeOtel, ft as OTEL_TRACES_ENDPOINT, g as observeExporter, gt as idManager, i as cleanupPostHog, it as createContextKey, j as ExportResultCode, k as resourceFromAttributes, lt as OTEL_LOGS_ENDPOINT, m as fetchBootstrap, mt as OTEL_USERNAME, n as setLogLevel, nt as createNoopMeter, o as getLogsFeatureFlag, ot as getGlobal, p as clockSync, pt as OTEL_TRACES_STREAM_NAME, q as suppressTracing, r as logSink, rt as ROOT_CONTEXT, s as initializePostHog, st as registerGlobal, t as logger, tt as ContextAPI, u as updatePostHogPersonPropertiesForFlags, ut as OTEL_PASSWORD, v as initializeOtelMetrics, w as createInstrumentationScope, x as resolveSdkVersion, xt as DrivingServiceMode, z as ATTR_EXCEPTION_MESSAGE } from "./logger-CnIdJBOF.js";
3
3
  //#region node_modules/.pnpm/@opentelemetry+api@1.9.1/node_modules/@opentelemetry/api/build/esm/baggage/internal/baggage-impl.js
4
4
  var BaggageImpl = class BaggageImpl {
5
5
  constructor(entries) {
@@ -5791,7 +5791,8 @@ function createBaseServerResponseAnimation() {
5791
5791
  reqId: "",
5792
5792
  end: false,
5793
5793
  animation: void 0,
5794
- avatarId: ""
5794
+ avatarId: "",
5795
+ traceContext: void 0
5795
5796
  };
5796
5797
  }
5797
5798
  const ServerResponseAnimation = {
@@ -5801,6 +5802,7 @@ const ServerResponseAnimation = {
5801
5802
  if (message.end !== false) writer.uint32(24).bool(message.end);
5802
5803
  if (message.animation !== void 0) FlameAnimation.encode(message.animation, writer.uint32(34).fork()).join();
5803
5804
  if (message.avatarId !== "") writer.uint32(42).string(message.avatarId);
5805
+ if (message.traceContext !== void 0) TraceContext.encode(message.traceContext, writer.uint32(50).fork()).join();
5804
5806
  return writer;
5805
5807
  },
5806
5808
  decode(input, length) {
@@ -5830,6 +5832,10 @@ const ServerResponseAnimation = {
5830
5832
  if (tag !== 42) break;
5831
5833
  message.avatarId = reader.string();
5832
5834
  continue;
5835
+ case 6:
5836
+ if (tag !== 50) break;
5837
+ message.traceContext = TraceContext.decode(reader, reader.uint32());
5838
+ continue;
5833
5839
  }
5834
5840
  if ((tag & 7) === 4 || tag === 0) break;
5835
5841
  reader.skip(tag & 7);
@@ -5842,7 +5848,8 @@ const ServerResponseAnimation = {
5842
5848
  reqId: isSet(object.reqId) ? globalThis.String(object.reqId) : isSet(object.req_id) ? globalThis.String(object.req_id) : "",
5843
5849
  end: isSet(object.end) ? globalThis.Boolean(object.end) : false,
5844
5850
  animation: isSet(object.animation) ? FlameAnimation.fromJSON(object.animation) : void 0,
5845
- avatarId: isSet(object.avatarId) ? globalThis.String(object.avatarId) : isSet(object.avatar_id) ? globalThis.String(object.avatar_id) : ""
5851
+ avatarId: isSet(object.avatarId) ? globalThis.String(object.avatarId) : isSet(object.avatar_id) ? globalThis.String(object.avatar_id) : "",
5852
+ traceContext: isSet(object.traceContext) ? TraceContext.fromJSON(object.traceContext) : isSet(object.trace_context) ? TraceContext.fromJSON(object.trace_context) : void 0
5846
5853
  };
5847
5854
  },
5848
5855
  toJSON(message) {
@@ -5852,6 +5859,7 @@ const ServerResponseAnimation = {
5852
5859
  if (message.end !== false) obj.end = message.end;
5853
5860
  if (message.animation !== void 0) obj.animation = FlameAnimation.toJSON(message.animation);
5854
5861
  if (message.avatarId !== "") obj.avatarId = message.avatarId;
5862
+ if (message.traceContext !== void 0) obj.traceContext = TraceContext.toJSON(message.traceContext);
5855
5863
  return obj;
5856
5864
  },
5857
5865
  create(base) {
@@ -5864,6 +5872,7 @@ const ServerResponseAnimation = {
5864
5872
  message.end = object.end ?? false;
5865
5873
  message.animation = object.animation !== void 0 && object.animation !== null ? FlameAnimation.fromPartial(object.animation) : void 0;
5866
5874
  message.avatarId = object.avatarId ?? "";
5875
+ message.traceContext = object.traceContext !== void 0 && object.traceContext !== null ? TraceContext.fromPartial(object.traceContext) : void 0;
5867
5876
  return message;
5868
5877
  }
5869
5878
  };
@@ -6223,7 +6232,7 @@ var AvatarSDK = class {
6223
6232
  static _initializationState = "uninitialized";
6224
6233
  static _initializingPromise = null;
6225
6234
  static _configuration = null;
6226
- static _version = "1.3.4";
6235
+ static _version = "1.3.5-beta.1";
6227
6236
  static _avatarCore = null;
6228
6237
  static _cachedDeviceScore = null;
6229
6238
  static _rendererBackend = null;
@@ -6412,7 +6421,7 @@ var AvatarSDK = class {
6412
6421
  logger.log("[AvatarSDK] Loading template resources...");
6413
6422
  logEvent("template_init_start", "info", { stage: "sdk_init" });
6414
6423
  try {
6415
- const { AvatarDownloader } = await import("./AvatarDownloader-DkReeoUZ.js");
6424
+ const { AvatarDownloader } = await import("./AvatarDownloader-DImd24mo.js");
6416
6425
  const templateResources = await new AvatarDownloader().loadUnifiedTemplate();
6417
6426
  if (await this._avatarCore.loadTemplateResourcesFromBuffers(templateResources)) logger.log("[AvatarSDK] Template resources initialized successfully");
6418
6427
  else logger.log("[AvatarSDK] Template resources already initialized, skipping...");
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./rolldown-runtime-B-1-B7_t.js";
2
- import { t as logger } from "./logger-__jZD7QG.js";
2
+ import { t as logger } from "./logger-CnIdJBOF.js";
3
3
  //#region __vite-browser-external
4
4
  var require___vite_browser_external = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5
5
  module.exports = {};
@@ -1,5 +1,5 @@
1
1
  import { r as __toESM, t as __commonJSMin } from "./rolldown-runtime-B-1-B7_t.js";
2
- import { t as logger } from "./logger-__jZD7QG.js";
2
+ import { t as logger } from "./logger-CnIdJBOF.js";
3
3
  //#region __vite-browser-external
4
4
  var require___vite_browser_external = /* @__PURE__ */ __commonJSMin(((exports, module) => {
5
5
  module.exports = {};
@@ -15449,7 +15449,7 @@ async function writeToLocalLog(message, level, extra = {}) {
15449
15449
  try {
15450
15450
  const { shouldPersist, sanitized } = sanitizeForLocalLog(message);
15451
15451
  if (!shouldPersist) return;
15452
- const { AvatarSDK } = await import("./AvatarSDK-DX8_-oyi.js").then((n) => n.n);
15452
+ const { AvatarSDK } = await import("./AvatarSDK-vQTYP0IB.js").then((n) => n.n);
15453
15453
  const version = AvatarSDK.version;
15454
15454
  const appId = idManager.getAppId();
15455
15455
  const userId = idManager.getUserId();
@@ -87,6 +87,23 @@ export declare class AvatarController {
87
87
  private readonly MAX_AUDIO_TIME_STUCK_COUNT;
88
88
  private readonly AUDIO_TIME_STUCK_THRESHOLD;
89
89
  private latencyMarks;
90
+ /**
91
+ * W3C `traceparent` the driving service stamped on this round's animation
92
+ * packets (`ServerResponseAnimation.trace_context`), first one wins.
93
+ *
94
+ * Backend mode only, because only there is the SDK the FOLLOWER of the trace:
95
+ * the conversation_id is minted locally and never reaches the server, so the
96
+ * trace_id derived from it cannot match the server's and the round would
97
+ * otherwise report as a trace unrelated to the upstream one. In direct mode the
98
+ * SDK originates the trace (it sends buildTraceparent upstream on the first
99
+ * audio packet), so the echoed value is by construction the derived one and is
100
+ * not collected — see startPlaybackTrace.
101
+ *
102
+ * Read when the round's trace is built (at playback end), hence kept for the
103
+ * round rather than used on the spot. Reset per conversation alongside
104
+ * latencyMarks.
105
+ */
106
+ private serverTraceparent;
90
107
  /**
91
108
  * Per-call trace records for the current round, in call order. Unlike
92
109
  * latencyMarks (which aggregates arrival into per-second/per-group instants),
@@ -1,4 +1,4 @@
1
- import { bt as isDebugMode } from "./logger-B_tTFAYq.js";
1
+ import { bt as isDebugMode } from "./logger-BCrlTIt2.js";
2
2
  //#region config/app-config.ts
3
3
  var GLOBAL_FLAME_CDN_BASE = "https://cdn.spatialwalk.cloud/public";
4
4
  var CN_FLAME_CDN_BASE = "https://cdn.spatialwalk.top/public";
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
- import { a as EgressType, c as TransportCompression, i as AudioFormat, l as BinaryReader, o as Message, r as avatarViewRegistry, s as MessageType, t as AvatarSDK, u as BinaryWriter } from "./AvatarSDK-BMjjoYiZ.js";
2
- import { At as DEFAULT_REGION_REQUEST, C as recordMetric, Ct as AnimationType, Dt as ConversationState, Et as ConnectionState, Ft as LogLevel, It as RENDER_QUALITY_PARAMS, Lt as RenderQuality, Mt as ErrorCode, Nt as FrameStarvationMode, Ot as DEFAULT_OPUS_BITRATE, Pt as LoadProgress, Rt as TransitionType, Tt as AvatarState, c as logEvent, g as clockSync, h as resolveMarks, jt as DrivingServiceMode, kt as DEFAULT_REGION, l as logMetric, m as monoTimestamp, p as monoMarkFrom, t as logger, wt as AvatarError, xt as idManager } from "./logger-B_tTFAYq.js";
3
- import { a as startLoadTrace, o as startPlaybackTrace, r as startConnectTrace, s as buildTraceparent } from "./otel-trace-DmmQrXv-.js";
4
- import { n as APP_CONFIG } from "./error-utils-B76Nf6d6.js";
5
- import { r as OggMuxer, t as OggPageSplitter } from "./OpusCodec-Cib3mtQ2.js";
6
- import { n as setOpusEncodeFrameSink } from "./OpusEncoderProxy-BiX90p4q.js";
7
- import { t as AvatarDownloader } from "./AvatarDownloader-CavxMpAz.js";
1
+ import { a as startLoadTrace, c as AudioFormat, d as MessageType, f as TransportCompression, l as EgressType, m as BinaryWriter, o as startPlaybackTrace, p as BinaryReader, r as startConnectTrace, s as buildTraceparent, u as Message } from "./otel-trace-D2py5nQo.js";
2
+ import { At as DEFAULT_REGION_REQUEST, C as recordMetric, Ct as AnimationType, Dt as ConversationState, Et as ConnectionState, Ft as LogLevel, It as RENDER_QUALITY_PARAMS, Lt as RenderQuality, Mt as ErrorCode, Nt as FrameStarvationMode, Ot as DEFAULT_OPUS_BITRATE, Pt as LoadProgress, Rt as TransitionType, Tt as AvatarState, c as logEvent, g as clockSync, h as resolveMarks, jt as DrivingServiceMode, kt as DEFAULT_REGION, l as logMetric, m as monoTimestamp, p as monoMarkFrom, t as logger, wt as AvatarError, xt as idManager } from "./logger-BCrlTIt2.js";
3
+ import { n as APP_CONFIG } from "./error-utils-CX5P3vnW.js";
4
+ import { r as OggMuxer, t as OggPageSplitter } from "./OpusCodec-BYwstcZb.js";
5
+ import { r as avatarViewRegistry, t as AvatarSDK } from "./AvatarSDK-DCYDBMwd.js";
6
+ import { n as setOpusEncodeFrameSink } from "./OpusEncoderProxy-CQrj6ZjY.js";
7
+ import { t as AvatarDownloader } from "./AvatarDownloader-BLERPef7.js";
8
8
  //#region core/Avatar.ts
9
9
  var Avatar = class {
10
10
  id;
@@ -125,11 +125,13 @@ function decodeAnimation(data, expectedAvatarId) {
125
125
  avatarIdMismatch: true
126
126
  };
127
127
  }
128
+ const traceparent = response.traceContext?.traceparent || void 0;
128
129
  return {
129
130
  animation: {
130
131
  keyframes: response.animation.keyframes,
131
132
  avatarId,
132
- end: response.end
133
+ end: response.end,
134
+ ...traceparent ? { traceparent } : {}
133
135
  },
134
136
  avatarIdMismatch: false
135
137
  };
@@ -311,8 +313,8 @@ var AnimationPlayer = class AnimationPlayer {
311
313
  */
312
314
  async createAndInitializeStreamingPlayer() {
313
315
  if (this.streamingPlayer) return;
314
- const { StreamingAudioPlayer } = await import("./StreamingAudioPlayer-D5_x6veD.js");
315
- const { AvatarSDK } = await import("./AvatarSDK-BMjjoYiZ.js").then((n) => n.n);
316
+ const { StreamingAudioPlayer } = await import("./StreamingAudioPlayer-BORop_1T.js");
317
+ const { AvatarSDK } = await import("./AvatarSDK-DCYDBMwd.js").then((n) => n.n);
316
318
  const audioFormat = AvatarSDK.getAudioFormat();
317
319
  this.streamingPlayer = new StreamingAudioPlayer({
318
320
  sampleRate: audioFormat.sampleRate,
@@ -1352,7 +1354,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
1352
1354
  return;
1353
1355
  }
1354
1356
  try {
1355
- const { OpusEncoderProxy } = await import("./OpusEncoderProxy-BiX90p4q.js").then((n) => n.t);
1357
+ const { OpusEncoderProxy } = await import("./OpusEncoderProxy-CQrj6ZjY.js").then((n) => n.t);
1356
1358
  const bitrate = opusBitrate ?? 48e3;
1357
1359
  this.opusEncoder = await OpusEncoderProxy.create(sampleRate, bitrate);
1358
1360
  this.uplinkIsOpus = true;
@@ -1528,6 +1530,15 @@ var AnimationWebSocketClient = class extends EventEmitter {
1528
1530
  });
1529
1531
  break;
1530
1532
  }
1533
+ if (this.connectStartMs > 0) {
1534
+ const connectResult = sdkErrorCode ?? (event.code === 1006 ? "closed_abnormally" : "closed_before_confirm");
1535
+ logMetric("ws_connect_latency", Date.now() - this.connectStartMs, { result: connectResult }, {
1536
+ connection_id: idManager.getConnectionId() || "",
1537
+ close_code: event.code,
1538
+ description: reason || `Closed with code ${event.code}`
1539
+ });
1540
+ this.connectStartMs = 0;
1541
+ }
1531
1542
  if (sdkErrorCode) this.emit("error", new AvatarError(reason || `WebSocket connection failed with code ${event.code}`, sdkErrorCode));
1532
1543
  else if (event.code !== 1e3) {
1533
1544
  logEvent("websocket_closed_unexpected", "error", {
@@ -1617,7 +1628,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
1617
1628
  } else logger.log("[AnimationWebSocketClient] Session confirmed by server");
1618
1629
  if (this.connectStartMs > 0) {
1619
1630
  const confirmMs = Date.now();
1620
- logMetric("ws_connect_latency", confirmMs - this.connectStartMs, {}, { connection_id: idManager.getConnectionId() || "" });
1631
+ logMetric("ws_connect_latency", confirmMs - this.connectStartMs, { result: "success" }, { connection_id: idManager.getConnectionId() || "" });
1621
1632
  this.emitConnectTrace(confirmMs);
1622
1633
  this.connectStartMs = 0;
1623
1634
  }
@@ -2274,6 +2285,23 @@ var AvatarController = class {
2274
2285
  animGroupCount: 0
2275
2286
  };
2276
2287
  /**
2288
+ * W3C `traceparent` the driving service stamped on this round's animation
2289
+ * packets (`ServerResponseAnimation.trace_context`), first one wins.
2290
+ *
2291
+ * Backend mode only, because only there is the SDK the FOLLOWER of the trace:
2292
+ * the conversation_id is minted locally and never reaches the server, so the
2293
+ * trace_id derived from it cannot match the server's and the round would
2294
+ * otherwise report as a trace unrelated to the upstream one. In direct mode the
2295
+ * SDK originates the trace (it sends buildTraceparent upstream on the first
2296
+ * audio packet), so the echoed value is by construction the derived one and is
2297
+ * not collected — see startPlaybackTrace.
2298
+ *
2299
+ * Read when the round's trace is built (at playback end), hence kept for the
2300
+ * round rather than used on the spot. Reset per conversation alongside
2301
+ * latencyMarks.
2302
+ */
2303
+ serverTraceparent = null;
2304
+ /**
2277
2305
  * Per-call trace records for the current round, in call order. Unlike
2278
2306
  * latencyMarks (which aggregates arrival into per-second/per-group instants),
2279
2307
  * these are one entry per actual API action, so each becomes a short span:
@@ -2604,7 +2632,7 @@ var AvatarController = class {
2604
2632
  end_reason: this.playbackEndReason,
2605
2633
  input_audio_format: resolveInputAudioFormat(),
2606
2634
  uplink_audio_format: resolveUplinkAudioFormat()
2607
- });
2635
+ }, this.serverTraceparent ?? void 0);
2608
2636
  if (resolved && typeof tap0 === "number") {
2609
2637
  const actionMarks = {};
2610
2638
  this.traceActions.sends.forEach((s, i) => {
@@ -2794,7 +2822,7 @@ var AvatarController = class {
2794
2822
  const { inputAudioFormat } = AvatarSDK.getAudioFormat();
2795
2823
  if (inputAudioFormat !== "opus" || this.inputOpusDecoderProxy) return;
2796
2824
  try {
2797
- const { OpusDecoderProxy } = await import("./OpusDecoderProxy-Dz21UtCz.js");
2825
+ const { OpusDecoderProxy } = await import("./OpusDecoderProxy-DW_SVYwd.js");
2798
2826
  this.inputOpusDecoderProxy = await OpusDecoderProxy.create();
2799
2827
  this.inputDecodeChain = Promise.resolve();
2800
2828
  } catch (error) {
@@ -3185,6 +3213,7 @@ var AvatarController = class {
3185
3213
  logger.warn(`[AvatarController] Message chunk ${i + 1}: decode failed`);
3186
3214
  continue;
3187
3215
  }
3216
+ if (!this.serverTraceparent && result.traceparent) this.serverTraceparent = result.traceparent;
3188
3217
  allKeyframes.push(...result.keyframes);
3189
3218
  if (result.end) isEnd = true;
3190
3219
  } catch (error) {
@@ -3381,6 +3410,7 @@ var AvatarController = class {
3381
3410
  decodes: [],
3382
3411
  encodes: []
3383
3412
  };
3413
+ this.serverTraceparent = null;
3384
3414
  this.decodeSpanStart = null;
3385
3415
  this.decodeSpanBytes = 0;
3386
3416
  this.lastOpusGranule = -1;
@@ -4021,6 +4051,7 @@ var AvatarManager = class AvatarManager {
4021
4051
  const task = this.downloadQueue.shift();
4022
4052
  this.currentTask = task;
4023
4053
  logger.log(`[AvatarManager] Processing task: ${task.id} (${this.downloadQueue.length} items remaining)`);
4054
+ const taskStartTime = Date.now();
4024
4055
  try {
4025
4056
  const avatar = await this.executeTask(task);
4026
4057
  if (task.status === "cancelled") return;
@@ -4033,6 +4064,15 @@ var AvatarManager = class AvatarManager {
4033
4064
  task.status = "failed";
4034
4065
  const err = error instanceof Error ? error : new Error(String(error));
4035
4066
  task._loadTrace?.end(false, Date.now(), { error: err.message });
4067
+ logMetric("fetch_avatar_latency", Date.now() - taskStartTime, {
4068
+ resolution: "default",
4069
+ use_compressed_model: task.useCompressedModel,
4070
+ cache_hit: false,
4071
+ result: err instanceof AvatarError ? err.code : "unknown_error"
4072
+ }, {
4073
+ avatar_id: task.id,
4074
+ description: err.message
4075
+ });
4036
4076
  this.notifyAllRequests(task, {
4037
4077
  type: LoadProgress.failed,
4038
4078
  error: err
@@ -4094,7 +4134,7 @@ var AvatarManager = class AvatarManager {
4094
4134
  } else {
4095
4135
  logger.log(`[AvatarManager] Avatar ${id} cache invalid: updatedAt=${cachedUpdatedAt}->${newUpdatedAt}, modelType=${cachedModelType}->${requestedModelType}, reloading...`);
4096
4136
  this.avatarCache.delete(id);
4097
- const { PwaCacheManager } = await import("./pwa-cache-manager-BxeZI1BU.js").then((n) => n.n);
4137
+ const { PwaCacheManager } = await import("./pwa-cache-manager-C7su6HpW.js").then((n) => n.n);
4098
4138
  await PwaCacheManager.clearCharacterCache(id);
4099
4139
  }
4100
4140
  }
@@ -4138,7 +4178,8 @@ var AvatarManager = class AvatarManager {
4138
4178
  logMetric("fetch_avatar_latency", Date.now() - startTime, {
4139
4179
  resolution: "default",
4140
4180
  use_compressed_model: task.useCompressedModel,
4141
- cache_hit: resources.cacheHit
4181
+ cache_hit: resources.cacheHit,
4182
+ result: "success"
4142
4183
  }, { avatar_id: id });
4143
4184
  return avatar;
4144
4185
  }
@@ -48,7 +48,26 @@ export interface SpanGroup {
48
48
  * what lets the backend's spans join a round without threading state through;
49
49
  * reproducing that separately would mean two definitions of one wire contract.
50
50
  */
51
- export declare function startPlaybackTrace(conversationId: string, startTimeMs?: number, attrs?: Attributes): PlaybackTrace;
51
+ export declare function startPlaybackTrace(conversationId: string, startTimeMs?: number, attrs?: Attributes, serverTraceparent?: string): PlaybackTrace;
52
+ /**
53
+ * Read the W3C traceparent the driving service stamped on an animation
54
+ * message, without decoding its frames. Undefined when the message carries
55
+ * none, or is not parseable.
56
+ *
57
+ * For transports that hand the SDK an opaque animation payload and never see a
58
+ * request id — RTC being the case this exists for. There the round's id is
59
+ * minted locally and never travels upstream, so a trace_id derived from it has
60
+ * nothing to do with the server's, and one round reports as two unrelated
61
+ * traces. The traceparent riding the animation is what joins them; pass the
62
+ * result to `startPlaybackTrace`.
63
+ *
64
+ * Kept separate from decoding rather than folded into it: callers need this
65
+ * once per round while frames are decoded continuously.
66
+ *
67
+ * @param rawMessage the same bytes handed to the renderer — a serialized
68
+ * `driveningress.v2.Message`.
69
+ */
70
+ export declare function peekTraceparent(rawMessage: Uint8Array): string | undefined;
52
71
  /**
53
72
  * Record one measurement onto avatarkit's metric pipeline.
54
73
  *
@@ -1,5 +1,5 @@
1
- import { C as recordMetric$1, E as setSdkIdentity$1, g as clockSync } from "./logger-B_tTFAYq.js";
2
- import { o as startPlaybackTrace$1 } from "./otel-trace-DmmQrXv-.js";
1
+ import { o as startPlaybackTrace$1, u as Message } from "./otel-trace-D2py5nQo.js";
2
+ import { C as recordMetric$1, E as setSdkIdentity$1, g as clockSync } from "./logger-BCrlTIt2.js";
3
3
  //#region internal-telemetry.ts
4
4
  /**
5
5
  * Internal telemetry surface for the companion RTC SDK.
@@ -50,8 +50,33 @@ function isClockCalibrated() {
50
50
  * what lets the backend's spans join a round without threading state through;
51
51
  * reproducing that separately would mean two definitions of one wire contract.
52
52
  */
53
- function startPlaybackTrace(conversationId, startTimeMs, attrs = {}) {
54
- return startPlaybackTrace$1(conversationId, startTimeMs, attrs);
53
+ function startPlaybackTrace(conversationId, startTimeMs, attrs = {}, serverTraceparent) {
54
+ return startPlaybackTrace$1(conversationId, startTimeMs, attrs, serverTraceparent);
55
+ }
56
+ /**
57
+ * Read the W3C traceparent the driving service stamped on an animation
58
+ * message, without decoding its frames. Undefined when the message carries
59
+ * none, or is not parseable.
60
+ *
61
+ * For transports that hand the SDK an opaque animation payload and never see a
62
+ * request id — RTC being the case this exists for. There the round's id is
63
+ * minted locally and never travels upstream, so a trace_id derived from it has
64
+ * nothing to do with the server's, and one round reports as two unrelated
65
+ * traces. The traceparent riding the animation is what joins them; pass the
66
+ * result to `startPlaybackTrace`.
67
+ *
68
+ * Kept separate from decoding rather than folded into it: callers need this
69
+ * once per round while frames are decoded continuously.
70
+ *
71
+ * @param rawMessage the same bytes handed to the renderer — a serialized
72
+ * `driveningress.v2.Message`.
73
+ */
74
+ function peekTraceparent(rawMessage) {
75
+ try {
76
+ return Message.decode(rawMessage).serverResponseAnimation?.traceContext?.traceparent || void 0;
77
+ } catch {
78
+ return;
79
+ }
55
80
  }
56
81
  /**
57
82
  * Record one measurement onto avatarkit's metric pipeline.
@@ -93,4 +118,4 @@ function setSdkIdentity(identity) {
93
118
  setSdkIdentity$1(identity);
94
119
  }
95
120
  //#endregion
96
- export { isClockCalibrated, recordMetric, resolveMonoTimestamp, setSdkIdentity, startPlaybackTrace };
121
+ export { isClockCalibrated, peekTraceparent, recordMetric, resolveMonoTimestamp, setSdkIdentity, startPlaybackTrace };
@@ -15570,7 +15570,7 @@ async function writeToLocalLog(message, level, extra = {}) {
15570
15570
  try {
15571
15571
  const { shouldPersist, sanitized } = sanitizeForLocalLog(message);
15572
15572
  if (!shouldPersist) return;
15573
- const { AvatarSDK } = await import("./AvatarSDK-BMjjoYiZ.js").then((n) => n.n);
15573
+ const { AvatarSDK } = await import("./AvatarSDK-DCYDBMwd.js").then((n) => n.n);
15574
15574
  const version = AvatarSDK.version;
15575
15575
  const appId = idManager.getAppId();
15576
15576
  const userId = idManager.getUserId();