@spatius/avatarkit 1.3.5 → 1.3.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/CHANGELOG.md CHANGED
@@ -5,6 +5,19 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.3.7] - 2026-08-17
9
+
10
+ ### Fixed
11
+ - Internal telemetry only, no change to public API or runtime behaviour: diagnostic records now carry this SDK's own version alongside the reporting one. A companion SDK built on top of this one declares its own identity, which replaced the version outright, so records from those integrations gave no indication of which renderer produced them.
12
+ - Internal telemetry only, no change to public API or runtime behaviour: the client environment fields (page host, locale, screen and viewport size) are now available to companion SDKs, whose records previously carried none of them.
13
+
14
+ ## [1.3.6] - 2026-08-15
15
+
16
+ ### Fixed
17
+ - **Fixed the SDK continuing to send audio under an already-finished conversation id in direct mode.** After `send(audio, end=true)`, feeding new audio while that round had not started playing yet reused the same conversation id on the wire, so the driving service received new audio on a request it had already been told was over. A new round now always starts under a fresh id, whether or not the previous one had begun playing. Host mode never produced the symptom (it owns the id and has no uplink) but shared the same flaw internally and is aligned.
18
+ - Internal telemetry only, no change to public API or runtime behaviour: the connection identifier is now attached automatically to the SDK's diagnostic events and traces. It previously had to be passed by hand at each call site and reached only two of the event types, which made it impractical to line up client-side events with the driving service's own records for the same session.
19
+ - Internal telemetry only, no change to public API or runtime behaviour: widened the duration buckets for template and asset downloads. The previous ceilings sat well below what a cold start on a large template actually takes, so the slow tail — the part worth measuring — collapsed into a single overflow bucket and 11 seconds could not be told apart from 90.
20
+
8
21
  ## [1.3.5] - 2026-08-12
9
22
 
10
23
  ### Fixed
@@ -49550,6 +49550,7 @@ function buildTelemetryContext(event, level, contents) {
49550
49550
  const sessionToken = idManager.getSessionToken() ?? "";
49551
49551
  const context = {
49552
49552
  session_token_suffix: sessionToken ? sessionToken.slice(-8) : "",
49553
+ connection_id: idManager.getConnectionId() ?? "",
49553
49554
  ...clientContextFields(),
49554
49555
  ...contents
49555
49556
  };
@@ -49550,6 +49550,7 @@ function buildTelemetryContext(event, level, contents) {
49550
49550
  const sessionToken = idManager.getSessionToken() ?? "";
49551
49551
  const context = {
49552
49552
  session_token_suffix: sessionToken ? sessionToken.slice(-8) : "",
49553
+ connection_id: idManager.getConnectionId() ?? "",
49553
49554
  ...clientContextFields(),
49554
49555
  ...contents
49555
49556
  };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { n as __toESM, t as __commonJSMin } from "./rolldown-runtime-FDOR9p9I.js";
2
- import { $ as DEFAULT_REGION, A as clockSync, B as OTEL_LOGS_ENDPOINT, C as logMetric, D as monoMarkFrom, E as initializeOtel, F as recordHttpClientDuration, G as idManager, H as OTEL_STREAM_NAME, I as recordMetric, J as AvatarError, K as generateTraceId, L as getSdkPackage, M as hostOf, N as cleanupOtelMetrics, O as monoTimestamp, P as initializeOtelMetrics, Q as DEFAULT_OPUS_BITRATE, R as resolveSdkVersion, S as logEvent, T as cleanupOtel, U as OTEL_USERNAME, V as OTEL_PASSWORD, W as isDebugMode, X as ConnectionState, Y as AvatarState, Z as ConversationState, _ as logSink, a as startLoadTrace, at as LogLevel, b as getLogsFeatureFlag, c as AudioFormat, ct as TransitionType, d as MessageType, et as DEFAULT_REGION_REQUEST, f as TransportCompression, g as setLogLevel, h as logger, i as startInitTrace, it as LoadProgress, j as fetchBootstrap, k as resolveMarks, l as EgressType, lt as requireSDK, m as BinaryWriter, n as initializeOtelTrace, nt as ErrorCode, o as startPlaybackTrace, ot as RENDER_QUALITY_PARAMS, p as BinaryReader, q as AnimationType, r as startConnectTrace, rt as FrameStarvationMode, s as buildTraceparent, st as RenderQuality, t as cleanupOtelTrace, tt as DrivingServiceMode, u as Message, ut as setSDKRef, v as cleanupPostHog, w as updatePostHogPersonPropertiesForFlags, x as initializePostHog, y as clientContextFields } from "./otel-trace-CdspSqI0.js";
2
+ import { $ as DEFAULT_REGION, A as clockSync, B as OTEL_LOGS_ENDPOINT, C as logMetric, D as monoMarkFrom, E as initializeOtel, F as recordHttpClientDuration, G as idManager, H as OTEL_STREAM_NAME, I as recordMetric, J as AvatarError, K as generateTraceId, L as getSdkPackage, M as hostOf, N as cleanupOtelMetrics, O as monoTimestamp, P as initializeOtelMetrics, Q as DEFAULT_OPUS_BITRATE, R as resolveSdkVersion, S as logEvent, T as cleanupOtel, U as OTEL_USERNAME, V as OTEL_PASSWORD, W as isDebugMode, X as ConnectionState, Y as AvatarState, Z as ConversationState, _ as logSink, a as startLoadTrace, at as LogLevel, b as getLogsFeatureFlag, c as AudioFormat, ct as TransitionType, d as MessageType, et as DEFAULT_REGION_REQUEST, f as TransportCompression, g as setLogLevel, h as logger, i as startInitTrace, it as LoadProgress, j as fetchBootstrap, k as resolveMarks, l as EgressType, lt as requireSDK, m as BinaryWriter, n as initializeOtelTrace, nt as ErrorCode, o as startPlaybackTrace, ot as RENDER_QUALITY_PARAMS, p as BinaryReader, q as AnimationType, r as startConnectTrace, rt as FrameStarvationMode, s as buildTraceparent, st as RenderQuality, t as cleanupOtelTrace, tt as DrivingServiceMode, u as Message, ut as setSDKRef, v as cleanupPostHog, w as updatePostHogPersonPropertiesForFlags, x as initializePostHog, y as clientContextFields } from "./otel-trace-Y_BtH06z.js";
3
3
  //#region core/Avatar.ts
4
4
  var Avatar = class {
5
5
  id;
@@ -41912,7 +41912,7 @@ var OpusDecoderProxy = class OpusDecoderProxy {
41912
41912
  try {
41913
41913
  worker = new Worker(new URL(
41914
41914
  /* @vite-ignore */
41915
- "" + new URL("assets/OpusDecoderWorker.worker-BTHlnzwA.js", import.meta.url).href,
41915
+ "" + new URL("assets/OpusDecoderWorker.worker-DbdfH4qX.js", import.meta.url).href,
41916
41916
  "" + import.meta.url
41917
41917
  ), { type: "module" });
41918
41918
  } catch (err) {
@@ -45730,7 +45730,7 @@ var AvatarSDK = class {
45730
45730
  static _initializationState = "uninitialized";
45731
45731
  static _initializingPromise = null;
45732
45732
  static _configuration = null;
45733
- static _version = "1.3.5";
45733
+ static _version = "1.3.7";
45734
45734
  static _avatarCore = null;
45735
45735
  static _cachedDeviceScore = null;
45736
45736
  static _rendererBackend = null;
@@ -46295,7 +46295,7 @@ var OpusEncoderProxy = class OpusEncoderProxy {
46295
46295
  try {
46296
46296
  worker = new Worker(new URL(
46297
46297
  /* @vite-ignore */
46298
- "" + new URL("assets/OpusEncoderWorker.worker-DB_Lvnzc.js", import.meta.url).href,
46298
+ "" + new URL("assets/OpusEncoderWorker.worker-DVnsr0L5.js", import.meta.url).href,
46299
46299
  "" + import.meta.url
46300
46300
  ), { type: "module" });
46301
46301
  } catch (err) {
@@ -46704,7 +46704,6 @@ var AnimationWebSocketClient = class extends EventEmitter {
46704
46704
  logger.error("[AnimationWebSocketClient] Failed to send audio data:", message);
46705
46705
  logEvent("send_audio_failed", "error", {
46706
46706
  conversation_id: conversationId || "",
46707
- connection_id: idManager.getConnectionId() || "",
46708
46707
  description: message
46709
46708
  });
46710
46709
  this.emit("error", error);
@@ -46762,7 +46761,6 @@ var AnimationWebSocketClient = class extends EventEmitter {
46762
46761
  logger.error("[AnimationWebSocketClient] Failed to forward Opus audio:", message);
46763
46762
  logEvent("send_audio_failed", "error", {
46764
46763
  conversation_id: conversationId || "",
46765
- connection_id: idManager.getConnectionId() || "",
46766
46764
  description: message
46767
46765
  });
46768
46766
  this.emit("error", error);
@@ -46860,7 +46858,6 @@ var AnimationWebSocketClient = class extends EventEmitter {
46860
46858
  logger.error("[AnimationWebSocketClient] Failed to send Opus audio:", message);
46861
46859
  logEvent("send_audio_failed", "error", {
46862
46860
  conversation_id: conversationId || "",
46863
- connection_id: idManager.getConnectionId() || "",
46864
46861
  description: message
46865
46862
  });
46866
46863
  this.emit("error", error);
@@ -47028,7 +47025,6 @@ var AnimationWebSocketClient = class extends EventEmitter {
47028
47025
  const readyStateText = readyState === WebSocket.CONNECTING ? "CONNECTING" : readyState === WebSocket.OPEN ? "OPEN" : readyState === WebSocket.CLOSING ? "CLOSING" : readyState === WebSocket.CLOSED ? "CLOSED" : "UNKNOWN";
47029
47026
  logger.error(`[AnimationWebSocketClient] WebSocket error: readyState=${readyStateText}, url=${urlForLog}`);
47030
47027
  logEvent("websocket_error", "error", {
47031
- connection_id: idManager.getConnectionId() || "",
47032
47028
  ready_state: readyStateText,
47033
47029
  description: `WebSocket error (readyState: ${readyStateText})`
47034
47030
  });
@@ -47037,12 +47033,14 @@ var AnimationWebSocketClient = class extends EventEmitter {
47037
47033
  };
47038
47034
  this.ws.onclose = (event) => {
47039
47035
  const sessionDurationMs = this.connectionStartTime > 0 ? Date.now() - this.connectionStartTime : 0;
47036
+ const connectionId = idManager.getConnectionId() || "";
47040
47037
  logger.log("[AnimationWebSocketClient] WebSocket closed:", {
47041
47038
  code: event.code,
47042
47039
  reason: event.reason || "(no reason)",
47043
47040
  wasClean: event.wasClean,
47044
47041
  url: urlForLog,
47045
- session_duration_ms: sessionDurationMs
47042
+ session_duration_ms: sessionDurationMs,
47043
+ connection_id: connectionId
47046
47044
  });
47047
47045
  this.emit("disconnected", event.reason || "Connection closed");
47048
47046
  this.sessionConfigured = false;
@@ -47052,7 +47050,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
47052
47050
  case 4010:
47053
47051
  sdkErrorCode = ErrorCode.sessionTokenInvalid;
47054
47052
  logEvent("session_token_invalid", "warning", {
47055
- connection_id: idManager.getConnectionId() || "",
47053
+ connection_id: connectionId,
47056
47054
  description: reason || "Authentication failed",
47057
47055
  session_duration_ms: sessionDurationMs
47058
47056
  });
@@ -47060,7 +47058,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
47060
47058
  case 4001:
47061
47059
  sdkErrorCode = ErrorCode.insufficientBalance;
47062
47060
  logEvent("insufficient_balance", "warning", {
47063
- connection_id: idManager.getConnectionId() || "",
47061
+ connection_id: connectionId,
47064
47062
  description: reason || "Insufficient balance",
47065
47063
  session_duration_ms: sessionDurationMs
47066
47064
  });
@@ -47068,7 +47066,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
47068
47066
  case 4002:
47069
47067
  sdkErrorCode = ErrorCode.sessionTimeout;
47070
47068
  logEvent("session_timeout", "warning", {
47071
- connection_id: idManager.getConnectionId() || "",
47069
+ connection_id: connectionId,
47072
47070
  description: reason || "Session timeout",
47073
47071
  session_duration_ms: sessionDurationMs
47074
47072
  });
@@ -47076,14 +47074,14 @@ var AnimationWebSocketClient = class extends EventEmitter {
47076
47074
  case 4003:
47077
47075
  sdkErrorCode = ErrorCode.concurrentLimitExceeded;
47078
47076
  logEvent("concurrent_limit_exceeded", "warning", {
47079
- connection_id: idManager.getConnectionId() || "",
47077
+ connection_id: connectionId,
47080
47078
  description: reason || "Concurrent connection limit exceeded",
47081
47079
  session_duration_ms: sessionDurationMs
47082
47080
  });
47083
47081
  break;
47084
47082
  case 1006:
47085
47083
  logEvent("websocket_closed_abnormally", "error", {
47086
- connection_id: idManager.getConnectionId() || "",
47084
+ connection_id: connectionId,
47087
47085
  code: event.code,
47088
47086
  description: reason || "Connection closed abnormally",
47089
47087
  session_duration_ms: sessionDurationMs
@@ -47091,7 +47089,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
47091
47089
  break;
47092
47090
  case 1012:
47093
47091
  logEvent("service_restarted", "warning", {
47094
- connection_id: idManager.getConnectionId() || "",
47092
+ connection_id: connectionId,
47095
47093
  description: reason || "Service restart",
47096
47094
  session_duration_ms: sessionDurationMs
47097
47095
  });
@@ -47100,7 +47098,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
47100
47098
  if (this.connectStartMs > 0) {
47101
47099
  const connectResult = sdkErrorCode ?? (event.code === 1006 ? "closed_abnormally" : "closed_before_confirm");
47102
47100
  logMetric("ws_connect_latency", Date.now() - this.connectStartMs, { result: connectResult }, {
47103
- connection_id: idManager.getConnectionId() || "",
47101
+ connection_id: connectionId,
47104
47102
  close_code: event.code,
47105
47103
  description: reason || `Closed with code ${event.code}`
47106
47104
  });
@@ -47109,7 +47107,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
47109
47107
  if (sdkErrorCode) this.emit("error", new AvatarError(reason || `WebSocket connection failed with code ${event.code}`, sdkErrorCode));
47110
47108
  else if (event.code !== 1e3) {
47111
47109
  logEvent("websocket_closed_unexpected", "error", {
47112
- connection_id: idManager.getConnectionId() || "",
47110
+ connection_id: connectionId,
47113
47111
  code: event.code,
47114
47112
  description: reason || `Unexpected close (code: ${event.code})`,
47115
47113
  session_duration_ms: sessionDurationMs
@@ -47195,7 +47193,7 @@ var AnimationWebSocketClient = class extends EventEmitter {
47195
47193
  } else logger.log("[AnimationWebSocketClient] Session confirmed by server");
47196
47194
  if (this.connectStartMs > 0) {
47197
47195
  const confirmMs = Date.now();
47198
- logMetric("ws_connect_latency", confirmMs - this.connectStartMs, { result: "success" }, { connection_id: idManager.getConnectionId() || "" });
47196
+ logMetric("ws_connect_latency", confirmMs - this.connectStartMs, { result: "success" }, {});
47199
47197
  this.emitConnectTrace(confirmMs);
47200
47198
  this.connectStartMs = 0;
47201
47199
  }
@@ -47463,7 +47461,6 @@ var NetworkLayer = class {
47463
47461
  logger.error(`[NetworkLayer] Server error: conversationId=${conversationId}, code=${message.serverError.code}, message=${message.serverError.message}`);
47464
47462
  logEvent("message_error", "error", {
47465
47463
  conversation_id: conversationId,
47466
- connection_id: idManager.getConnectionId() || "",
47467
47464
  description: message.serverError.message || `Server error: code=${message.serverError.code}`
47468
47465
  });
47469
47466
  const httpStatusCode = message.serverError.code;
@@ -47474,7 +47471,6 @@ var NetworkLayer = class {
47474
47471
  sdkErrorCode = ErrorCode.sessionTokenExpired;
47475
47472
  logEvent("session_token_expired", "warning", {
47476
47473
  avatar_id: this.dataController.getAvatarId(),
47477
- connection_id: idManager.getConnectionId() || "",
47478
47474
  description: errorMessage,
47479
47475
  session_duration_ms: sessionDurationMs
47480
47476
  });
@@ -47482,7 +47478,6 @@ var NetworkLayer = class {
47482
47478
  sdkErrorCode = ErrorCode.sessionTokenInvalid;
47483
47479
  logEvent("session_token_invalid", "warning", {
47484
47480
  avatar_id: this.dataController.getAvatarId(),
47485
- connection_id: idManager.getConnectionId() || "",
47486
47481
  description: errorMessage,
47487
47482
  session_duration_ms: sessionDurationMs
47488
47483
  });
@@ -47532,10 +47527,7 @@ var NetworkLayer = class {
47532
47527
  this.heartbeatFailureCount++;
47533
47528
  logger.warn(`[NetworkLayer] Driving service heartbeat failed (count: ${this.heartbeatFailureCount})`);
47534
47529
  if (this.heartbeatFailureCount >= 3) {
47535
- logEvent("heartbeat_failed", "warning", {
47536
- connection_id: idManager.getConnectionId() || "",
47537
- description: `Driving service heartbeat failed ${this.heartbeatFailureCount} times`
47538
- });
47530
+ logEvent("heartbeat_failed", "warning", { description: `Driving service heartbeat failed ${this.heartbeatFailureCount} times` });
47539
47531
  this.heartbeatFailureCount = 0;
47540
47532
  }
47541
47533
  }
@@ -47543,10 +47535,7 @@ var NetworkLayer = class {
47543
47535
  this.heartbeatFailureCount++;
47544
47536
  logger.warn(`[NetworkLayer] Heartbeat check error (count: ${this.heartbeatFailureCount}):`, error instanceof Error ? error.message : String(error));
47545
47537
  if (this.heartbeatFailureCount >= 3) {
47546
- logEvent("heartbeat_failed", "warning", {
47547
- connection_id: idManager.getConnectionId() || "",
47548
- description: `Heartbeat check error: ${error instanceof Error ? error.message : String(error)}`
47549
- });
47538
+ logEvent("heartbeat_failed", "warning", { description: `Heartbeat check error: ${error instanceof Error ? error.message : String(error)}` });
47550
47539
  this.heartbeatFailureCount = 0;
47551
47540
  }
47552
47541
  }
@@ -48476,7 +48465,11 @@ var AvatarController = class {
48476
48465
  this.onError?.(new AvatarError("Network layer not available", ErrorCode.networkLayerNotAvailable));
48477
48466
  return null;
48478
48467
  }
48479
- if (this.reqEnd && this.isPlaying && this.currentConversationId) this.interrupt();
48468
+ if (this.reqEnd && this.currentConversationId) if (this.isPlaying) this.interrupt();
48469
+ else {
48470
+ this.resetConversationIdState();
48471
+ this.clearPlaybackData();
48472
+ }
48480
48473
  if (!this.currentConversationId) {
48481
48474
  this.currentConversationId = this.generateAndLogNewConversationId();
48482
48475
  this.reqEnd = false;
@@ -48617,8 +48610,12 @@ var AvatarController = class {
48617
48610
  this.onError?.(error);
48618
48611
  return null;
48619
48612
  }
48620
- if (this.reqEnd && this.isPlaying && this.currentConversationId) {
48621
- this.interrupt();
48613
+ if (this.reqEnd && this.currentConversationId) {
48614
+ if (this.isPlaying) this.interrupt();
48615
+ else {
48616
+ this.resetConversationIdState();
48617
+ this.clearPlaybackData();
48618
+ }
48622
48619
  this.currentConversationId = this.generateAndLogNewConversationId();
48623
48620
  this.reqEnd = false;
48624
48621
  }
@@ -49373,7 +49370,6 @@ var AvatarController = class {
49373
49370
  logEvent("fallback_mode_entered", "warning", {
49374
49371
  avatar_id: this.avatar.id,
49375
49372
  reason,
49376
- connection_id: idManager.getConnectionId() || "",
49377
49373
  conversation_id: this.currentConversationId || ""
49378
49374
  });
49379
49375
  this.emit("playFallback");
@@ -79,6 +79,24 @@ export declare function peekTraceparent(rawMessage: Uint8Array): string | undefi
79
79
  * dropped before it is sent.
80
80
  */
81
81
  export declare function recordMetric(name: string, value: number, attributes?: Attributes): void;
82
+ /**
83
+ * The client environment fields this SDK stamps on every OTel log record —
84
+ * `host`, `domain`, `url`, `pathname`, `referrer`, `user_agent`, `locale`,
85
+ * screen/viewport size and `timezone`.
86
+ *
87
+ * Shared with the RTC SDK rather than re-derived there. These are record-level
88
+ * fields, not Resource attributes: they are read from `window.location` at emit
89
+ * time because `url`/`pathname` change as a single-page app routes. Sharing the
90
+ * OTel providers therefore does not carry them across — the RTC SDK emits
91
+ * through its own logger and would report no `host` at all, which is what
92
+ * prompted this export. Re-implementing the collection on that side would let
93
+ * the two drift apart in field names and in how each value is read, and the
94
+ * backend aggregates on exactly these names.
95
+ *
96
+ * Call at emit time, once per record; spread the result before the caller's own
97
+ * properties so an explicit value at the call site still wins.
98
+ */
99
+ export declare function clientContextFields(): Record<string, string | number>;
82
100
  /**
83
101
  * Declare which SDK these records come from, as the `sdk.package` and
84
102
  * `sdk.version` resource attributes.
@@ -1,4 +1,4 @@
1
- import { A as clockSync, I as recordMetric$1, o as startPlaybackTrace$1, u as Message, z as setSdkIdentity$1 } from "./otel-trace-CdspSqI0.js";
1
+ import { A as clockSync, I as recordMetric$1, o as startPlaybackTrace$1, u as Message, y as clientContextFields$1, z as setSdkIdentity$1 } from "./otel-trace-Y_BtH06z.js";
2
2
  //#region internal-telemetry.ts
3
3
  /**
4
4
  * Internal telemetry surface for the companion RTC SDK.
@@ -91,6 +91,26 @@ function recordMetric(name, value, attributes = {}) {
91
91
  recordMetric$1(name, value, attributes);
92
92
  }
93
93
  /**
94
+ * The client environment fields this SDK stamps on every OTel log record —
95
+ * `host`, `domain`, `url`, `pathname`, `referrer`, `user_agent`, `locale`,
96
+ * screen/viewport size and `timezone`.
97
+ *
98
+ * Shared with the RTC SDK rather than re-derived there. These are record-level
99
+ * fields, not Resource attributes: they are read from `window.location` at emit
100
+ * time because `url`/`pathname` change as a single-page app routes. Sharing the
101
+ * OTel providers therefore does not carry them across — the RTC SDK emits
102
+ * through its own logger and would report no `host` at all, which is what
103
+ * prompted this export. Re-implementing the collection on that side would let
104
+ * the two drift apart in field names and in how each value is read, and the
105
+ * backend aggregates on exactly these names.
106
+ *
107
+ * Call at emit time, once per record; spread the result before the caller's own
108
+ * properties so an explicit value at the call site still wins.
109
+ */
110
+ function clientContextFields() {
111
+ return clientContextFields$1();
112
+ }
113
+ /**
94
114
  * Declare which SDK these records come from, as the `sdk.package` and
95
115
  * `sdk.version` resource attributes.
96
116
  *
@@ -117,4 +137,4 @@ function setSdkIdentity(identity) {
117
137
  setSdkIdentity$1(identity);
118
138
  }
119
139
  //#endregion
120
- export { isClockCalibrated, peekTraceparent, recordMetric, resolveMonoTimestamp, setSdkIdentity, startPlaybackTrace };
140
+ export { clientContextFields, isClockCalibrated, peekTraceparent, recordMetric, resolveMonoTimestamp, setSdkIdentity, startPlaybackTrace };
@@ -14583,6 +14583,11 @@ var HTTP_CLIENT_DURATION_METRIC = "http.client.request.duration";
14583
14583
  * (浮点 duration 会被后端拒/丢),因此值与桶统一用整数毫秒,不用浮点秒。
14584
14584
  * 桶经后台确认调整:去掉 100ms 以下分级(网络 rt 极少落在此区、无区分价值),
14585
14585
  * 并在 1000~5000ms 高区段加密(2000/3000/4000)以便看清慢请求分布。(与 android/iOS 一致。)
14586
+ *
14587
+ * 5 秒之上再加 10/30/60/120 秒:这是所有 HTTP 请求共用的一条 metric(靠 operation
14588
+ * 标签区分),其中 `/assets/template` 是几十 MB 的大文件下载,实测约三成样本超过
14589
+ * 5 秒——原先全部挤进 +Inf,是 6 秒还是 60 秒完全看不出来。前段分档不变,API 请求
14590
+ * 的分辨率不受影响。
14586
14591
  */
14587
14592
  var HTTP_NETWORK_BUCKETS_MS = [
14588
14593
  100,
@@ -14592,7 +14597,11 @@ var HTTP_NETWORK_BUCKETS_MS = [
14592
14597
  2e3,
14593
14598
  3e3,
14594
14599
  4e3,
14595
- 5e3
14600
+ 5e3,
14601
+ 1e4,
14602
+ 3e4,
14603
+ 6e4,
14604
+ 12e4
14596
14605
  ];
14597
14606
  /**
14598
14607
  * 播放指标的桶。默认桶(0/5/10/25/50/…/10000)对这批指标毫无分辨率:
@@ -14863,6 +14872,14 @@ var BUCKET_PROFILES = [
14863
14872
  ["playback_latency_anim_0_ms", ANIM_LATENCY_BUCKETS_MS],
14864
14873
  ["playback_latency_anim_1_ms", ANIM_LATENCY_BUCKETS_MS],
14865
14874
  ["playback_latency_anim_2_ms", ANIM_LATENCY_BUCKETS_MS],
14875
+ ["template_resources_load_measure", [
14876
+ 1e3,
14877
+ 1e4,
14878
+ 2e4,
14879
+ 3e4,
14880
+ 6e4,
14881
+ 12e4
14882
+ ]],
14866
14883
  ["rtc_playback_avg_fps", RTC_FPS_BUCKETS],
14867
14884
  ["rtc_playback_frame_count", RTC_FRAME_COUNT_BUCKETS],
14868
14885
  ["rtc_playback_skipped_frames", RTC_LOST_FRAME_BUCKETS],
@@ -14943,6 +14960,7 @@ function initializeOtelMetrics(version, resourceAttrs) {
14943
14960
  "sdk.version": resolveSdkVersion(sdkVersion$3),
14944
14961
  "sdk.platform": "web",
14945
14962
  "sdk.package": getSdkPackage(),
14963
+ "render_sdk_version": sdkVersion$3,
14946
14964
  "app_id": resourceAttrs.appId || "",
14947
14965
  "region": resourceAttrs.region,
14948
14966
  "dsm": resourceAttrs.dsm
@@ -15701,6 +15719,7 @@ function initializeOtel(version, resourceAttrs) {
15701
15719
  "sdk.version": resolveSdkVersion(sdkVersion$2),
15702
15720
  "sdk.platform": "web",
15703
15721
  "sdk.package": getSdkPackage(),
15722
+ "render_sdk_version": sdkVersion$2,
15704
15723
  "app_id": resourceAttrs.appId || "",
15705
15724
  "region": resourceAttrs.region,
15706
15725
  "dsm": resourceAttrs.dsm
@@ -16234,6 +16253,7 @@ function buildTelemetryContext(event, level, contents) {
16234
16253
  const sessionToken = idManager.getSessionToken() ?? "";
16235
16254
  const context = {
16236
16255
  session_token_suffix: sessionToken ? sessionToken.slice(-8) : "",
16256
+ connection_id: idManager.getConnectionId() ?? "",
16237
16257
  ...clientContextFields(),
16238
16258
  ...contents
16239
16259
  };
@@ -20371,6 +20391,7 @@ function initializeOtelTrace(version, resourceAttrs) {
20371
20391
  "sdk.version": resolveSdkVersion(sdkVersion),
20372
20392
  "sdk.platform": "web",
20373
20393
  "sdk.package": getSdkPackage(),
20394
+ "render_sdk_version": sdkVersion,
20374
20395
  "app_id": resourceAttrs.appId || "",
20375
20396
  "region": resourceAttrs.region,
20376
20397
  "dsm": resourceAttrs.dsm,
@@ -20434,6 +20455,7 @@ function startInitTrace(sessionId, startTimeMs, attrs = {}) {
20434
20455
  startTime: startTimeMs,
20435
20456
  attributes: {
20436
20457
  session_id: sessionId,
20458
+ connection_id: idManager.getConnectionId() ?? "",
20437
20459
  ...attrs
20438
20460
  }
20439
20461
  }, ROOT_CONTEXT);
@@ -20471,6 +20493,7 @@ function startLoadTrace(avatarId, startTimeMs, attrs = {}) {
20471
20493
  attributes: {
20472
20494
  avatar_id: avatarId,
20473
20495
  session_id: idManager.getSessionId(),
20496
+ connection_id: idManager.getConnectionId() ?? "",
20474
20497
  ...attrs
20475
20498
  }
20476
20499
  }, ROOT_CONTEXT);
@@ -20573,6 +20596,7 @@ function startPlaybackTrace(conversationId, startTimeMs, attrs = {}, serverTrace
20573
20596
  attributes: {
20574
20597
  conversation_id: conversationId,
20575
20598
  session_id: idManager.getSessionId(),
20599
+ connection_id: idManager.getConnectionId() ?? "",
20576
20600
  ...attrs
20577
20601
  },
20578
20602
  ...typeof startTimeMs === "number" ? { startTime: startTimeMs } : {}
@@ -20582,6 +20606,7 @@ function startPlaybackTrace(conversationId, startTimeMs, attrs = {}, serverTrace
20582
20606
  attributes: {
20583
20607
  conversation_id: conversationId,
20584
20608
  session_id: idManager.getSessionId(),
20609
+ connection_id: idManager.getConnectionId() ?? "",
20585
20610
  ...attrs
20586
20611
  },
20587
20612
  ...typeof startTimeMs === "number" ? { startTime: startTimeMs } : {}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@spatius/avatarkit",
3
3
  "type": "module",
4
- "version": "1.3.5",
4
+ "version": "1.3.7",
5
5
  "packageManager": "pnpm@10.18.2",
6
6
  "description": "AvatarKit — real-time, audio-driven avatar rendering SDK for Web.",
7
7
  "homepage": "https://spatius.ai/",