@spatius/avatarkit 1.3.8 → 1.3.9

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,4 +1,26 @@
1
- import { n as __toESM, t as __commonJSMin } from "./rolldown-runtime-FDOR9p9I.js";
1
+ //#region \0rolldown/runtime.js
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
11
+ key = keys[i];
12
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
13
+ get: ((k) => from[k]).bind(null, key),
14
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
15
+ });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
20
+ value: mod,
21
+ enumerable: true
22
+ }) : target, mod));
23
+ //#endregion
2
24
  //#region core/sdk-ref.ts
3
25
  var ref = null;
4
26
  /** @internal 仅供 AvatarSDK 在自身模块求值时回填。 */
@@ -1292,8 +1314,6 @@ var AvatarState = /* @__PURE__ */ function(AvatarState) {
1292
1314
  return AvatarState;
1293
1315
  }({});
1294
1316
  var ErrorCode = /* @__PURE__ */ function(ErrorCode) {
1295
- /** AppID not recognized (reserved, future appID validation logic) */
1296
- ErrorCode["appIDUnrecognized"] = "appIDUnrecognized";
1297
1317
  /** Session Token invalid (WebSocket close code 4010) */
1298
1318
  ErrorCode["sessionTokenInvalid"] = "sessionTokenInvalid";
1299
1319
  /** Session Token expired (WebSocket close code 4010) */
@@ -1312,10 +1332,17 @@ var ErrorCode = /* @__PURE__ */ function(ErrorCode) {
1312
1332
  ErrorCode["failedToDownloadAvatarAssets"] = "failedToDownloadAvatarAssets";
1313
1333
  /** Avatar asset compatibility_flags not supported by this SDK version (upgrade SDK) */
1314
1334
  ErrorCode["unsupportedAvatarAsset"] = "unsupportedAvatarAsset";
1335
+ /**
1336
+ * Neither WebGL2 nor WebGPU is available, so the avatar cannot be drawn at all.
1337
+ * Typically hardware acceleration is disabled in the browser, the GPU driver is
1338
+ * blocklisted, or the page runs in a restricted iframe. Deterministic — no point
1339
+ * retrying; tell the user to enable graphics acceleration.
1340
+ */
1341
+ ErrorCode["renderNotSupported"] = "renderNotSupported";
1342
+ /** Render system failed to initialize for a reason other than missing WebGL2/WebGPU */
1343
+ ErrorCode["renderInitFailed"] = "renderInitFailed";
1315
1344
  /** WebSocket connection error (handshake failure, network error) */
1316
1345
  ErrorCode["websocketError"] = "websocketError";
1317
- /** WebSocket connection closed abnormally (close code 1006) */
1318
- ErrorCode["websocketClosedAbnormally"] = "websocketClosedAbnormally";
1319
1346
  /** WebSocket closed with unexpected close code */
1320
1347
  ErrorCode["websocketClosedUnexpected"] = "websocketClosedUnexpected";
1321
1348
  /** Session timeout (WebSocket close code 4002) */
@@ -1328,8 +1355,6 @@ var ErrorCode = /* @__PURE__ */ function(ErrorCode) {
1328
1355
  ErrorCode["playbackStartFailed"] = "playbackStartFailed";
1329
1356
  /** Playback initialization failed */
1330
1357
  ErrorCode["playbackInitFailed"] = "playbackInitFailed";
1331
- /** Audio-only playback initialization failed */
1332
- ErrorCode["audioOnlyInitFailed"] = "audioOnlyInitFailed";
1333
1358
  /** No audio data to play */
1334
1359
  ErrorCode["noAudio"] = "noAudio";
1335
1360
  /**
@@ -1355,93 +1380,671 @@ var AvatarError = class extends Error {
1355
1380
  this.name = "AvatarError";
1356
1381
  }
1357
1382
  };
1358
- //#endregion
1359
- //#region node_modules/.pnpm/posthog-js@1.422.5_react@19.2.4/node_modules/posthog-js/dist/module.js
1360
- var t = "undefined" != typeof window ? window : void 0;
1361
- var i = "undefined" != typeof globalThis ? globalThis : t;
1362
- var e = null == i ? void 0 : i.navigator;
1363
- var r = null == i ? void 0 : i.document;
1364
- var s = null == i ? void 0 : i.location;
1365
- var n = null == i ? void 0 : i.fetch;
1366
- var o = null != i && i.XMLHttpRequest && "withCredentials" in new i.XMLHttpRequest() ? i.XMLHttpRequest : void 0;
1367
- var a = null == i ? void 0 : i.AbortController;
1368
- var l = null == i ? void 0 : i.CompressionStream;
1369
- var h = null == e ? void 0 : e.userAgent;
1370
- function u() {
1371
- return !(!t || !1 === t.navigator.onLine);
1372
- }
1373
- var d = "undefined" != typeof globalThis ? globalThis : t;
1374
- d && "undefined" == typeof self && (d.self = d), d && "undefined" == typeof File && (d.File = function() {});
1375
- var v = null != t ? t : {};
1376
- var c = {
1377
- DEBUG: !1,
1378
- LIB_VERSION: "0.7.0",
1379
- LIB_NAME: "browser-common"
1380
- };
1381
- function f(t, i, e, r, s, n, o) {
1382
- try {
1383
- var a = t[n](o), l = a.value;
1384
- } catch (t) {
1385
- e(t);
1386
- return;
1383
+ var logSink = class LogSink {
1384
+ static instance = null;
1385
+ db = null;
1386
+ dbName = "avatarkit_logs";
1387
+ storeName = "logs";
1388
+ version = 1;
1389
+ trimThreshold = 5e3;
1390
+ trimBufferSize = 1e3;
1391
+ isFlushing = false;
1392
+ constructor() {}
1393
+ static getInstance() {
1394
+ if (!LogSink.instance) LogSink.instance = new LogSink();
1395
+ return LogSink.instance;
1387
1396
  }
1388
- a.done ? i(l) : Promise.resolve(l).then(r, s);
1389
- }
1390
- function p(t) {
1391
- return function() {
1392
- var i = this, e = arguments;
1393
- return new Promise((function(r, s) {
1394
- var n = t.apply(i, e);
1395
- function o(t) {
1396
- f(n, r, s, o, a, "next", t);
1397
- }
1398
- function a(t) {
1399
- f(n, r, s, o, a, "throw", t);
1397
+ /**
1398
+ * Initialize IndexedDB
1399
+ */
1400
+ async initialize() {
1401
+ if (this.db) return;
1402
+ return new Promise((resolve, reject) => {
1403
+ const request = indexedDB.open(this.dbName, this.version);
1404
+ request.onerror = () => {
1405
+ reject(/* @__PURE__ */ new Error("Failed to open IndexedDB"));
1406
+ };
1407
+ request.onsuccess = () => {
1408
+ this.db = request.result;
1409
+ resolve();
1410
+ };
1411
+ request.onupgradeneeded = (event) => {
1412
+ const db = event.target.result;
1413
+ if (!db.objectStoreNames.contains(this.storeName)) db.createObjectStore(this.storeName, {
1414
+ keyPath: "id",
1415
+ autoIncrement: true
1416
+ }).createIndex("ts", "ts", { unique: false });
1417
+ };
1418
+ });
1419
+ }
1420
+ /**
1421
+ * Append log entry to IndexedDB
1422
+ */
1423
+ async append(entry) {
1424
+ if (!this.db) try {
1425
+ await this.initialize();
1426
+ } catch {
1427
+ return;
1428
+ }
1429
+ if (!this.db) return;
1430
+ try {
1431
+ const store = this.db.transaction([this.storeName], "readwrite").objectStore(this.storeName);
1432
+ await new Promise((resolve, reject) => {
1433
+ const request = store.add(entry);
1434
+ request.onsuccess = () => resolve();
1435
+ request.onerror = () => reject(/* @__PURE__ */ new Error("Failed to add log"));
1436
+ });
1437
+ this.getCount().then((count) => {
1438
+ if (count > this.trimThreshold) this.trim().catch(() => {});
1439
+ }).catch(() => {});
1440
+ } catch (error) {}
1441
+ }
1442
+ /**
1443
+ * Get total log count
1444
+ */
1445
+ async getCount() {
1446
+ if (!this.db) return 0;
1447
+ return new Promise((resolve, reject) => {
1448
+ const request = this.db.transaction([this.storeName], "readonly").objectStore(this.storeName).count();
1449
+ request.onsuccess = () => {
1450
+ resolve(request.result);
1451
+ };
1452
+ request.onerror = () => {
1453
+ reject(/* @__PURE__ */ new Error("Failed to count logs"));
1454
+ };
1455
+ });
1456
+ }
1457
+ /**
1458
+ * Trim logs to keep only recent entries
1459
+ */
1460
+ async trim() {
1461
+ if (!this.db || this.isFlushing) return;
1462
+ try {
1463
+ const store = this.db.transaction([this.storeName], "readwrite").objectStore(this.storeName);
1464
+ const getAllRequest = store.getAll();
1465
+ const entries = await new Promise((resolve, reject) => {
1466
+ getAllRequest.onsuccess = () => {
1467
+ resolve(getAllRequest.result);
1468
+ };
1469
+ getAllRequest.onerror = () => {
1470
+ reject(/* @__PURE__ */ new Error("Failed to get logs"));
1471
+ };
1472
+ });
1473
+ const keepCount = this.trimThreshold - this.trimBufferSize;
1474
+ if (entries.length <= keepCount) return;
1475
+ entries.sort((a, b) => a.ts - b.ts);
1476
+ const toDelete = entries.slice(0, entries.length - keepCount);
1477
+ for (const entry of toDelete) if (entry.id !== void 0) await new Promise((resolve, reject) => {
1478
+ const deleteRequest = store.delete(entry.id);
1479
+ deleteRequest.onsuccess = () => resolve();
1480
+ deleteRequest.onerror = () => reject(/* @__PURE__ */ new Error("Failed to delete log"));
1481
+ });
1482
+ } catch (error) {}
1483
+ }
1484
+ /**
1485
+ * Flush logs to server
1486
+ */
1487
+ async flush() {
1488
+ if (!this.db || this.isFlushing) return;
1489
+ this.isFlushing = true;
1490
+ try {
1491
+ const getAllRequest = this.db.transaction([this.storeName], "readonly").objectStore(this.storeName).getAll();
1492
+ const entries = await new Promise((resolve, reject) => {
1493
+ getAllRequest.onsuccess = () => {
1494
+ resolve(getAllRequest.result);
1495
+ };
1496
+ getAllRequest.onerror = () => {
1497
+ reject(/* @__PURE__ */ new Error("Failed to get logs"));
1498
+ };
1499
+ });
1500
+ if (entries.length === 0) {
1501
+ this.isFlushing = false;
1502
+ return;
1400
1503
  }
1401
- o(void 0);
1402
- }));
1403
- };
1404
- }
1405
- function _() {
1406
- return _ = Object.assign ? Object.assign.bind() : function(t) {
1407
- for (var i = 1; arguments.length > i; i++) {
1408
- var e = arguments[i];
1409
- for (var r in e) ({}).hasOwnProperty.call(e, r) && (t[r] = e[r]);
1504
+ const requestBody = { logs: entries.map((entry) => ({
1505
+ ...entry,
1506
+ extra: {
1507
+ ...entry.extra,
1508
+ platform: "Web"
1509
+ }
1510
+ })) };
1511
+ const jsonData = JSON.stringify(requestBody);
1512
+ const gzippedData = await this.gzip(jsonData);
1513
+ const response = await fetch("https://hogtool.spatialwalk.ai/batch-upload-log", {
1514
+ method: "POST",
1515
+ headers: {
1516
+ "Content-Type": "application/json",
1517
+ "Content-Encoding": "gzip"
1518
+ },
1519
+ body: gzippedData,
1520
+ signal: AbortSignal.timeout(15e3)
1521
+ });
1522
+ if (!response.ok) throw new Error(`Failed to upload logs: ${response.status} ${response.statusText}`);
1523
+ await this.clearFirst(entries.length);
1524
+ } catch (error) {
1525
+ console.warn("[LogSink] Failed to flush logs:", error);
1526
+ throw error;
1527
+ } finally {
1528
+ this.isFlushing = false;
1410
1529
  }
1411
- return t;
1412
- }, _.apply(null, arguments);
1413
- }
1414
- function g(t, i) {
1415
- if (null == t) return {};
1416
- var e = {};
1417
- for (var r in t) if ({}.hasOwnProperty.call(t, r)) {
1418
- if (-1 !== i.indexOf(r)) continue;
1419
- e[r] = t[r];
1420
1530
  }
1421
- return e;
1422
- }
1423
- var m = (t) => {
1424
- if ("string" != typeof t) return t;
1425
- try {
1426
- return JSON.parse(t);
1427
- } catch (i) {
1428
- return t;
1531
+ /**
1532
+ * Clear first N log entries
1533
+ */
1534
+ async clearFirst(count) {
1535
+ if (!this.db || count <= 0) return;
1536
+ try {
1537
+ const store = this.db.transaction([this.storeName], "readwrite").objectStore(this.storeName);
1538
+ const getAllRequest = store.getAll();
1539
+ const entries = await new Promise((resolve, reject) => {
1540
+ getAllRequest.onsuccess = () => {
1541
+ resolve(getAllRequest.result);
1542
+ };
1543
+ getAllRequest.onerror = () => {
1544
+ reject(/* @__PURE__ */ new Error("Failed to get logs"));
1545
+ };
1546
+ });
1547
+ entries.sort((a, b) => a.ts - b.ts);
1548
+ const toDelete = entries.slice(0, count);
1549
+ for (const entry of toDelete) if (entry.id !== void 0) await new Promise((resolve, reject) => {
1550
+ const deleteRequest = store.delete(entry.id);
1551
+ deleteRequest.onsuccess = () => resolve();
1552
+ deleteRequest.onerror = () => reject(/* @__PURE__ */ new Error("Failed to delete log"));
1553
+ });
1554
+ } catch (error) {}
1429
1555
  }
1430
- };
1431
- function y(t) {
1432
- return "string" == typeof t || t;
1433
- }
1434
- function b(t) {
1435
- return "string" == typeof t ? t : void 0;
1436
- }
1437
- var w = [
1438
- "$feature_flag",
1439
- "$feature_flag_response",
1440
- "$feature_flag_has_experiment",
1441
- "$feature_flag_id",
1442
- "$feature_flag_version",
1443
- "$feature_flag_reason",
1444
- "$feature_flag_request_id",
1556
+ /**
1557
+ * Gzip string data
1558
+ */
1559
+ async gzip(data) {
1560
+ try {
1561
+ const encoded = new TextEncoder().encode(data);
1562
+ const compressedStream = new ReadableStream({ start(controller) {
1563
+ controller.enqueue(encoded);
1564
+ controller.close();
1565
+ } }).pipeThrough(new CompressionStream("gzip"));
1566
+ return await new Response(compressedStream).blob();
1567
+ } catch (error) {
1568
+ console.error("[LogSink] gzip() error:", error);
1569
+ throw error;
1570
+ }
1571
+ }
1572
+ }.getInstance();
1573
+ //#endregion
1574
+ //#region node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/url-alphabet/index.js
1575
+ var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
1576
+ //#endregion
1577
+ //#region node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.browser.js
1578
+ var random = (bytes) => crypto.getRandomValues(new Uint8Array(bytes));
1579
+ var customRandom = (alphabet, defaultSize, getRandom) => {
1580
+ let mask = (2 << Math.log2(alphabet.length - 1)) - 1;
1581
+ let step = -~(1.6 * mask * defaultSize / alphabet.length);
1582
+ return (size = defaultSize) => {
1583
+ let id = "";
1584
+ while (true) {
1585
+ let bytes = getRandom(step);
1586
+ let j = step | 0;
1587
+ while (j--) {
1588
+ id += alphabet[bytes[j] & mask] || "";
1589
+ if (id.length >= size) return id;
1590
+ }
1591
+ }
1592
+ };
1593
+ };
1594
+ var customAlphabet = (alphabet, size = 21) => customRandom(alphabet, size | 0, random);
1595
+ var nanoid$2 = (size = 21) => {
1596
+ let id = "";
1597
+ let bytes = crypto.getRandomValues(new Uint8Array(size |= 0));
1598
+ while (size--) id += urlAlphabet[bytes[size] & 63];
1599
+ return id;
1600
+ };
1601
+ //#endregion
1602
+ //#region utils/client-id.ts
1603
+ /**
1604
+ * Client ID management utility
1605
+ * Used to generate and persist unique device identifier
1606
+ * @internal
1607
+ */
1608
+ var CLIENT_ID_STORAGE_KEY = "spavatar_client_id";
1609
+ /**
1610
+ * Get or create client_id
1611
+ * - If exists in localStorage, return existing client_id
1612
+ * - If not exists, generate new client_id and store to localStorage
1613
+ * @returns client_id string
1614
+ * @internal
1615
+ */
1616
+ function getOrCreateClientId() {
1617
+ try {
1618
+ const stored = localStorage.getItem(CLIENT_ID_STORAGE_KEY);
1619
+ if (stored) return stored;
1620
+ const clientId = nanoid$2(21);
1621
+ localStorage.setItem(CLIENT_ID_STORAGE_KEY, clientId);
1622
+ return clientId;
1623
+ } catch (error) {
1624
+ return `temp_${nanoid$2(21)}_${Date.now()}`;
1625
+ }
1626
+ }
1627
+ //#endregion
1628
+ //#region utils/conversationId.ts
1629
+ /**
1630
+ * Conversation ID generation utility
1631
+ *
1632
+ * Unified format: timestamp (UTC time, second-level, format: YYYYMMDDHHmmss) + underscore + 12-digit NanoID
1633
+ * Example: 20251027143034_aB3dEf9hIjKl
1634
+ *
1635
+ * Time part uses UTC time for easier cross-platform log troubleshooting with unified timezone conversion
1636
+ * @internal
1637
+ */
1638
+ /**
1639
+ * Custom character set: only uppercase, lowercase letters and numbers (URL safe, no hyphens)
1640
+ * Character set: A-Z, a-z, 0-9 (62 characters)
1641
+ */
1642
+ var nanoid$1 = customAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 12);
1643
+ /**
1644
+ * Generate unified conversation ID
1645
+ *
1646
+ * Format: timestamp (UTC time, second-level, format: YYYYMMDDHHmmss) + underscore + 12-digit NanoID
1647
+ * Time part uses UTC time for easier cross-platform log troubleshooting with unified timezone conversion
1648
+ *
1649
+ * @returns Conversation ID in format YYYYMMDDHHmmss_nanoid
1650
+ * @example
1651
+ * generateConversationId() // "20251027143034_aB3dEf9hIjKl"
1652
+ * @internal
1653
+ */
1654
+ var generateTraceId = () => generateConversationId();
1655
+ function generateConversationId() {
1656
+ const now = /* @__PURE__ */ new Date();
1657
+ return `${`${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, "0")}${String(now.getUTCDate()).padStart(2, "0")}${String(now.getUTCHours()).padStart(2, "0")}${String(now.getUTCMinutes()).padStart(2, "0")}${String(now.getUTCSeconds()).padStart(2, "0")}`}_${nanoid$1()}`;
1658
+ }
1659
+ //#endregion
1660
+ //#region utils/id-manager.ts
1661
+ /**
1662
+ * ID Manager
1663
+ * Unified management of all types of IDs in SDK
1664
+ * @internal
1665
+ */
1666
+ /** 与 conversation_id 同字符集:URL 安全、无连字符。 */
1667
+ var nanoid = customAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 12);
1668
+ var IdManager = class {
1669
+ ids = {
1670
+ clientId: "",
1671
+ sessionId: "",
1672
+ userId: null,
1673
+ appId: null,
1674
+ sessionToken: null,
1675
+ connectionId: null,
1676
+ conversationId: null
1677
+ };
1678
+ constructor() {
1679
+ this.ids.clientId = getOrCreateClientId();
1680
+ }
1681
+ getClientId() {
1682
+ return this.ids.clientId;
1683
+ }
1684
+ setUserId(userId) {
1685
+ this.ids.userId = userId;
1686
+ }
1687
+ getUserId() {
1688
+ return this.ids.userId;
1689
+ }
1690
+ setAppId(appId) {
1691
+ this.ids.appId = appId;
1692
+ }
1693
+ getAppId() {
1694
+ return this.ids.appId;
1695
+ }
1696
+ setSessionToken(token) {
1697
+ this.ids.sessionToken = token;
1698
+ }
1699
+ getSessionToken() {
1700
+ return this.ids.sessionToken;
1701
+ }
1702
+ /**
1703
+ * Generate new connectionId (for WebSocket connection)
1704
+ * @internal
1705
+ */
1706
+ generateConnectionId() {
1707
+ this.ids.connectionId = generateConversationId();
1708
+ return this.ids.connectionId;
1709
+ }
1710
+ /**
1711
+ * Set connectionId (for connectionId received from server)
1712
+ * @internal
1713
+ */
1714
+ setConnectionId(connectionId) {
1715
+ this.ids.connectionId = connectionId;
1716
+ }
1717
+ getConnectionId() {
1718
+ return this.ids.connectionId;
1719
+ }
1720
+ clearConnectionId() {
1721
+ this.ids.connectionId = null;
1722
+ }
1723
+ /**
1724
+ * Generate new conversationId (for each conversation)
1725
+ * @internal
1726
+ */
1727
+ generateNewConversationId() {
1728
+ this.ids.conversationId = generateConversationId();
1729
+ return this.ids.conversationId;
1730
+ }
1731
+ getConversationId() {
1732
+ return this.ids.conversationId;
1733
+ }
1734
+ setConversationId(conversationId) {
1735
+ this.ids.conversationId = conversationId;
1736
+ }
1737
+ clearConversationId() {
1738
+ this.ids.conversationId = null;
1739
+ }
1740
+ /**
1741
+ * Get all IDs (for log reporting)
1742
+ * @internal
1743
+ */
1744
+ getAllIds() {
1745
+ return { ...this.ids };
1746
+ }
1747
+ /**
1748
+ * Get public log parameters (contains all necessary IDs)
1749
+ * @internal
1750
+ */
1751
+ getLogContext() {
1752
+ return {
1753
+ client_id: this.ids.clientId,
1754
+ session_id: this.ids.sessionId,
1755
+ user_id: this.ids.userId || "",
1756
+ app_id: this.ids.appId || ""
1757
+ };
1758
+ }
1759
+ /** 本次启动的 session id;首次调用时生成。 @internal */
1760
+ getSessionId() {
1761
+ if (!this.ids.sessionId) this.ids.sessionId = nanoid();
1762
+ return this.ids.sessionId;
1763
+ }
1764
+ /**
1765
+ * Clear all IDs (for testing or reset)
1766
+ * @internal
1767
+ */
1768
+ clear() {
1769
+ this.ids.userId = null;
1770
+ this.ids.appId = null;
1771
+ this.ids.sessionToken = null;
1772
+ this.ids.connectionId = null;
1773
+ this.ids.conversationId = null;
1774
+ }
1775
+ };
1776
+ var idManager = new IdManager();
1777
+ //#endregion
1778
+ //#region utils/log-sanitizer.ts
1779
+ var ALGORITHM_REG = new RegExp(`\\b(${[
1780
+ "flame",
1781
+ "keyframe",
1782
+ "keyframes",
1783
+ "splat",
1784
+ "splats",
1785
+ "covariance",
1786
+ "gaussian",
1787
+ "cov6",
1788
+ "packeddata",
1789
+ "sortorder",
1790
+ "sortindex",
1791
+ "avatar_core",
1792
+ "emscripten",
1793
+ "wasm",
1794
+ "blendshape",
1795
+ "expressionparam",
1796
+ "rig"
1797
+ ].join("|")})\\b`, "gi");
1798
+ /** Chinese characters (CJK Unified Ideographs) */
1799
+ var CHINESE_REG = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/;
1800
+ /** Patterns to redact: capture group 1 = key, 2 = value; replace value with *** */
1801
+ var SENSITIVE_PATTERNS = [
1802
+ {
1803
+ reg: /\b(token|sessiontoken|accesstoken|apikey|apisecret|secret|password|auth)=([^\s,}\]'"]+)/gi,
1804
+ replacement: "$1=***"
1805
+ },
1806
+ {
1807
+ reg: /\b(conversationid|connectionid|clientid|sessionid)=([^\s,}\]'"]+)/gi,
1808
+ replacement: "$1=***"
1809
+ },
1810
+ {
1811
+ reg: /\b(appid|app_id)=([^\s,}\]'"]+)/gi,
1812
+ replacement: "$1=***"
1813
+ },
1814
+ {
1815
+ reg: /\b(userid|user_id)=([^\s,}\]'"]+)/gi,
1816
+ replacement: "$1=***"
1817
+ },
1818
+ {
1819
+ reg: /(https?:\/\/)[^\s,}\]'"]+/gi,
1820
+ replacement: "$1***"
1821
+ },
1822
+ {
1823
+ reg: /(wss?:\/\/)[^\s,}\]'"]+/gi,
1824
+ replacement: "$1***"
1825
+ }
1826
+ ];
1827
+ /**
1828
+ * Check if message contains Chinese.
1829
+ */
1830
+ function hasChinese(msg) {
1831
+ return CHINESE_REG.test(msg);
1832
+ }
1833
+ /**
1834
+ * Check if message contains algorithm/internal terms.
1835
+ */
1836
+ function hasAlgorithmTerms(msg) {
1837
+ return ALGORITHM_REG.test(msg);
1838
+ }
1839
+ /**
1840
+ * Redact sensitive substrings in message.
1841
+ */
1842
+ function redactSensitive(msg) {
1843
+ let out = msg;
1844
+ for (const { reg, replacement } of SENSITIVE_PATTERNS) out = out.replace(reg, replacement);
1845
+ return out;
1846
+ }
1847
+ /**
1848
+ * Sanitize a log message for local persistence.
1849
+ * - Do not persist if message contains Chinese or algorithm terms.
1850
+ * - Otherwise persist, but redact sensitive content first.
1851
+ */
1852
+ function sanitizeForLocalLog(message) {
1853
+ if (hasChinese(message) || hasAlgorithmTerms(message)) return {
1854
+ shouldPersist: false,
1855
+ sanitized: message
1856
+ };
1857
+ return {
1858
+ shouldPersist: true,
1859
+ sanitized: redactSensitive(message)
1860
+ };
1861
+ }
1862
+ //#endregion
1863
+ //#region utils/logger.ts
1864
+ /**
1865
+ * Logger Utility
1866
+ * Environment-aware logger wrapper with local log persistence
1867
+ * - Always writes to local log file (IndexedDB) regardless of logLevel
1868
+ * - Console output is controlled by logLevel
1869
+ * - Errors and warnings are always reported to PostHog (when enabled)
1870
+ *
1871
+ * Usage: Replace `console.log()` with `logger.log()`
1872
+ */
1873
+ setGlobalLogLevel(LogLevel$1.Warning);
1874
+ var baseLogger = useLogger("Web").useGlobalConfig();
1875
+ logSink.initialize().catch(() => {});
1876
+ var currentLogLevel = LogLevel.off;
1877
+ /**
1878
+ * Write log to local storage.
1879
+ * Skips persistence if message contains Chinese, algorithm terms (e.g. Flame, splat), or sensitive content.
1880
+ * Otherwise redacts sensitive substrings then persists.
1881
+ */
1882
+ async function writeToLocalLog(message, level, extra = {}) {
1883
+ try {
1884
+ const { shouldPersist, sanitized } = sanitizeForLocalLog(message);
1885
+ if (!shouldPersist) return;
1886
+ const version = requireSDK().version;
1887
+ const appId = idManager.getAppId();
1888
+ const userId = idManager.getUserId();
1889
+ await logSink.append({
1890
+ level,
1891
+ ts: Date.now(),
1892
+ msg: sanitized,
1893
+ extra: {
1894
+ ...extra,
1895
+ _category: "Web",
1896
+ sdk_version: version || "",
1897
+ app_id: appId || "",
1898
+ user_id: userId || "",
1899
+ platform: "Web",
1900
+ framework: "",
1901
+ framework_version: ""
1902
+ }
1903
+ });
1904
+ } catch {}
1905
+ }
1906
+ /**
1907
+ * Format console message with [AvatarKit] prefix
1908
+ */
1909
+ function formatConsoleMessage(message) {
1910
+ return `[AvatarKit] ${message}`;
1911
+ }
1912
+ var logger = {
1913
+ debug: (message, ...args) => {
1914
+ writeToLocalLog(message, "info", {}).catch(() => {});
1915
+ if (currentLogLevel === LogLevel.all) baseLogger.debug(formatConsoleMessage(message), ...args);
1916
+ },
1917
+ verbose: (message, ...args) => {
1918
+ writeToLocalLog(message, "info", {}).catch(() => {});
1919
+ if (currentLogLevel === LogLevel.all) baseLogger.verbose(formatConsoleMessage(message), ...args);
1920
+ },
1921
+ log: (message, ...args) => {
1922
+ writeToLocalLog(message, "info", {}).catch(() => {});
1923
+ if (currentLogLevel === LogLevel.all) baseLogger.log(formatConsoleMessage(message), ...args);
1924
+ },
1925
+ warn: (message, ...args) => {
1926
+ writeToLocalLog(message, "warn", {}).catch(() => {});
1927
+ if (currentLogLevel === LogLevel.warning || currentLogLevel === LogLevel.all) baseLogger.warn(formatConsoleMessage(message), ...args);
1928
+ },
1929
+ error: (message, ...args) => {
1930
+ const fullMessage = message + (args.length > 0 ? " " + args.map((a) => a instanceof Error ? a.message : typeof a === "string" ? a : JSON.stringify(a)).join(" ") : "");
1931
+ writeToLocalLog(fullMessage, "error", {}).catch(() => {});
1932
+ if (currentLogLevel !== LogLevel.off) baseLogger.error(formatConsoleMessage(fullMessage));
1933
+ }
1934
+ };
1935
+ /**
1936
+ * Set SDK log level
1937
+ * Note: Local log writing is always enabled regardless of logLevel
1938
+ * @param level SDK's LogLevel enum value
1939
+ * @internal
1940
+ */
1941
+ function setLogLevel(level) {
1942
+ currentLogLevel = level;
1943
+ switch (level) {
1944
+ case LogLevel.off:
1945
+ setGlobalLogLevel(LogLevel$1.Error);
1946
+ break;
1947
+ case LogLevel.error:
1948
+ setGlobalLogLevel(LogLevel$1.Error);
1949
+ break;
1950
+ case LogLevel.warning:
1951
+ setGlobalLogLevel(LogLevel$1.Warning);
1952
+ break;
1953
+ case LogLevel.all:
1954
+ setGlobalLogLevel(LogLevel$1.Debug);
1955
+ break;
1956
+ default:
1957
+ setGlobalLogLevel(LogLevel$1.Warning);
1958
+ break;
1959
+ }
1960
+ }
1961
+ //#endregion
1962
+ //#region node_modules/.pnpm/posthog-js@1.422.5_react@19.2.4/node_modules/posthog-js/dist/module.js
1963
+ var t = "undefined" != typeof window ? window : void 0;
1964
+ var i = "undefined" != typeof globalThis ? globalThis : t;
1965
+ var e = null == i ? void 0 : i.navigator;
1966
+ var r = null == i ? void 0 : i.document;
1967
+ var s = null == i ? void 0 : i.location;
1968
+ var n = null == i ? void 0 : i.fetch;
1969
+ var o = null != i && i.XMLHttpRequest && "withCredentials" in new i.XMLHttpRequest() ? i.XMLHttpRequest : void 0;
1970
+ var a = null == i ? void 0 : i.AbortController;
1971
+ var l = null == i ? void 0 : i.CompressionStream;
1972
+ var h = null == e ? void 0 : e.userAgent;
1973
+ function u() {
1974
+ return !(!t || !1 === t.navigator.onLine);
1975
+ }
1976
+ var d = "undefined" != typeof globalThis ? globalThis : t;
1977
+ d && "undefined" == typeof self && (d.self = d), d && "undefined" == typeof File && (d.File = function() {});
1978
+ var v = null != t ? t : {};
1979
+ var c = {
1980
+ DEBUG: !1,
1981
+ LIB_VERSION: "0.7.0",
1982
+ LIB_NAME: "browser-common"
1983
+ };
1984
+ function f(t, i, e, r, s, n, o) {
1985
+ try {
1986
+ var a = t[n](o), l = a.value;
1987
+ } catch (t) {
1988
+ e(t);
1989
+ return;
1990
+ }
1991
+ a.done ? i(l) : Promise.resolve(l).then(r, s);
1992
+ }
1993
+ function p(t) {
1994
+ return function() {
1995
+ var i = this, e = arguments;
1996
+ return new Promise((function(r, s) {
1997
+ var n = t.apply(i, e);
1998
+ function o(t) {
1999
+ f(n, r, s, o, a, "next", t);
2000
+ }
2001
+ function a(t) {
2002
+ f(n, r, s, o, a, "throw", t);
2003
+ }
2004
+ o(void 0);
2005
+ }));
2006
+ };
2007
+ }
2008
+ function _() {
2009
+ return _ = Object.assign ? Object.assign.bind() : function(t) {
2010
+ for (var i = 1; arguments.length > i; i++) {
2011
+ var e = arguments[i];
2012
+ for (var r in e) ({}).hasOwnProperty.call(e, r) && (t[r] = e[r]);
2013
+ }
2014
+ return t;
2015
+ }, _.apply(null, arguments);
2016
+ }
2017
+ function g(t, i) {
2018
+ if (null == t) return {};
2019
+ var e = {};
2020
+ for (var r in t) if ({}.hasOwnProperty.call(t, r)) {
2021
+ if (-1 !== i.indexOf(r)) continue;
2022
+ e[r] = t[r];
2023
+ }
2024
+ return e;
2025
+ }
2026
+ var m = (t) => {
2027
+ if ("string" != typeof t) return t;
2028
+ try {
2029
+ return JSON.parse(t);
2030
+ } catch (i) {
2031
+ return t;
2032
+ }
2033
+ };
2034
+ function y(t) {
2035
+ return "string" == typeof t || t;
2036
+ }
2037
+ function b(t) {
2038
+ return "string" == typeof t ? t : void 0;
2039
+ }
2040
+ var w = [
2041
+ "$feature_flag",
2042
+ "$feature_flag_response",
2043
+ "$feature_flag_has_experiment",
2044
+ "$feature_flag_id",
2045
+ "$feature_flag_version",
2046
+ "$feature_flag_reason",
2047
+ "$feature_flag_request_id",
1445
2048
  "$feature_flag_evaluated_at",
1446
2049
  "$feature_flag_error",
1447
2050
  "locally_evaluated",
@@ -11104,232 +11707,81 @@ var iu = _({}, zh, qh, Hh, Vh, Wh, Gh, Jh, Kh, Yh, Qh, { conversations: class {
11104
11707
  kind: "retry-later",
11105
11708
  error: null !== (e = t.error) && void 0 !== e ? e : /* @__PURE__ */ new Error("metrics request failed with status " + i)
11106
11709
  });
11107
- }
11108
- }
11109
- }));
11110
- }));
11111
- }
11112
- Gc() {
11113
- return this._instance.requestRouter.endpointFor("api", "/i/v1/metrics") + "?token=" + encodeURIComponent(this._instance.config.token);
11114
- }
11115
- } });
11116
- Rl.__defaultExtensionClasses = _({}, iu);
11117
- var eu = function() {
11118
- c.SDK_DIST_CHANNEL = "npm";
11119
- var i = fl[xl] = new Rl();
11120
- return function() {
11121
- function i() {
11122
- i.done || (i.done = !0, El = !1, es(fl, (function(t) {
11123
- t._dom_loaded();
11124
- })));
11125
- }
11126
- null != r && r.addEventListener ? "complete" === r.readyState ? i() : us(r, "DOMContentLoaded", i, { capture: !1 }) : t && Ie.error("Browser doesn't support `document.addEventListener` so PostHog couldn't be initialized");
11127
- }(), i;
11128
- }();
11129
- //#endregion
11130
- //#region node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/url-alphabet/index.js
11131
- var urlAlphabet = "useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";
11132
- //#endregion
11133
- //#region node_modules/.pnpm/nanoid@5.1.6/node_modules/nanoid/index.browser.js
11134
- var random = (bytes) => crypto.getRandomValues(new Uint8Array(bytes));
11135
- var customRandom = (alphabet, defaultSize, getRandom) => {
11136
- let mask = (2 << Math.log2(alphabet.length - 1)) - 1;
11137
- let step = -~(1.6 * mask * defaultSize / alphabet.length);
11138
- return (size = defaultSize) => {
11139
- let id = "";
11140
- while (true) {
11141
- let bytes = getRandom(step);
11142
- let j = step | 0;
11143
- while (j--) {
11144
- id += alphabet[bytes[j] & mask] || "";
11145
- if (id.length >= size) return id;
11146
- }
11147
- }
11148
- };
11149
- };
11150
- var customAlphabet = (alphabet, size = 21) => customRandom(alphabet, size | 0, random);
11151
- var nanoid$2 = (size = 21) => {
11152
- let id = "";
11153
- let bytes = crypto.getRandomValues(new Uint8Array(size |= 0));
11154
- while (size--) id += urlAlphabet[bytes[size] & 63];
11155
- return id;
11156
- };
11157
- //#endregion
11158
- //#region utils/client-id.ts
11159
- /**
11160
- * Client ID management utility
11161
- * Used to generate and persist unique device identifier
11162
- * @internal
11163
- */
11164
- var CLIENT_ID_STORAGE_KEY = "spavatar_client_id";
11165
- /**
11166
- * Get or create client_id
11167
- * - If exists in localStorage, return existing client_id
11168
- * - If not exists, generate new client_id and store to localStorage
11169
- * @returns client_id string
11170
- * @internal
11171
- */
11172
- function getOrCreateClientId() {
11173
- try {
11174
- const stored = localStorage.getItem(CLIENT_ID_STORAGE_KEY);
11175
- if (stored) return stored;
11176
- const clientId = nanoid$2(21);
11177
- localStorage.setItem(CLIENT_ID_STORAGE_KEY, clientId);
11178
- return clientId;
11179
- } catch (error) {
11180
- return `temp_${nanoid$2(21)}_${Date.now()}`;
11181
- }
11182
- }
11183
- //#endregion
11184
- //#region utils/conversationId.ts
11185
- /**
11186
- * Conversation ID generation utility
11187
- *
11188
- * Unified format: timestamp (UTC time, second-level, format: YYYYMMDDHHmmss) + underscore + 12-digit NanoID
11189
- * Example: 20251027143034_aB3dEf9hIjKl
11190
- *
11191
- * Time part uses UTC time for easier cross-platform log troubleshooting with unified timezone conversion
11192
- * @internal
11193
- */
11194
- /**
11195
- * Custom character set: only uppercase, lowercase letters and numbers (URL safe, no hyphens)
11196
- * Character set: A-Z, a-z, 0-9 (62 characters)
11197
- */
11198
- var nanoid$1 = customAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 12);
11199
- /**
11200
- * Generate unified conversation ID
11201
- *
11202
- * Format: timestamp (UTC time, second-level, format: YYYYMMDDHHmmss) + underscore + 12-digit NanoID
11203
- * Time part uses UTC time for easier cross-platform log troubleshooting with unified timezone conversion
11204
- *
11205
- * @returns Conversation ID in format YYYYMMDDHHmmss_nanoid
11206
- * @example
11207
- * generateConversationId() // "20251027143034_aB3dEf9hIjKl"
11208
- * @internal
11209
- */
11210
- var generateTraceId = () => generateConversationId();
11211
- function generateConversationId() {
11212
- const now = /* @__PURE__ */ new Date();
11213
- return `${`${now.getUTCFullYear()}${String(now.getUTCMonth() + 1).padStart(2, "0")}${String(now.getUTCDate()).padStart(2, "0")}${String(now.getUTCHours()).padStart(2, "0")}${String(now.getUTCMinutes()).padStart(2, "0")}${String(now.getUTCSeconds()).padStart(2, "0")}`}_${nanoid$1()}`;
11214
- }
11215
- //#endregion
11216
- //#region utils/id-manager.ts
11217
- /**
11218
- * ID Manager
11219
- * Unified management of all types of IDs in SDK
11220
- * @internal
11221
- */
11222
- /** 与 conversation_id 同字符集:URL 安全、无连字符。 */
11223
- var nanoid = customAlphabet("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789", 12);
11224
- var IdManager = class {
11225
- ids = {
11226
- clientId: "",
11227
- sessionId: "",
11228
- userId: null,
11229
- appId: null,
11230
- sessionToken: null,
11231
- connectionId: null,
11232
- conversationId: null
11233
- };
11234
- constructor() {
11235
- this.ids.clientId = getOrCreateClientId();
11236
- }
11237
- getClientId() {
11238
- return this.ids.clientId;
11239
- }
11240
- setUserId(userId) {
11241
- this.ids.userId = userId;
11242
- }
11243
- getUserId() {
11244
- return this.ids.userId;
11245
- }
11246
- setAppId(appId) {
11247
- this.ids.appId = appId;
11248
- }
11249
- getAppId() {
11250
- return this.ids.appId;
11251
- }
11252
- setSessionToken(token) {
11253
- this.ids.sessionToken = token;
11254
- }
11255
- getSessionToken() {
11256
- return this.ids.sessionToken;
11257
- }
11258
- /**
11259
- * Generate new connectionId (for WebSocket connection)
11260
- * @internal
11261
- */
11262
- generateConnectionId() {
11263
- this.ids.connectionId = generateConversationId();
11264
- return this.ids.connectionId;
11265
- }
11266
- /**
11267
- * Set connectionId (for connectionId received from server)
11268
- * @internal
11269
- */
11270
- setConnectionId(connectionId) {
11271
- this.ids.connectionId = connectionId;
11272
- }
11273
- getConnectionId() {
11274
- return this.ids.connectionId;
11275
- }
11276
- clearConnectionId() {
11277
- this.ids.connectionId = null;
11278
- }
11279
- /**
11280
- * Generate new conversationId (for each conversation)
11281
- * @internal
11282
- */
11283
- generateNewConversationId() {
11284
- this.ids.conversationId = generateConversationId();
11285
- return this.ids.conversationId;
11286
- }
11287
- getConversationId() {
11288
- return this.ids.conversationId;
11289
- }
11290
- setConversationId(conversationId) {
11291
- this.ids.conversationId = conversationId;
11292
- }
11293
- clearConversationId() {
11294
- this.ids.conversationId = null;
11295
- }
11296
- /**
11297
- * Get all IDs (for log reporting)
11298
- * @internal
11299
- */
11300
- getAllIds() {
11301
- return { ...this.ids };
11302
- }
11303
- /**
11304
- * Get public log parameters (contains all necessary IDs)
11305
- * @internal
11306
- */
11307
- getLogContext() {
11308
- return {
11309
- client_id: this.ids.clientId,
11310
- session_id: this.ids.sessionId,
11311
- user_id: this.ids.userId || "",
11312
- app_id: this.ids.appId || ""
11313
- };
11710
+ }
11711
+ }
11712
+ }));
11713
+ }));
11314
11714
  }
11315
- /** 本次启动的 session id;首次调用时生成。 @internal */
11316
- getSessionId() {
11317
- if (!this.ids.sessionId) this.ids.sessionId = nanoid();
11318
- return this.ids.sessionId;
11715
+ Gc() {
11716
+ return this._instance.requestRouter.endpointFor("api", "/i/v1/metrics") + "?token=" + encodeURIComponent(this._instance.config.token);
11319
11717
  }
11320
- /**
11321
- * Clear all IDs (for testing or reset)
11322
- * @internal
11323
- */
11324
- clear() {
11325
- this.ids.userId = null;
11326
- this.ids.appId = null;
11327
- this.ids.sessionToken = null;
11328
- this.ids.connectionId = null;
11329
- this.ids.conversationId = null;
11718
+ } });
11719
+ Rl.__defaultExtensionClasses = _({}, iu);
11720
+ var eu = function() {
11721
+ c.SDK_DIST_CHANNEL = "npm";
11722
+ var i = fl[xl] = new Rl();
11723
+ return function() {
11724
+ function i() {
11725
+ i.done || (i.done = !0, El = !1, es(fl, (function(t) {
11726
+ t._dom_loaded();
11727
+ })));
11728
+ }
11729
+ null != r && r.addEventListener ? "complete" === r.readyState ? i() : us(r, "DOMContentLoaded", i, { capture: !1 }) : t && Ie.error("Browser doesn't support `document.addEventListener` so PostHog couldn't be initialized");
11730
+ }(), i;
11731
+ }();
11732
+ //#endregion
11733
+ //#region utils/telemetry-rate-limit.ts
11734
+ /**
11735
+ * 事件限频(三端同一规则,见 knowledge/error-telemetry-gap-audit.md「限频策略」)。
11736
+ *
11737
+ * 只给**循环路径**上的错误事件用(每帧 / 每包 / 每 tick):一台机器卡在某个坏状态时,
11738
+ * 同一条错误一秒能刷几十次,既刷爆上报量也淹没别的事件。
11739
+ *
11740
+ * - key = 事件名 + `stage` / `op` / `path` / `direction` / `backend` 之一(低基数判别字段),
11741
+ * **不含** reason 自由文本——否则每条 reason 都是新 key,限频等于没有
11742
+ * - 同一 key 每 session(页面生命周期)首次必发
11743
+ * - 之后 60s 内只发一次;被压掉的次数累计进下一条的 `suppressed_count`
11744
+ */
11745
+ var WINDOW_MS = 6e4;
11746
+ var slots = /* @__PURE__ */ new Map();
11747
+ var DISCRIMINATORS = [
11748
+ "stage",
11749
+ "op",
11750
+ "path",
11751
+ "direction",
11752
+ "backend",
11753
+ "code"
11754
+ ];
11755
+ /** @internal */
11756
+ function rateLimitKey(event, contents) {
11757
+ for (const k of DISCRIMINATORS) {
11758
+ const v = contents[k];
11759
+ if (v !== void 0 && v !== null && v !== "") return `${event}|${k}=${String(v)}`;
11330
11760
  }
11331
- };
11332
- var idManager = new IdManager();
11761
+ return event;
11762
+ }
11763
+ /**
11764
+ * 判定这次能不能发。返回 `null` = 压掉;返回数字 = 放行,数字是自上次放行以来被压掉的次数。
11765
+ * @internal
11766
+ */
11767
+ function admitRateLimited(key, now = Date.now()) {
11768
+ const slot = slots.get(key);
11769
+ if (!slot) {
11770
+ slots.set(key, {
11771
+ lastSent: now,
11772
+ suppressed: 0
11773
+ });
11774
+ return 0;
11775
+ }
11776
+ if (now - slot.lastSent < WINDOW_MS) {
11777
+ slot.suppressed++;
11778
+ return null;
11779
+ }
11780
+ const suppressed = slot.suppressed;
11781
+ slot.lastSent = now;
11782
+ slot.suppressed = 0;
11783
+ return suppressed;
11784
+ }
11333
11785
  //#endregion
11334
11786
  //#region config/constants.ts
11335
11787
  var POSTHOG_HOST = "https://i.spatialwalk.ai";
@@ -19863,755 +20315,398 @@ async function replayPersistedEvents() {
19863
20315
  }
19864
20316
  if (loggerProvider) loggerProvider.forceFlush().catch(() => {});
19865
20317
  } catch (error) {
19866
- logger.warn("[OTel] Failed to load persisted events:", error instanceof Error ? error.message : String(error));
19867
- }
19868
- }
19869
- /**
19870
- * Cleanup OTel (flush remaining events and shutdown).
19871
- * @internal
19872
- */
19873
- function cleanupOtel() {
19874
- if (!isInitialized$2 || !loggerProvider) return;
19875
- try {
19876
- loggerProvider.shutdown().catch((error) => {
19877
- logger.warn("[OTel] Shutdown error:", error instanceof Error ? error.message : String(error));
19878
- });
19879
- isInitialized$2 = false;
19880
- loggerProvider = null;
19881
- logger.log("[OTel] Cleaned up");
19882
- } catch (error) {
19883
- logger.warn("[OTel] Failed to cleanup:", error instanceof Error ? error.message : String(error));
19884
- isInitialized$2 = false;
19885
- loggerProvider = null;
19886
- }
19887
- }
19888
- //#endregion
19889
- //#region utils/posthog-tracker.ts
19890
- /**
19891
- * PostHog Telemetry Tool (Browser Version)
19892
- *
19893
- * Unified PostHog telemetry reporting, supports custom reporting
19894
- * Uses PostHog JS SDK for event tracking, suitable for browser environments
19895
- * @internal
19896
- */
19897
- /**
19898
- * 构建时间戳字段:本地时间戳(校准基准+单调流逝)+ 后台时间戳(拿到才带)。
19899
- * @internal
19900
- */
19901
- function timestampFields(enqueueMono) {
19902
- const local = enqueueMono === void 0 ? clockSync.localNow() : clockSync.localAt(enqueueMono);
19903
- const server = enqueueMono === void 0 ? clockSync.serverNow() : clockSync.serverAt(enqueueMono);
19904
- const fields = { timestamp: local };
19905
- if (server !== null) fields.server_timestamp = server;
19906
- return fields;
19907
- }
19908
- /**
19909
- * 客户端环境字段(仅 OTel log 通道补——PostHog 通道由其 SDK 自动附加同类 `$` 属性)。
19910
- * 全部从浏览器 API 现取(与 PostHog 客户端取法一致),不解析 UA/不造设备信息,
19911
- * 浏览器/OS/设备类型交给后端从 user_agent 解析。GeoIP(国家/城市/IP)由后端从 IP 推断,此处不涉及。
19912
- * 每条 log 实时取:url/pathname 随 SPA 路由变,取当前值才准。全程 try/catch 兜底,缺失即省略该字段。
19913
- * @internal
19914
- */
19915
- function clientContextFields() {
19916
- const fields = {};
19917
- try {
19918
- if (typeof window !== "undefined" && window.location) {
19919
- const loc = window.location;
19920
- if (loc.host) fields.host = loc.host;
19921
- if (loc.hostname) fields.domain = loc.hostname;
19922
- if (loc.href) fields.url = loc.href;
19923
- if (loc.pathname) fields.pathname = loc.pathname;
19924
- }
19925
- if (typeof document !== "undefined" && document.referrer) fields.referrer = document.referrer;
19926
- if (typeof navigator !== "undefined") {
19927
- if (navigator.userAgent) fields.user_agent = navigator.userAgent;
19928
- if (navigator.language) fields.locale = navigator.language;
19929
- }
19930
- if (typeof screen !== "undefined") {
19931
- if (screen.width) fields.screen_width = screen.width;
19932
- if (screen.height) fields.screen_height = screen.height;
19933
- }
19934
- if (typeof window !== "undefined") {
19935
- if (window.innerWidth) fields.viewport_width = window.innerWidth;
19936
- if (window.innerHeight) fields.viewport_height = window.innerHeight;
19937
- }
19938
- const tz = Intl?.DateTimeFormat?.().resolvedOptions?.().timeZone;
19939
- if (tz) fields.timezone = tz;
19940
- } catch {}
19941
- return fields;
19942
- }
19943
- var sdkVersion$1 = "1.0.0";
19944
- var isInitialized$1 = false;
19945
- var commonRegion = "";
19946
- var commonDsm = "";
19947
- function isPostHogEnabled() {
19948
- return !commonRegion.startsWith("cn-");
19949
- }
19950
- var SDK_POSTHOG_INSTANCE_NAME = "spatius-posthog";
19951
- var sdkPosthogInstance = null;
19952
- var eventQueue = [];
19953
- /**
19954
- * Get common fields for PostHog (excluding level)
19955
- * userProperties = 公共字段除了 level 外的所有字段
19956
- * @internal
19957
- */
19958
- function getCommonFields() {
19959
- const logContext = idManager.getLogContext();
19960
- return {
19961
- platform: "Web",
19962
- sdk_version: sdkVersion$1,
19963
- app_id: logContext.app_id || "",
19964
- user_id: logContext.user_id || "",
19965
- client_id: logContext.client_id,
19966
- region: commonRegion,
19967
- dsm: commonDsm,
19968
- framework: "",
19969
- framework_version: ""
19970
- };
19971
- }
19972
- /**
19973
- * Initialize PostHog with the SDK version.
19974
- * @internal
19975
- */
19976
- function initializePostHog(version, commonFields) {
19977
- commonRegion = commonFields.region;
19978
- commonDsm = commonFields.dsm;
19979
- if (!isPostHogEnabled()) {
19980
- logger.log(`[PostHog] Tracking disabled for region=${commonRegion} (data residency)`);
19981
- return;
19982
- }
19983
- const { host, apiKey, disableCompression } = getPostHogConfig();
19984
- if (!apiKey) {
19985
- logger.warn("[PostHog] API Key not configured, tracking disabled");
19986
- return;
19987
- }
19988
- if (isInitialized$1) {
19989
- logger.log("[PostHog] Already initialized, skipping");
19990
- return;
19991
- }
19992
- sdkVersion$1 = version;
19993
- try {
19994
- const logContext = idManager.getLogContext();
19995
- eu.init(apiKey, {
19996
- api_host: host,
19997
- person_profiles: "identified_only",
19998
- capture_pageview: false,
19999
- capture_pageleave: false,
20000
- disable_compression: disableCompression,
20001
- disable_session_recording: true,
20002
- autocapture: false,
20003
- capture_performance: false,
20004
- loaded: (posthogInstance) => {
20005
- logger.log(`[PostHog] Initialized successfully - host: ${host}, instance: ${SDK_POSTHOG_INSTANCE_NAME}`);
20006
- isInitialized$1 = true;
20007
- sdkPosthogInstance = posthogInstance;
20008
- const userProperties = getCommonFields();
20009
- if (logContext.user_id) posthogInstance.identify(logContext.user_id, userProperties);
20010
- else posthogInstance.register(userProperties);
20011
- posthogInstance.setPersonPropertiesForFlags(userProperties);
20012
- flushEventQueue();
20013
- clockSync.onReady(() => flushEventQueue());
20014
- }
20015
- }, SDK_POSTHOG_INSTANCE_NAME);
20016
- } catch (error) {
20017
- logger.warn("[PostHog] Failed to initialize:", error instanceof Error ? error.message : String(error));
20018
- }
20019
- }
20020
- /**
20021
- * Get SDK's PostHog instance (if not initialized, try to get it)
20022
- * @internal
20023
- */
20024
- function getSdkPosthogInstance() {
20025
- if (sdkPosthogInstance) return sdkPosthogInstance;
20026
- try {
20027
- sdkPosthogInstance = eu.getInstance?.(SDK_POSTHOG_INSTANCE_NAME);
20028
- return sdkPosthogInstance;
20029
- } catch (error) {
20030
- return null;
20031
- }
20032
- }
20033
- /**
20034
- * Get logs feature flag (default: false)
20035
- * Reloads feature flags from server first, then checks if logs_feature_flag is enabled
20036
- * @returns Promise<boolean> - true if feature flag is enabled, false otherwise
20037
- * @internal
20038
- */
20039
- async function getLogsFeatureFlag() {
20040
- let instance = getSdkPosthogInstance();
20041
- if (!instance) {
20042
- const maxWaitTime = 5e3;
20043
- const checkInterval = 100;
20044
- const startTime = Date.now();
20045
- while (!instance && Date.now() - startTime < maxWaitTime) {
20046
- await new Promise((resolve) => setTimeout(resolve, checkInterval));
20047
- instance = getSdkPosthogInstance();
20048
- }
20049
- }
20050
- if (!instance) {
20051
- logger.log("[PostHog] PostHog not initialized after waiting, logs feature flag disabled (default: false)");
20052
- return false;
20053
- }
20054
- try {
20055
- const commonFields = getCommonFields();
20056
- instance.setPersonPropertiesForFlags(commonFields);
20057
- instance.reloadFeatureFlags();
20058
- await new Promise((resolve) => {
20059
- instance.onFeatureFlags((_flags, _variants, { errorsLoading } = {}) => {
20060
- if (errorsLoading) logger.warn("[PostHog] Error loading feature flags");
20061
- resolve();
20062
- });
20063
- });
20064
- const isEnabled = instance.isFeatureEnabled("logs_feature_flag") === true;
20065
- logger.log(`[PostHog] Logs feature flag: ${isEnabled ? "enabled" : "disabled"}`);
20066
- return isEnabled;
20067
- } catch (error) {
20068
- logger.warn("[PostHog] Failed to get logs feature flag:", error instanceof Error ? error.message : String(error));
20069
- return false;
20318
+ logger.warn("[OTel] Failed to load persisted events:", error instanceof Error ? error.message : String(error));
20070
20319
  }
20071
20320
  }
20072
20321
  /**
20073
- * Update PostHog person properties for feature flags evaluation
20322
+ * Cleanup OTel (flush remaining events and shutdown).
20074
20323
  * @internal
20075
20324
  */
20076
- function updatePostHogPersonPropertiesForFlags() {
20077
- const instance = getSdkPosthogInstance();
20078
- if (!instance) return;
20079
- const commonFields = getCommonFields();
20080
- instance.setPersonPropertiesForFlags(commonFields);
20325
+ function cleanupOtel() {
20326
+ if (!isInitialized$2 || !loggerProvider) return;
20327
+ try {
20328
+ loggerProvider.shutdown().catch((error) => {
20329
+ logger.warn("[OTel] Shutdown error:", error instanceof Error ? error.message : String(error));
20330
+ });
20331
+ isInitialized$2 = false;
20332
+ loggerProvider = null;
20333
+ logger.log("[OTel] Cleaned up");
20334
+ } catch (error) {
20335
+ logger.warn("[OTel] Failed to cleanup:", error instanceof Error ? error.message : String(error));
20336
+ isInitialized$2 = false;
20337
+ loggerProvider = null;
20338
+ }
20081
20339
  }
20340
+ //#endregion
20341
+ //#region utils/posthog-tracker.ts
20082
20342
  /**
20083
- * Send queued events (called after PostHog initialization completes)
20343
+ * PostHog Telemetry Tool (Browser Version)
20344
+ *
20345
+ * Unified PostHog telemetry reporting, supports custom reporting
20346
+ * Uses PostHog JS SDK for event tracking, suitable for browser environments
20084
20347
  * @internal
20085
20348
  */
20086
- function flushEventQueue() {
20087
- if (!sdkPosthogInstance || !clockSync.isReady() || eventQueue.length === 0) return;
20088
- logger.log(`[PostHog] Flushing ${eventQueue.length} queued events`);
20089
- setTimeout(() => {
20090
- for (const { event, level, contents, enqueueMono } of eventQueue) try {
20091
- const properties = {
20092
- ...getCommonFields(),
20093
- level,
20094
- service_module: "sdk",
20095
- ...timestampFields(enqueueMono),
20096
- ...resolveMarks(contents)
20097
- };
20098
- sdkPosthogInstance.capture(event, properties);
20099
- } catch (error) {
20100
- logger.warn(`[PostHog] Failed to flush queued event ${event}:`, error instanceof Error ? error.message : String(error));
20101
- }
20102
- eventQueue.length = 0;
20103
- }, 0);
20104
- }
20105
20349
  /**
20106
- * Report event to PostHog
20107
- * @param event Event name
20108
- * @param level Log level
20109
- * @param contents Event contents
20350
+ * 构建时间戳字段:本地时间戳(校准基准+单调流逝)+ 后台时间戳(拿到才带)。
20110
20351
  * @internal
20111
20352
  */
20112
- function trackEvent(event, level = "info", contents = {}) {
20113
- if (!isPostHogEnabled()) return;
20114
- const instance = getSdkPosthogInstance();
20115
- if (!instance || !clockSync.isReady()) {
20116
- eventQueue.push({
20117
- event,
20118
- level,
20119
- contents,
20120
- enqueueMono: performance.now()
20121
- });
20122
- return;
20123
- }
20124
- sdkPosthogInstance = instance;
20125
- try {
20126
- const properties = {
20127
- ...getCommonFields(),
20128
- level,
20129
- service_module: "sdk",
20130
- ...timestampFields(),
20131
- ...resolveMarks(contents)
20132
- };
20133
- sdkPosthogInstance.capture(event, properties);
20134
- } catch (error) {
20135
- logger.warn("[PostHog] Failed to track event:", error instanceof Error ? error.message : String(error));
20136
- }
20353
+ function timestampFields(enqueueMono) {
20354
+ const local = enqueueMono === void 0 ? clockSync.localNow() : clockSync.localAt(enqueueMono);
20355
+ const server = enqueueMono === void 0 ? clockSync.serverNow() : clockSync.serverAt(enqueueMono);
20356
+ const fields = { timestamp: local };
20357
+ if (server !== null) fields.server_timestamp = server;
20358
+ return fields;
20137
20359
  }
20138
20360
  /**
20139
- * Cleanup PostHog (flush remaining events)
20361
+ * 客户端环境字段(仅 OTel log 通道补——PostHog 通道由其 SDK 自动附加同类 `$` 属性)。
20362
+ * 全部从浏览器 API 现取(与 PostHog 客户端取法一致),不解析 UA/不造设备信息,
20363
+ * 浏览器/OS/设备类型交给后端从 user_agent 解析。GeoIP(国家/城市/IP)由后端从 IP 推断,此处不涉及。
20364
+ * 每条 log 实时取:url/pathname 随 SPA 路由变,取当前值才准。全程 try/catch 兜底,缺失即省略该字段。
20140
20365
  * @internal
20141
20366
  */
20142
- function cleanupPostHog() {
20143
- if (!isInitialized$1) return;
20367
+ function clientContextFields() {
20368
+ const fields = {};
20144
20369
  try {
20145
- const instance = getSdkPosthogInstance();
20146
- if (!instance) {
20147
- isInitialized$1 = false;
20148
- return;
20370
+ if (typeof window !== "undefined" && window.location) {
20371
+ const loc = window.location;
20372
+ if (loc.host) fields.host = loc.host;
20373
+ if (loc.hostname) fields.domain = loc.hostname;
20374
+ if (loc.href) fields.url = loc.href;
20375
+ if (loc.pathname) fields.pathname = loc.pathname;
20149
20376
  }
20150
- sdkPosthogInstance = instance;
20151
- if (typeof instance.shutdown === "function") instance.shutdown();
20152
- else if (typeof instance.flush === "function") instance.flush();
20153
- isInitialized$1 = false;
20154
- sdkPosthogInstance = null;
20155
- logger.log("[PostHog] Cleaned up");
20156
- } catch (error) {
20157
- logger.warn("[PostHog] Failed to cleanup:", error instanceof Error ? error.message : String(error));
20158
- isInitialized$1 = false;
20159
- sdkPosthogInstance = null;
20160
- }
20161
- }
20162
- var TELEMETRY_LOG_METHOD = {
20163
- debug: "log",
20164
- info: "log",
20165
- warning: "warn",
20166
- error: "error"
20167
- };
20168
- /** 组装上报 context(附加 session_token 后缀)并写一条本地 console。两条上报通道共用。 */
20169
- function buildTelemetryContext(event, level, contents) {
20170
- const sessionToken = idManager.getSessionToken() ?? "";
20171
- const context = {
20172
- session_token_suffix: sessionToken ? sessionToken.slice(-8) : "",
20173
- connection_id: idManager.getConnectionId() ?? "",
20174
- ...clientContextFields(),
20175
- ...contents
20176
- };
20177
- const logMethod = TELEMETRY_LOG_METHOD[level] ?? "log";
20178
- const propsDescription = Object.entries(contents).map(([k, v]) => `${k}=${v}`).join(", ");
20179
- logger[logMethod](`[Telemetry] ${event} [${propsDescription}]`);
20180
- return context;
20181
- }
20182
- /** 通过 OTel 上报(独立通道,失败隔离,不影响 PostHog)。 */
20183
- function emitToOtel(event, level, context) {
20184
- try {
20185
- trackEventOtel(event, level, context);
20186
- } catch (error) {
20187
- logger.warn("[OTel] Dual-send failed:", error instanceof Error ? error.message : String(error));
20188
- }
20377
+ if (typeof document !== "undefined" && document.referrer) fields.referrer = document.referrer;
20378
+ if (typeof navigator !== "undefined") {
20379
+ if (navigator.userAgent) fields.user_agent = navigator.userAgent;
20380
+ if (navigator.language) fields.locale = navigator.language;
20381
+ }
20382
+ if (typeof screen !== "undefined") {
20383
+ if (screen.width) fields.screen_width = screen.width;
20384
+ if (screen.height) fields.screen_height = screen.height;
20385
+ }
20386
+ if (typeof window !== "undefined") {
20387
+ if (window.innerWidth) fields.viewport_width = window.innerWidth;
20388
+ if (window.innerHeight) fields.viewport_height = window.innerHeight;
20389
+ }
20390
+ const tz = Intl?.DateTimeFormat?.().resolvedOptions?.().timeZone;
20391
+ if (tz) fields.timezone = tz;
20392
+ } catch {}
20393
+ return fields;
20189
20394
  }
20190
- /**
20191
- * 日志上报接口:同时发往 PostHog 与 OTel。
20192
- * 用于 SDK 内部**日志类**事件(失败、状态变更、生命周期等)。
20193
- * 指标类(延迟/帧率/时长/次数等度量)请用 {@link logMetric}——只发 OTel。
20194
- * @param event Event name
20195
- * @param level Log level
20196
- * @param contents Log contents
20197
- * @internal
20198
- */
20199
- function logEvent(event, level = "info", contents = {}) {
20200
- const context = buildTelemetryContext(event, level, contents);
20201
- trackEvent(event, level, context);
20202
- emitToOtel(event, level, context);
20395
+ var sdkVersion$1 = "1.0.0";
20396
+ var isInitialized$1 = false;
20397
+ var commonRegion = "";
20398
+ var commonDsm = "";
20399
+ function isPostHogEnabled() {
20400
+ return !commonRegion.startsWith("cn-");
20203
20401
  }
20402
+ var SDK_POSTHOG_INSTANCE_NAME = "spatius-posthog";
20403
+ var sdkPosthogInstance = null;
20404
+ var eventQueue = [];
20204
20405
  /**
20205
- * 指标上报接口:**双发**——OTel Metric 信号(Histogram,供聚合 P95/均值/SLO)
20206
- * + 一份 OTel log(带完整明细,供按 avatar_id 等排查单次)。不发 PostHog。
20207
- *
20208
- * metric 的天然形态是「一个数值 + 一组低基数标签」,故签名为 (name, value, labels, logExtra):
20209
- * - `value` 被记录到 Histogram(延迟 ms / 帧率 / 时长 / 次数 / 比率等)
20210
- * - `labels` 低基数标签(dsm / resolution / is_fallback / renderer_backend 等),
20211
- * 同时进 metric 的 attributes 和 log。**不要**放高基数字段(会撑爆 metric 基数)。
20212
- * - `logExtra` 只进 log 的明细(avatar_id / conversation_id 等高基数字段)。
20213
- *
20214
- * @param name Metric 名(如 `fetch_avatar_latency`)
20215
- * @param value 被聚合的数值
20216
- * @param labels 低基数标签
20217
- * @param logExtra 仅 log 携带的高基数明细
20406
+ * Get common fields for PostHog (excluding level)
20407
+ * userProperties = 公共字段除了 level 外的所有字段
20218
20408
  * @internal
20219
20409
  */
20220
- function logMetric(name, value, labels = {}, logExtra = {}) {
20221
- recordMetric(name, value, labels);
20222
- emitToOtel(name, "info", buildTelemetryContext(name, "info", {
20223
- value,
20224
- ...labels,
20225
- ...logExtra
20226
- }));
20227
- }
20228
- var logSink = class LogSink {
20229
- static instance = null;
20230
- db = null;
20231
- dbName = "avatarkit_logs";
20232
- storeName = "logs";
20233
- version = 1;
20234
- trimThreshold = 5e3;
20235
- trimBufferSize = 1e3;
20236
- isFlushing = false;
20237
- constructor() {}
20238
- static getInstance() {
20239
- if (!LogSink.instance) LogSink.instance = new LogSink();
20240
- return LogSink.instance;
20241
- }
20242
- /**
20243
- * Initialize IndexedDB
20244
- */
20245
- async initialize() {
20246
- if (this.db) return;
20247
- return new Promise((resolve, reject) => {
20248
- const request = indexedDB.open(this.dbName, this.version);
20249
- request.onerror = () => {
20250
- reject(/* @__PURE__ */ new Error("Failed to open IndexedDB"));
20251
- };
20252
- request.onsuccess = () => {
20253
- this.db = request.result;
20254
- resolve();
20255
- };
20256
- request.onupgradeneeded = (event) => {
20257
- const db = event.target.result;
20258
- if (!db.objectStoreNames.contains(this.storeName)) db.createObjectStore(this.storeName, {
20259
- keyPath: "id",
20260
- autoIncrement: true
20261
- }).createIndex("ts", "ts", { unique: false });
20262
- };
20263
- });
20264
- }
20265
- /**
20266
- * Append log entry to IndexedDB
20267
- */
20268
- async append(entry) {
20269
- if (!this.db) try {
20270
- await this.initialize();
20271
- } catch {
20272
- return;
20273
- }
20274
- if (!this.db) return;
20275
- try {
20276
- const store = this.db.transaction([this.storeName], "readwrite").objectStore(this.storeName);
20277
- await new Promise((resolve, reject) => {
20278
- const request = store.add(entry);
20279
- request.onsuccess = () => resolve();
20280
- request.onerror = () => reject(/* @__PURE__ */ new Error("Failed to add log"));
20281
- });
20282
- this.getCount().then((count) => {
20283
- if (count > this.trimThreshold) this.trim().catch(() => {});
20284
- }).catch(() => {});
20285
- } catch (error) {}
20410
+ function getCommonFields() {
20411
+ const logContext = idManager.getLogContext();
20412
+ return {
20413
+ platform: "Web",
20414
+ sdk_version: sdkVersion$1,
20415
+ app_id: logContext.app_id || "",
20416
+ user_id: logContext.user_id || "",
20417
+ client_id: logContext.client_id,
20418
+ region: commonRegion,
20419
+ dsm: commonDsm,
20420
+ framework: "",
20421
+ framework_version: ""
20422
+ };
20423
+ }
20424
+ /**
20425
+ * Initialize PostHog with the SDK version.
20426
+ * @internal
20427
+ */
20428
+ function initializePostHog(version, commonFields) {
20429
+ commonRegion = commonFields.region;
20430
+ commonDsm = commonFields.dsm;
20431
+ if (!isPostHogEnabled()) {
20432
+ logger.log(`[PostHog] Tracking disabled for region=${commonRegion} (data residency)`);
20433
+ return;
20286
20434
  }
20287
- /**
20288
- * Get total log count
20289
- */
20290
- async getCount() {
20291
- if (!this.db) return 0;
20292
- return new Promise((resolve, reject) => {
20293
- const request = this.db.transaction([this.storeName], "readonly").objectStore(this.storeName).count();
20294
- request.onsuccess = () => {
20295
- resolve(request.result);
20296
- };
20297
- request.onerror = () => {
20298
- reject(/* @__PURE__ */ new Error("Failed to count logs"));
20299
- };
20300
- });
20435
+ const { host, apiKey, disableCompression } = getPostHogConfig();
20436
+ if (!apiKey) {
20437
+ logger.warn("[PostHog] API Key not configured, tracking disabled");
20438
+ return;
20301
20439
  }
20302
- /**
20303
- * Trim logs to keep only recent entries
20304
- */
20305
- async trim() {
20306
- if (!this.db || this.isFlushing) return;
20307
- try {
20308
- const store = this.db.transaction([this.storeName], "readwrite").objectStore(this.storeName);
20309
- const getAllRequest = store.getAll();
20310
- const entries = await new Promise((resolve, reject) => {
20311
- getAllRequest.onsuccess = () => {
20312
- resolve(getAllRequest.result);
20313
- };
20314
- getAllRequest.onerror = () => {
20315
- reject(/* @__PURE__ */ new Error("Failed to get logs"));
20316
- };
20317
- });
20318
- const keepCount = this.trimThreshold - this.trimBufferSize;
20319
- if (entries.length <= keepCount) return;
20320
- entries.sort((a, b) => a.ts - b.ts);
20321
- const toDelete = entries.slice(0, entries.length - keepCount);
20322
- for (const entry of toDelete) if (entry.id !== void 0) await new Promise((resolve, reject) => {
20323
- const deleteRequest = store.delete(entry.id);
20324
- deleteRequest.onsuccess = () => resolve();
20325
- deleteRequest.onerror = () => reject(/* @__PURE__ */ new Error("Failed to delete log"));
20326
- });
20327
- } catch (error) {}
20440
+ if (isInitialized$1) {
20441
+ logger.log("[PostHog] Already initialized, skipping");
20442
+ return;
20328
20443
  }
20329
- /**
20330
- * Flush logs to server
20331
- */
20332
- async flush() {
20333
- if (!this.db || this.isFlushing) return;
20334
- this.isFlushing = true;
20335
- try {
20336
- const getAllRequest = this.db.transaction([this.storeName], "readonly").objectStore(this.storeName).getAll();
20337
- const entries = await new Promise((resolve, reject) => {
20338
- getAllRequest.onsuccess = () => {
20339
- resolve(getAllRequest.result);
20340
- };
20341
- getAllRequest.onerror = () => {
20342
- reject(/* @__PURE__ */ new Error("Failed to get logs"));
20343
- };
20344
- });
20345
- if (entries.length === 0) {
20346
- this.isFlushing = false;
20347
- return;
20444
+ sdkVersion$1 = version;
20445
+ try {
20446
+ const logContext = idManager.getLogContext();
20447
+ eu.init(apiKey, {
20448
+ api_host: host,
20449
+ person_profiles: "identified_only",
20450
+ capture_pageview: false,
20451
+ capture_pageleave: false,
20452
+ disable_compression: disableCompression,
20453
+ disable_session_recording: true,
20454
+ autocapture: false,
20455
+ capture_performance: false,
20456
+ loaded: (posthogInstance) => {
20457
+ logger.log(`[PostHog] Initialized successfully - host: ${host}, instance: ${SDK_POSTHOG_INSTANCE_NAME}`);
20458
+ isInitialized$1 = true;
20459
+ sdkPosthogInstance = posthogInstance;
20460
+ const userProperties = getCommonFields();
20461
+ if (logContext.user_id) posthogInstance.identify(logContext.user_id, userProperties);
20462
+ else posthogInstance.register(userProperties);
20463
+ posthogInstance.setPersonPropertiesForFlags(userProperties);
20464
+ flushEventQueue();
20465
+ clockSync.onReady(() => flushEventQueue());
20348
20466
  }
20349
- const requestBody = { logs: entries.map((entry) => ({
20350
- ...entry,
20351
- extra: {
20352
- ...entry.extra,
20353
- platform: "Web"
20354
- }
20355
- })) };
20356
- const jsonData = JSON.stringify(requestBody);
20357
- const gzippedData = await this.gzip(jsonData);
20358
- const response = await fetch("https://hogtool.spatialwalk.ai/batch-upload-log", {
20359
- method: "POST",
20360
- headers: {
20361
- "Content-Type": "application/json",
20362
- "Content-Encoding": "gzip"
20363
- },
20364
- body: gzippedData,
20365
- signal: AbortSignal.timeout(15e3)
20366
- });
20367
- if (!response.ok) throw new Error(`Failed to upload logs: ${response.status} ${response.statusText}`);
20368
- await this.clearFirst(entries.length);
20369
- } catch (error) {
20370
- console.warn("[LogSink] Failed to flush logs:", error);
20371
- throw error;
20372
- } finally {
20373
- this.isFlushing = false;
20374
- }
20467
+ }, SDK_POSTHOG_INSTANCE_NAME);
20468
+ } catch (error) {
20469
+ logger.warn("[PostHog] Failed to initialize:", error instanceof Error ? error.message : String(error));
20375
20470
  }
20376
- /**
20377
- * Clear first N log entries
20378
- */
20379
- async clearFirst(count) {
20380
- if (!this.db || count <= 0) return;
20381
- try {
20382
- const store = this.db.transaction([this.storeName], "readwrite").objectStore(this.storeName);
20383
- const getAllRequest = store.getAll();
20384
- const entries = await new Promise((resolve, reject) => {
20385
- getAllRequest.onsuccess = () => {
20386
- resolve(getAllRequest.result);
20387
- };
20388
- getAllRequest.onerror = () => {
20389
- reject(/* @__PURE__ */ new Error("Failed to get logs"));
20390
- };
20391
- });
20392
- entries.sort((a, b) => a.ts - b.ts);
20393
- const toDelete = entries.slice(0, count);
20394
- for (const entry of toDelete) if (entry.id !== void 0) await new Promise((resolve, reject) => {
20395
- const deleteRequest = store.delete(entry.id);
20396
- deleteRequest.onsuccess = () => resolve();
20397
- deleteRequest.onerror = () => reject(/* @__PURE__ */ new Error("Failed to delete log"));
20398
- });
20399
- } catch (error) {}
20471
+ }
20472
+ /**
20473
+ * Get SDK's PostHog instance (if not initialized, try to get it)
20474
+ * @internal
20475
+ */
20476
+ function getSdkPosthogInstance() {
20477
+ if (sdkPosthogInstance) return sdkPosthogInstance;
20478
+ try {
20479
+ sdkPosthogInstance = eu.getInstance?.(SDK_POSTHOG_INSTANCE_NAME);
20480
+ return sdkPosthogInstance;
20481
+ } catch (error) {
20482
+ return null;
20400
20483
  }
20401
- /**
20402
- * Gzip string data
20403
- */
20404
- async gzip(data) {
20405
- try {
20406
- const encoded = new TextEncoder().encode(data);
20407
- const compressedStream = new ReadableStream({ start(controller) {
20408
- controller.enqueue(encoded);
20409
- controller.close();
20410
- } }).pipeThrough(new CompressionStream("gzip"));
20411
- return await new Response(compressedStream).blob();
20412
- } catch (error) {
20413
- console.error("[LogSink] gzip() error:", error);
20414
- throw error;
20484
+ }
20485
+ /**
20486
+ * Get logs feature flag (default: false)
20487
+ * Reloads feature flags from server first, then checks if logs_feature_flag is enabled
20488
+ * @returns Promise<boolean> - true if feature flag is enabled, false otherwise
20489
+ * @internal
20490
+ */
20491
+ async function getLogsFeatureFlag() {
20492
+ let instance = getSdkPosthogInstance();
20493
+ if (!instance) {
20494
+ const maxWaitTime = 5e3;
20495
+ const checkInterval = 100;
20496
+ const startTime = Date.now();
20497
+ while (!instance && Date.now() - startTime < maxWaitTime) {
20498
+ await new Promise((resolve) => setTimeout(resolve, checkInterval));
20499
+ instance = getSdkPosthogInstance();
20415
20500
  }
20416
20501
  }
20417
- }.getInstance();
20418
- //#endregion
20419
- //#region utils/log-sanitizer.ts
20420
- var ALGORITHM_REG = new RegExp(`\\b(${[
20421
- "flame",
20422
- "keyframe",
20423
- "keyframes",
20424
- "splat",
20425
- "splats",
20426
- "covariance",
20427
- "gaussian",
20428
- "cov6",
20429
- "packeddata",
20430
- "sortorder",
20431
- "sortindex",
20432
- "avatar_core",
20433
- "emscripten",
20434
- "wasm",
20435
- "blendshape",
20436
- "expressionparam",
20437
- "rig"
20438
- ].join("|")})\\b`, "gi");
20439
- /** Chinese characters (CJK Unified Ideographs) */
20440
- var CHINESE_REG = /[\u4e00-\u9fff\u3400-\u4dbf\uf900-\ufaff]/;
20441
- /** Patterns to redact: capture group 1 = key, 2 = value; replace value with *** */
20442
- var SENSITIVE_PATTERNS = [
20443
- {
20444
- reg: /\b(token|sessiontoken|accesstoken|apikey|apisecret|secret|password|auth)=([^\s,}\]'"]+)/gi,
20445
- replacement: "$1=***"
20446
- },
20447
- {
20448
- reg: /\b(conversationid|connectionid|clientid|sessionid)=([^\s,}\]'"]+)/gi,
20449
- replacement: "$1=***"
20450
- },
20451
- {
20452
- reg: /\b(appid|app_id)=([^\s,}\]'"]+)/gi,
20453
- replacement: "$1=***"
20454
- },
20455
- {
20456
- reg: /\b(userid|user_id)=([^\s,}\]'"]+)/gi,
20457
- replacement: "$1=***"
20458
- },
20459
- {
20460
- reg: /(https?:\/\/)[^\s,}\]'"]+/gi,
20461
- replacement: "$1***"
20462
- },
20463
- {
20464
- reg: /(wss?:\/\/)[^\s,}\]'"]+/gi,
20465
- replacement: "$1***"
20502
+ if (!instance) {
20503
+ logger.log("[PostHog] PostHog not initialized after waiting, logs feature flag disabled (default: false)");
20504
+ return false;
20505
+ }
20506
+ try {
20507
+ const commonFields = getCommonFields();
20508
+ instance.setPersonPropertiesForFlags(commonFields);
20509
+ instance.reloadFeatureFlags();
20510
+ await new Promise((resolve) => {
20511
+ instance.onFeatureFlags((_flags, _variants, { errorsLoading } = {}) => {
20512
+ if (errorsLoading) logger.warn("[PostHog] Error loading feature flags");
20513
+ resolve();
20514
+ });
20515
+ });
20516
+ const isEnabled = instance.isFeatureEnabled("logs_feature_flag") === true;
20517
+ logger.log(`[PostHog] Logs feature flag: ${isEnabled ? "enabled" : "disabled"}`);
20518
+ return isEnabled;
20519
+ } catch (error) {
20520
+ logger.warn("[PostHog] Failed to get logs feature flag:", error instanceof Error ? error.message : String(error));
20521
+ return false;
20466
20522
  }
20467
- ];
20468
- /**
20469
- * Check if message contains Chinese.
20470
- */
20471
- function hasChinese(msg) {
20472
- return CHINESE_REG.test(msg);
20473
- }
20474
- /**
20475
- * Check if message contains algorithm/internal terms.
20476
- */
20477
- function hasAlgorithmTerms(msg) {
20478
- return ALGORITHM_REG.test(msg);
20479
20523
  }
20480
20524
  /**
20481
- * Redact sensitive substrings in message.
20525
+ * Update PostHog person properties for feature flags evaluation
20526
+ * @internal
20482
20527
  */
20483
- function redactSensitive(msg) {
20484
- let out = msg;
20485
- for (const { reg, replacement } of SENSITIVE_PATTERNS) out = out.replace(reg, replacement);
20486
- return out;
20528
+ function updatePostHogPersonPropertiesForFlags() {
20529
+ const instance = getSdkPosthogInstance();
20530
+ if (!instance) return;
20531
+ const commonFields = getCommonFields();
20532
+ instance.setPersonPropertiesForFlags(commonFields);
20487
20533
  }
20488
20534
  /**
20489
- * Sanitize a log message for local persistence.
20490
- * - Do not persist if message contains Chinese or algorithm terms.
20491
- * - Otherwise persist, but redact sensitive content first.
20535
+ * Send queued events (called after PostHog initialization completes)
20536
+ * @internal
20492
20537
  */
20493
- function sanitizeForLocalLog(message) {
20494
- if (hasChinese(message) || hasAlgorithmTerms(message)) return {
20495
- shouldPersist: false,
20496
- sanitized: message
20497
- };
20498
- return {
20499
- shouldPersist: true,
20500
- sanitized: redactSensitive(message)
20501
- };
20538
+ function flushEventQueue() {
20539
+ if (!sdkPosthogInstance || !clockSync.isReady() || eventQueue.length === 0) return;
20540
+ logger.log(`[PostHog] Flushing ${eventQueue.length} queued events`);
20541
+ setTimeout(() => {
20542
+ for (const { event, level, contents, enqueueMono } of eventQueue) try {
20543
+ const properties = {
20544
+ ...getCommonFields(),
20545
+ level,
20546
+ service_module: "sdk",
20547
+ ...timestampFields(enqueueMono),
20548
+ ...resolveMarks(contents)
20549
+ };
20550
+ sdkPosthogInstance.capture(event, properties);
20551
+ } catch (error) {
20552
+ logger.warn(`[PostHog] Failed to flush queued event ${event}:`, error instanceof Error ? error.message : String(error));
20553
+ }
20554
+ eventQueue.length = 0;
20555
+ }, 0);
20502
20556
  }
20503
- //#endregion
20504
- //#region utils/logger.ts
20505
20557
  /**
20506
- * Logger Utility
20507
- * Environment-aware logger wrapper with local log persistence
20508
- * - Always writes to local log file (IndexedDB) regardless of logLevel
20509
- * - Console output is controlled by logLevel
20510
- * - Errors and warnings are always reported to PostHog (when enabled)
20558
+ * **只发 PostHog**,不进 OTel——也就是不进 OpenObserve,看板和告警都查不到。
20511
20559
  *
20512
- * Usage: Replace `console.log()` with `logger.log()`
20513
- */
20514
- setGlobalLogLevel(LogLevel$1.Warning);
20515
- var baseLogger = useLogger("Web").withErrorProcessor((err) => {
20516
- captureErrorContext("error", err);
20517
- return err;
20518
- }).useGlobalConfig();
20519
- logSink.initialize().catch(() => {});
20520
- var currentLogLevel = LogLevel.off;
20521
- /**
20522
- * Write log to local storage.
20523
- * Skips persistence if message contains Chinese, algorithm terms (e.g. Flame, splat), or sensitive content.
20524
- * Otherwise redacts sensitive substrings then persists.
20560
+ * 业务事件禁止直接调这个,用 {@link logEvent}(PostHog + OTel 双发)。这个名字
20561
+ * 故意起得难看:它以前叫 `trackEvent`,和 `internal-telemetry.ts` 里给 RTC 暴露的
20562
+ * OTel 单发 `trackEvent` 同名反向,`render_blank_canvas` 与 `render_init_failed`
20563
+ * 先后因此只进了 PostHog、后台零记录。现在唯一的调用点是 `logEvent` 本身,不再导出。
20564
+ * @param event Event name
20565
+ * @param level Log level
20566
+ * @param contents Event contents
20567
+ * @internal
20525
20568
  */
20526
- async function writeToLocalLog(message, level, extra = {}) {
20527
- try {
20528
- const { shouldPersist, sanitized } = sanitizeForLocalLog(message);
20529
- if (!shouldPersist) return;
20530
- const version = requireSDK().version;
20531
- const appId = idManager.getAppId();
20532
- const userId = idManager.getUserId();
20533
- await logSink.append({
20569
+ function trackPostHogOnly(event, level = "info", contents = {}) {
20570
+ if (!isPostHogEnabled()) return;
20571
+ const instance = getSdkPosthogInstance();
20572
+ if (!instance || !clockSync.isReady()) {
20573
+ eventQueue.push({
20574
+ event,
20534
20575
  level,
20535
- ts: Date.now(),
20536
- msg: sanitized,
20537
- extra: {
20538
- ...extra,
20539
- _category: "Web",
20540
- sdk_version: version || "",
20541
- app_id: appId || "",
20542
- user_id: userId || "",
20543
- platform: "Web",
20544
- framework: "",
20545
- framework_version: ""
20546
- }
20576
+ contents,
20577
+ enqueueMono: performance.now()
20547
20578
  });
20548
- } catch {}
20579
+ return;
20580
+ }
20581
+ sdkPosthogInstance = instance;
20582
+ try {
20583
+ const properties = {
20584
+ ...getCommonFields(),
20585
+ level,
20586
+ service_module: "sdk",
20587
+ ...timestampFields(),
20588
+ ...resolveMarks(contents)
20589
+ };
20590
+ sdkPosthogInstance.capture(event, properties);
20591
+ } catch (error) {
20592
+ logger.warn("[PostHog] Failed to track event:", error instanceof Error ? error.message : String(error));
20593
+ }
20549
20594
  }
20550
20595
  /**
20551
- * Format console message with [AvatarKit] prefix
20596
+ * Cleanup PostHog (flush remaining events)
20597
+ * @internal
20552
20598
  */
20553
- function formatConsoleMessage(message) {
20554
- return `[AvatarKit] ${message}`;
20555
- }
20556
- var logger = {
20557
- debug: (message, ...args) => {
20558
- writeToLocalLog(message, "info", {}).catch(() => {});
20559
- if (currentLogLevel === LogLevel.all) baseLogger.debug(formatConsoleMessage(message), ...args);
20560
- },
20561
- verbose: (message, ...args) => {
20562
- writeToLocalLog(message, "info", {}).catch(() => {});
20563
- if (currentLogLevel === LogLevel.all) baseLogger.verbose(formatConsoleMessage(message), ...args);
20564
- },
20565
- log: (message, ...args) => {
20566
- writeToLocalLog(message, "info", {}).catch(() => {});
20567
- if (currentLogLevel === LogLevel.all) baseLogger.log(formatConsoleMessage(message), ...args);
20568
- },
20569
- warn: (message, ...args) => {
20570
- writeToLocalLog(message, "warn", {}).catch(() => {});
20571
- if (currentLogLevel === LogLevel.warning || currentLogLevel === LogLevel.all) baseLogger.warn(formatConsoleMessage(message), ...args);
20572
- },
20573
- error: (message, ...args) => {
20574
- const fullMessage = message + (args.length > 0 ? " " + args.map((a) => a instanceof Error ? a.message : typeof a === "string" ? a : JSON.stringify(a)).join(" ") : "");
20575
- writeToLocalLog(fullMessage, "error", {}).catch(() => {});
20576
- if (currentLogLevel !== LogLevel.off) baseLogger.error(formatConsoleMessage(fullMessage));
20599
+ function cleanupPostHog() {
20600
+ if (!isInitialized$1) return;
20601
+ try {
20602
+ const instance = getSdkPosthogInstance();
20603
+ if (!instance) {
20604
+ isInitialized$1 = false;
20605
+ return;
20606
+ }
20607
+ sdkPosthogInstance = instance;
20608
+ if (typeof instance.shutdown === "function") instance.shutdown();
20609
+ else if (typeof instance.flush === "function") instance.flush();
20610
+ isInitialized$1 = false;
20611
+ sdkPosthogInstance = null;
20612
+ logger.log("[PostHog] Cleaned up");
20613
+ } catch (error) {
20614
+ logger.warn("[PostHog] Failed to cleanup:", error instanceof Error ? error.message : String(error));
20615
+ isInitialized$1 = false;
20616
+ sdkPosthogInstance = null;
20577
20617
  }
20618
+ }
20619
+ var TELEMETRY_LOG_METHOD = {
20620
+ debug: "log",
20621
+ info: "log",
20622
+ warning: "warn",
20623
+ error: "error"
20578
20624
  };
20625
+ /** 组装上报 context(附加 session_token 后缀)并写一条本地 console。两条上报通道共用。 */
20626
+ function buildTelemetryContext(event, level, contents) {
20627
+ const sessionToken = idManager.getSessionToken() ?? "";
20628
+ const context = {
20629
+ session_token_suffix: sessionToken ? sessionToken.slice(-8) : "",
20630
+ connection_id: idManager.getConnectionId() ?? "",
20631
+ ...clientContextFields(),
20632
+ ...contents
20633
+ };
20634
+ const logMethod = TELEMETRY_LOG_METHOD[level] ?? "log";
20635
+ const propsDescription = Object.entries(contents).map(([k, v]) => `${k}=${v}`).join(", ");
20636
+ logger[logMethod](`[Telemetry] ${event} [${propsDescription}]`);
20637
+ return context;
20638
+ }
20639
+ /** 通过 OTel 上报(独立通道,失败隔离,不影响 PostHog)。 */
20640
+ function emitToOtel(event, level, context) {
20641
+ try {
20642
+ trackEventOtel(event, level, context);
20643
+ } catch (error) {
20644
+ logger.warn("[OTel] Dual-send failed:", error instanceof Error ? error.message : String(error));
20645
+ }
20646
+ }
20579
20647
  /**
20580
- * Set SDK log level
20581
- * Note: Local log writing is always enabled regardless of logLevel
20582
- * @param level SDK's LogLevel enum value
20648
+ * 日志上报接口:同时发往 PostHog OTel。
20649
+ * 用于 SDK 内部**日志类**事件(失败、状态变更、生命周期等)。
20650
+ * 指标类(延迟/帧率/时长/次数等度量)请用 {@link logMetric}——只发 OTel。
20651
+ * @param event Event name
20652
+ * @param level Log level
20653
+ * @param contents Log contents
20583
20654
  * @internal
20584
20655
  */
20585
- function setLogLevel(level) {
20586
- currentLogLevel = level;
20587
- switch (level) {
20588
- case LogLevel.off:
20589
- setGlobalLogLevel(LogLevel$1.Error);
20590
- break;
20591
- case LogLevel.error:
20592
- setGlobalLogLevel(LogLevel$1.Error);
20593
- break;
20594
- case LogLevel.warning:
20595
- setGlobalLogLevel(LogLevel$1.Warning);
20596
- break;
20597
- case LogLevel.all:
20598
- setGlobalLogLevel(LogLevel$1.Debug);
20599
- break;
20600
- default:
20601
- setGlobalLogLevel(LogLevel$1.Warning);
20602
- break;
20656
+ function logEvent(event, level = "info", contents = {}, opts = {}) {
20657
+ if (opts.rateLimit) {
20658
+ const suppressed = admitRateLimited(rateLimitKey(event, contents));
20659
+ if (suppressed === null) return;
20660
+ if (suppressed > 0) contents = {
20661
+ ...contents,
20662
+ suppressed_count: suppressed
20663
+ };
20603
20664
  }
20665
+ const context = buildTelemetryContext(event, level, contents);
20666
+ trackPostHogOnly(event, level, context);
20667
+ emitToOtel(event, level, context);
20668
+ }
20669
+ /**
20670
+ * 指标上报:**只发** OTel Metric 信号(Histogram,供聚合 P95/均值/SLO)。
20671
+ * 不发 PostHog,也不再附带一条 log。
20672
+ *
20673
+ * 曾经每条 metric 都双发一条同名 log。那条 log 里 95% 的字节是每条都重复的
20674
+ * resource 字段(一条约 1KB,有效载荷只有事件名 + value 约 50 字节),而数值本身
20675
+ * 已经在 metric 信号里,聚合查询走的也是 metric——log 那一路纯属冗余。一轮播放
20676
+ * 12 条 metric 就多出 12KB 重复数据。
20677
+ *
20678
+ * **需要高基数明细(avatar_id / conversation_id / trace_id 等)时,在调用点自己
20679
+ * 再发一条 {@link logMetricDetail}**——显式一行,比让每条 metric 都默认背一条 log 便宜得多。
20680
+ *
20681
+ * - `value` 被记录到 Histogram(延迟 ms / 帧率 / 时长 / 次数 / 比率等)
20682
+ * - `labels` 低基数标签(dsm / resolution / is_fallback / renderer_backend 等)。
20683
+ * **不要**放高基数字段,会撑爆 metric 基数。
20684
+ *
20685
+ * @param name Metric 名(如 `fetch_avatar_latency`)
20686
+ * @param value 被聚合的数值
20687
+ * @param labels 低基数标签
20688
+ * @internal
20689
+ */
20690
+ function logMetric(name, value, labels = {}) {
20691
+ recordMetric(name, value, labels);
20604
20692
  }
20605
20693
  /**
20606
- * Capture error context for PostHog
20694
+ * 一条 metric 的高基数明细,作为独立 log 发出(**只走 OTel,不发 PostHog**)。
20695
+ *
20696
+ * 事件名与对应 metric 同名——看板按名查;`props` 里放同一份低基数 labels +
20697
+ * 高基数明细,与 {@link logMetric} 曾经自带的那条记录一致。
20698
+ *
20699
+ * 只在真的有 metric 装不下的字段(avatar_id / conversation_id / trace_id /
20700
+ * description 等)时才调;没有明细就别发,那种 log 是 metric 的逐字重复。
20701
+ *
20702
+ * 与 android `SPLogger.logMetricDetail` / iOS `logMetricDetail` 同形。
20703
+ * @internal
20607
20704
  */
20608
- function captureErrorContext(level, error) {
20609
- trackEvent("logger_error", level, {
20610
- error: error instanceof Error ? error.message : String(error),
20611
- timestamp: Date.now(),
20612
- environment: "library",
20613
- user_agent: typeof navigator !== "undefined" ? navigator.userAgent : ""
20614
- });
20705
+ function logMetricDetail(name, value, props = {}) {
20706
+ emitToOtel(name, "info", buildTelemetryContext(name, "info", {
20707
+ value,
20708
+ ...props
20709
+ }));
20615
20710
  }
20616
20711
  //#endregion
20617
20712
  //#region node_modules/.pnpm/@bufbuild+protobuf@2.10.1/node_modules/@bufbuild/protobuf/dist/esm/wire/varint.js
@@ -24593,4 +24688,4 @@ function cleanupOtelTrace() {
24593
24688
  }
24594
24689
  }
24595
24690
  //#endregion
24596
- export { DEFAULT_REGION as $, monoTimestamp as A, resolveSdkVersion as B, logMetric as C, initializeOtel as D, cleanupOtel as E, cleanupOtelMetrics as F, idManager as G, OTEL_LOGS_ENDPOINT as H, initializeOtelMetrics as I, AvatarError as J, generateTraceId as K, recordHttpClientDuration as L, clockSync as M, fetchBootstrap as N, trackEventOtel as O, hostOf as P, DEFAULT_OPUS_BITRATE as Q, recordMetric as R, logEvent as S, updatePostHogPersonPropertiesForFlags as T, OTEL_STREAM_NAME as U, setSdkIdentity as V, isDebugMode as W, ConnectionState as X, AvatarState as Y, ConversationState as Z, logSink as _, startLoadTrace as a, LogLevel as at, getLogsFeatureFlag as b, AudioFormat as c, TransitionType as ct, MessageType as d, DEFAULT_REGION_REQUEST as et, TransportCompression as f, setLogLevel as g, logger as h, startInitTrace as i, LoadProgress as it, resolveMarks as j, monoMarkFrom as k, EgressType as l, requireSDK as lt, BinaryWriter as m, initializeOtelTrace as n, ErrorCode as nt, startPlaybackTrace as o, RENDER_QUALITY_PARAMS as ot, BinaryReader as p, AnimationType as q, startConnectTrace as r, FrameStarvationMode as rt, buildTraceparent as s, RenderQuality as st, cleanupOtelTrace as t, DrivingServiceMode as tt, Message as u, setSDKRef as ut, cleanupPostHog as v, trackEvent as w, initializePostHog as x, clientContextFields as y, getSdkPackage as z };
24691
+ export { DEFAULT_REGION as $, fetchBootstrap as A, OTEL_STREAM_NAME as B, cleanupOtel as C, monoTimestamp as D, monoMarkFrom as E, recordMetric as F, generateTraceId as G, logger as H, getSdkPackage as I, AvatarError as J, logSink as K, resolveSdkVersion as L, cleanupOtelMetrics as M, initializeOtelMetrics as N, resolveMarks as O, recordHttpClientDuration as P, DEFAULT_OPUS_BITRATE as Q, setSdkIdentity as R, updatePostHogPersonPropertiesForFlags as S, trackEventOtel as T, setLogLevel as U, isDebugMode as V, idManager as W, ConnectionState as X, AvatarState as Y, ConversationState as Z, getLogsFeatureFlag as _, startLoadTrace as a, LogLevel as at, logMetric as b, AudioFormat as c, TransitionType as ct, MessageType as d, __commonJSMin as dt, DEFAULT_REGION_REQUEST as et, TransportCompression as f, __toESM as ft, clientContextFields as g, cleanupPostHog as h, startInitTrace as i, LoadProgress as it, hostOf as j, clockSync as k, EgressType as l, requireSDK as lt, BinaryWriter as m, initializeOtelTrace as n, ErrorCode as nt, startPlaybackTrace as o, RENDER_QUALITY_PARAMS as ot, BinaryReader as p, AnimationType as q, startConnectTrace as r, FrameStarvationMode as rt, buildTraceparent as s, RenderQuality as st, cleanupOtelTrace as t, DrivingServiceMode as tt, Message as u, setSDKRef as ut, initializePostHog as v, initializeOtel as w, logMetricDetail as x, logEvent as y, OTEL_LOGS_ENDPOINT as z };