@antglobal/rlog-sdk 0.0.1755855517-dev.9 → 1.0.0

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.
Files changed (127) hide show
  1. package/README.md +192 -432
  2. package/dist/esm/index.d.ts +14 -41
  3. package/dist/esm/index.d.ts.map +1 -1
  4. package/dist/esm/index.js +92 -76
  5. package/dist/esm/lib/api.d.ts +10 -0
  6. package/dist/esm/lib/api.d.ts.map +1 -1
  7. package/dist/esm/lib/api.js +58 -35
  8. package/dist/esm/lib/config.d.ts +13 -6
  9. package/dist/esm/lib/config.d.ts.map +1 -1
  10. package/dist/esm/lib/config.js +61 -33
  11. package/dist/esm/lib/constants.d.ts +89 -0
  12. package/dist/esm/lib/constants.d.ts.map +1 -0
  13. package/dist/esm/lib/constants.js +145 -0
  14. package/dist/esm/lib/drive/indexeddb-adapt.d.ts +12 -0
  15. package/dist/esm/lib/drive/indexeddb-adapt.d.ts.map +1 -1
  16. package/dist/esm/lib/drive/indexeddb-adapt.js +190 -20
  17. package/dist/esm/lib/drive/localstorage-adapt.d.ts +12 -0
  18. package/dist/esm/lib/drive/localstorage-adapt.d.ts.map +1 -1
  19. package/dist/esm/lib/drive/localstorage-adapt.js +179 -36
  20. package/dist/esm/lib/drive/memory-adapt.d.ts +10 -2
  21. package/dist/esm/lib/drive/memory-adapt.d.ts.map +1 -1
  22. package/dist/esm/lib/drive/memory-adapt.js +118 -26
  23. package/dist/esm/lib/drive/safe-storage.d.ts +24 -0
  24. package/dist/esm/lib/drive/safe-storage.d.ts.map +1 -0
  25. package/dist/esm/lib/drive/safe-storage.js +96 -0
  26. package/dist/esm/lib/drive/storage-interface.d.ts +20 -0
  27. package/dist/esm/lib/drive/storage-interface.d.ts.map +1 -1
  28. package/dist/esm/lib/error-trigger.d.ts +73 -0
  29. package/dist/esm/lib/error-trigger.d.ts.map +1 -0
  30. package/dist/esm/lib/error-trigger.js +162 -0
  31. package/dist/esm/lib/error.d.ts +9 -0
  32. package/dist/esm/lib/error.d.ts.map +1 -1
  33. package/dist/esm/lib/error.js +70 -118
  34. package/dist/esm/lib/init.d.ts +0 -4
  35. package/dist/esm/lib/init.d.ts.map +1 -1
  36. package/dist/esm/lib/init.js +148 -47
  37. package/dist/esm/lib/logger.d.ts +27 -0
  38. package/dist/esm/lib/logger.d.ts.map +1 -0
  39. package/dist/esm/lib/logger.js +79 -0
  40. package/dist/esm/lib/net.d.ts +11 -0
  41. package/dist/esm/lib/net.d.ts.map +1 -1
  42. package/dist/esm/lib/net.js +264 -119
  43. package/dist/esm/lib/request.d.ts.map +1 -1
  44. package/dist/esm/lib/request.js +2 -2
  45. package/dist/esm/lib/router-monitor.d.ts.map +1 -1
  46. package/dist/esm/lib/router-monitor.js +135 -49
  47. package/dist/esm/lib/rrweb.d.ts.map +1 -1
  48. package/dist/esm/lib/rrweb.js +31 -24
  49. package/dist/esm/lib/storage-manager.d.ts +12 -0
  50. package/dist/esm/lib/storage-manager.d.ts.map +1 -1
  51. package/dist/esm/lib/storage-manager.js +129 -46
  52. package/dist/esm/lib/upload-worker-manager.d.ts +47 -0
  53. package/dist/esm/lib/upload-worker-manager.d.ts.map +1 -0
  54. package/dist/esm/lib/upload-worker-manager.js +559 -0
  55. package/dist/esm/lib/upload-worker.d.ts +58 -0
  56. package/dist/esm/lib/upload-worker.d.ts.map +1 -0
  57. package/dist/esm/lib/upload-worker.js +28 -0
  58. package/dist/esm/lib/uploader.d.ts +43 -0
  59. package/dist/esm/lib/uploader.d.ts.map +1 -1
  60. package/dist/esm/lib/uploader.js +464 -102
  61. package/dist/esm/lib/utils.d.ts +75 -0
  62. package/dist/esm/lib/utils.d.ts.map +1 -1
  63. package/dist/esm/lib/utils.js +268 -5
  64. package/dist/lib/index.d.ts +14 -41
  65. package/dist/lib/index.d.ts.map +1 -1
  66. package/dist/lib/index.js +81 -63
  67. package/dist/lib/lib/api.d.ts +10 -0
  68. package/dist/lib/lib/api.d.ts.map +1 -1
  69. package/dist/lib/lib/api.js +59 -35
  70. package/dist/lib/lib/config.d.ts +13 -6
  71. package/dist/lib/lib/config.d.ts.map +1 -1
  72. package/dist/lib/lib/config.js +63 -33
  73. package/dist/lib/lib/constants.d.ts +89 -0
  74. package/dist/lib/lib/constants.d.ts.map +1 -0
  75. package/dist/lib/lib/constants.js +151 -0
  76. package/dist/lib/lib/drive/indexeddb-adapt.d.ts +12 -0
  77. package/dist/lib/lib/drive/indexeddb-adapt.d.ts.map +1 -1
  78. package/dist/lib/lib/drive/indexeddb-adapt.js +191 -19
  79. package/dist/lib/lib/drive/localstorage-adapt.d.ts +12 -0
  80. package/dist/lib/lib/drive/localstorage-adapt.d.ts.map +1 -1
  81. package/dist/lib/lib/drive/localstorage-adapt.js +179 -36
  82. package/dist/lib/lib/drive/memory-adapt.d.ts +10 -2
  83. package/dist/lib/lib/drive/memory-adapt.d.ts.map +1 -1
  84. package/dist/lib/lib/drive/memory-adapt.js +117 -26
  85. package/dist/lib/lib/drive/safe-storage.d.ts +24 -0
  86. package/dist/lib/lib/drive/safe-storage.d.ts.map +1 -0
  87. package/dist/lib/lib/drive/safe-storage.js +102 -0
  88. package/dist/lib/lib/drive/storage-interface.d.ts +20 -0
  89. package/dist/lib/lib/drive/storage-interface.d.ts.map +1 -1
  90. package/dist/lib/lib/error-trigger.d.ts +73 -0
  91. package/dist/lib/lib/error-trigger.d.ts.map +1 -0
  92. package/dist/lib/lib/error-trigger.js +167 -0
  93. package/dist/lib/lib/error.d.ts +9 -0
  94. package/dist/lib/lib/error.d.ts.map +1 -1
  95. package/dist/lib/lib/error.js +73 -118
  96. package/dist/lib/lib/init.d.ts +0 -4
  97. package/dist/lib/lib/init.d.ts.map +1 -1
  98. package/dist/lib/lib/init.js +144 -43
  99. package/dist/lib/lib/logger.d.ts +27 -0
  100. package/dist/lib/lib/logger.d.ts.map +1 -0
  101. package/dist/lib/lib/logger.js +84 -0
  102. package/dist/lib/lib/net.d.ts +11 -0
  103. package/dist/lib/lib/net.d.ts.map +1 -1
  104. package/dist/lib/lib/net.js +268 -120
  105. package/dist/lib/lib/request.d.ts.map +1 -1
  106. package/dist/lib/lib/request.js +3 -3
  107. package/dist/lib/lib/router-monitor.d.ts.map +1 -1
  108. package/dist/lib/lib/router-monitor.js +136 -49
  109. package/dist/lib/lib/rrweb.d.ts.map +1 -1
  110. package/dist/lib/lib/rrweb.js +31 -23
  111. package/dist/lib/lib/storage-manager.d.ts +12 -0
  112. package/dist/lib/lib/storage-manager.d.ts.map +1 -1
  113. package/dist/lib/lib/storage-manager.js +130 -46
  114. package/dist/lib/lib/upload-worker-manager.d.ts +47 -0
  115. package/dist/lib/lib/upload-worker-manager.d.ts.map +1 -0
  116. package/dist/lib/lib/upload-worker-manager.js +570 -0
  117. package/dist/lib/lib/upload-worker.d.ts +58 -0
  118. package/dist/lib/lib/upload-worker.d.ts.map +1 -0
  119. package/dist/lib/lib/upload-worker.js +33 -0
  120. package/dist/lib/lib/uploader.d.ts +43 -0
  121. package/dist/lib/lib/uploader.d.ts.map +1 -1
  122. package/dist/lib/lib/uploader.js +468 -101
  123. package/dist/lib/lib/utils.d.ts +75 -0
  124. package/dist/lib/lib/utils.d.ts.map +1 -1
  125. package/dist/lib/lib/utils.js +276 -6
  126. package/dist/rlog-sdk.min.js +1 -1
  127. package/package.json +3 -2
@@ -1,3 +1,78 @@
1
1
  export declare const generateUUIDCompat: () => string;
2
2
  export declare const getDeviceId: () => string;
3
+ /**
4
+ * session 过期时间(1小时)
5
+ * 超过此时间的 session 数据将在下次 SDK 初始化时被清理
6
+ */
7
+ /**
8
+ * 获取当前标签页的 sessionId
9
+ * 首次调用时自动生成并注册
10
+ */
11
+ export declare const getSessionId: () => string;
12
+ /**
13
+ * 获取存储用的复合键(deviceId_sessionId)
14
+ * 用于替代原来单独使用 deviceId 作为存储分区键
15
+ * 确保多标签页的录制数据互相隔离
16
+ */
17
+ export declare const getStorageKey: () => string;
18
+ /**
19
+ * 从注册表中移除指定 sessionId
20
+ */
21
+ export declare function unregisterSession(sessionId: string): void;
22
+ /**
23
+ * 清理过期的 session 数据
24
+ * 在 SDK 初始化时调用,扫描注册表中超过 SESSION_MAX_AGE 的 session,
25
+ * 删除其对应的存储数据和锁,并从注册表中移除
26
+ */
27
+ export declare function cleanupStaleSessions(): void;
28
+ /**
29
+ * 孤儿 session 数据的最大有效时间跨度(默认 2 分钟)
30
+ * 只有数据时间跨度在此范围内的才被视为"上传周期内的残留数据",
31
+ * 超过此范围的可能是其他无关项目或异常数据,不予上传
32
+ */
33
+ /**
34
+ * 孤儿 session 数据的最大年龄(默认 5 分钟)
35
+ * 只有 session 注册时间在此范围内的才被视为"近期的残留数据",
36
+ * 超过此范围的可能是长时间未清理的旧数据
37
+ */
38
+ /**
39
+ * 孤儿 session 信息
40
+ */
41
+ export interface OrphanSessionInfo {
42
+ sessionId: string;
43
+ storageKey: string;
44
+ }
45
+ /**
46
+ * 获取所有孤儿 session(注册表中存在但不属于当前标签页的 session)
47
+ * 仅返回近期的、可能包含残留数据的 session
48
+ *
49
+ * 判断条件:
50
+ * 1. 不是当前标签页的 sessionId
51
+ * 2. session 注册时间在 ORPHAN_SESSION_MAX_AGE 范围内(排除过老的数据)
52
+ * 3. 对应的 localStorage 中确实存在数据
53
+ */
54
+ export declare function getOrphanSessions(): OrphanSessionInfo[];
55
+ /**
56
+ * 检查孤儿 session 的数据是否在合理的时间跨度内
57
+ * 用于过滤掉可能是其他无关项目或异常的数据
58
+ *
59
+ * @param events 事件数组
60
+ * @returns 是否在合理范围内
61
+ */
62
+ export declare function isOrphanDataValid(events: any[]): boolean;
63
+ /**
64
+ * 清理指定孤儿 session 的数据和注册信息
65
+ */
66
+ export declare function cleanupOrphanSession(sessionId: string): void;
67
+ /**
68
+ * 检查值是否为纯对象(非数组、非null)
69
+ */
70
+ export declare const isPlainObject: (value: any) => value is Record<string, any>;
71
+ /**
72
+ * 深度合并配置对象
73
+ * @param target 目标配置(默认配置)
74
+ * @param source 源配置(新配置)
75
+ * @returns 合并后的配置
76
+ */
77
+ export declare const deepMergeConfig: <T extends Record<string, any>>(target: T, source: Partial<T>) => T;
3
78
  //# sourceMappingURL=utils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,cAM9B,CAAC;AAEF,eAAO,MAAM,WAAW,cAYvB,CAAC"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.ts"],"names":[],"mappings":"AAaA,eAAO,MAAM,kBAAkB,cAM9B,CAAC;AAEF,eAAO,MAAM,WAAW,cAYvB,CAAC;AAgBF;;;GAGG;AAGH;;;GAGG;AACH,eAAO,MAAM,YAAY,QAAO,MAM/B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,aAAa,QAAO,MAEhC,CAAC;AAeF;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAQzD;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,IAAI,IAAI,CA0B3C;AAID;;;;GAIG;AAGH;;;;GAIG;AAGH;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,wBAAgB,iBAAiB,IAAI,iBAAiB,EAAE,CAkCvD;AAED;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CA0BxD;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAW5D;AAED;;GAEG;AACH,eAAO,MAAM,aAAa,UAAW,GAAG,iCAEvC,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,eAAe,0CAClB,CAAC,UACD,QAAQ,CAAC,CAAC,KACjB,CAsBF,CAAC"}
@@ -3,7 +3,25 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.getDeviceId = exports.generateUUIDCompat = void 0;
6
+ exports.cleanupOrphanSession = cleanupOrphanSession;
7
+ exports.cleanupStaleSessions = cleanupStaleSessions;
8
+ exports.getDeviceId = exports.generateUUIDCompat = exports.deepMergeConfig = void 0;
9
+ exports.getOrphanSessions = getOrphanSessions;
10
+ exports.getStorageKey = exports.getSessionId = void 0;
11
+ exports.isOrphanDataValid = isOrphanDataValid;
12
+ exports.isPlainObject = void 0;
13
+ exports.unregisterSession = unregisterSession;
14
+ var _safeStorage = require("./drive/safe-storage");
15
+ var _constants = require("./constants");
16
+ function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
17
+ function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
18
+ function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
19
+ function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == _typeof(i) ? i : String(i); }
20
+ function _toPrimitive(t, r) { if ("object" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != _typeof(i)) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
21
+ function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); }
22
+ function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }
23
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
24
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }
7
25
  var generateUUIDCompat = exports.generateUUIDCompat = function generateUUIDCompat() {
8
26
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
9
27
  var r = Math.random() * 16 | 0;
@@ -12,11 +30,263 @@ var generateUUIDCompat = exports.generateUUIDCompat = function generateUUIDCompa
12
30
  });
13
31
  };
14
32
  var getDeviceId = exports.getDeviceId = function getDeviceId() {
15
- var _localStorage, _localStorage2, _localStorage3;
16
- if (localStorage.getItem('rlog-deviceId')) {
17
- return localStorage.getItem('rlog-deviceId');
33
+ if (_safeStorage.safeStorage.getItem(_constants.STORAGE_KEY_DEVICE_ID)) {
34
+ return _safeStorage.safeStorage.getItem(_constants.STORAGE_KEY_DEVICE_ID);
18
35
  }
19
- var newId = ((_localStorage = localStorage) === null || _localStorage === void 0 ? void 0 : _localStorage.getItem('utoken')) || ((_localStorage2 = localStorage) === null || _localStorage2 === void 0 ? void 0 : _localStorage2.getItem('IWP-iwp-deivceTag')) || generateUUIDCompat();
20
- (_localStorage3 = localStorage) === null || _localStorage3 === void 0 || _localStorage3.setItem('rlog-deviceId', newId);
36
+ var newId = _safeStorage.safeStorage.getItem(_constants.STORAGE_KEY_UTOKEN) || _safeStorage.safeStorage.getItem(_constants.STORAGE_KEY_IWP_DEVICE_TAG) || generateUUIDCompat();
37
+ _safeStorage.safeStorage.setItem(_constants.STORAGE_KEY_DEVICE_ID, newId);
21
38
  return newId;
39
+ };
40
+
41
+ // ==================== Session 隔离 ====================
42
+
43
+ /**
44
+ * 当前标签页的 sessionId(内存中,每次页面加载生成新的)
45
+ * 用于隔离同域下多个标签页的录制数据
46
+ */
47
+ var currentSessionId = null;
48
+
49
+ /**
50
+ * session 注册表的存储 key
51
+ * 注册表结构: { [sessionId]: timestamp }
52
+ */
53
+ var SESSION_REGISTRY_KEY = _constants.STORAGE_KEY_SESSION_REGISTRY;
54
+
55
+ /**
56
+ * session 过期时间(1小时)
57
+ * 超过此时间的 session 数据将在下次 SDK 初始化时被清理
58
+ */
59
+ // SESSION_MAX_AGE 已从 constants.ts 导入
60
+
61
+ /**
62
+ * 获取当前标签页的 sessionId
63
+ * 首次调用时自动生成并注册
64
+ */
65
+ var getSessionId = exports.getSessionId = function getSessionId() {
66
+ if (!currentSessionId) {
67
+ currentSessionId = generateUUIDCompat();
68
+ registerSession(currentSessionId);
69
+ }
70
+ return currentSessionId;
71
+ };
72
+
73
+ /**
74
+ * 获取存储用的复合键(deviceId_sessionId)
75
+ * 用于替代原来单独使用 deviceId 作为存储分区键
76
+ * 确保多标签页的录制数据互相隔离
77
+ */
78
+ var getStorageKey = exports.getStorageKey = function getStorageKey() {
79
+ return "".concat(getDeviceId(), "_").concat(getSessionId());
80
+ };
81
+
82
+ /**
83
+ * 将 sessionId 注册到注册表中
84
+ */
85
+ function registerSession(sessionId) {
86
+ try {
87
+ var registry = JSON.parse(_safeStorage.safeStorage.getItem(SESSION_REGISTRY_KEY) || '{}');
88
+ registry[sessionId] = Date.now();
89
+ _safeStorage.safeStorage.setItem(SESSION_REGISTRY_KEY, JSON.stringify(registry));
90
+ } catch (e) {
91
+ // 解析失败时静默忽略
92
+ }
93
+ }
94
+
95
+ /**
96
+ * 从注册表中移除指定 sessionId
97
+ */
98
+ function unregisterSession(sessionId) {
99
+ try {
100
+ var registry = JSON.parse(_safeStorage.safeStorage.getItem(SESSION_REGISTRY_KEY) || '{}');
101
+ delete registry[sessionId];
102
+ _safeStorage.safeStorage.setItem(SESSION_REGISTRY_KEY, JSON.stringify(registry));
103
+ } catch (e) {
104
+ // 解析失败时静默忽略
105
+ }
106
+ }
107
+
108
+ /**
109
+ * 清理过期的 session 数据
110
+ * 在 SDK 初始化时调用,扫描注册表中超过 SESSION_MAX_AGE 的 session,
111
+ * 删除其对应的存储数据和锁,并从注册表中移除
112
+ */
113
+ function cleanupStaleSessions() {
114
+ try {
115
+ var registry = JSON.parse(_safeStorage.safeStorage.getItem(SESSION_REGISTRY_KEY) || '{}');
116
+ var now = Date.now();
117
+ var deviceId = getDeviceId();
118
+ var changed = false;
119
+ for (var _i = 0, _Object$keys = Object.keys(registry); _i < _Object$keys.length; _i++) {
120
+ var sessionId = _Object$keys[_i];
121
+ var createdAt = registry[sessionId];
122
+ if (now - createdAt > _constants.SESSION_MAX_AGE) {
123
+ // 清理该 session 对应的存储数据和锁
124
+ var storageKey = "".concat(_constants.STORAGE_KEY_DATA_PREFIX).concat(deviceId, "_").concat(sessionId);
125
+ var lockKey = "".concat(_constants.STORAGE_KEY_LOCK_PREFIX).concat(deviceId, "_").concat(sessionId);
126
+ _safeStorage.safeStorage.removeItem(storageKey);
127
+ _safeStorage.safeStorage.removeItem(lockKey);
128
+ delete registry[sessionId];
129
+ changed = true;
130
+ }
131
+ }
132
+ if (changed) {
133
+ _safeStorage.safeStorage.setItem(SESSION_REGISTRY_KEY, JSON.stringify(registry));
134
+ }
135
+ } catch (e) {
136
+ // 解析失败时静默忽略
137
+ }
138
+ }
139
+
140
+ // ==================== 孤儿 Session 残留数据扫描 ====================
141
+
142
+ /**
143
+ * 孤儿 session 数据的最大有效时间跨度(默认 2 分钟)
144
+ * 只有数据时间跨度在此范围内的才被视为"上传周期内的残留数据",
145
+ * 超过此范围的可能是其他无关项目或异常数据,不予上传
146
+ */
147
+ // ORPHAN_DATA_MAX_SPAN 已从 constants.ts 导入
148
+
149
+ /**
150
+ * 孤儿 session 数据的最大年龄(默认 5 分钟)
151
+ * 只有 session 注册时间在此范围内的才被视为"近期的残留数据",
152
+ * 超过此范围的可能是长时间未清理的旧数据
153
+ */
154
+ // ORPHAN_SESSION_MAX_AGE 已从 constants.ts 导入
155
+
156
+ /**
157
+ * 孤儿 session 信息
158
+ */
159
+
160
+ /**
161
+ * 获取所有孤儿 session(注册表中存在但不属于当前标签页的 session)
162
+ * 仅返回近期的、可能包含残留数据的 session
163
+ *
164
+ * 判断条件:
165
+ * 1. 不是当前标签页的 sessionId
166
+ * 2. session 注册时间在 ORPHAN_SESSION_MAX_AGE 范围内(排除过老的数据)
167
+ * 3. 对应的 localStorage 中确实存在数据
168
+ */
169
+ function getOrphanSessions() {
170
+ try {
171
+ var registry = JSON.parse(_safeStorage.safeStorage.getItem(SESSION_REGISTRY_KEY) || '{}');
172
+ var now = Date.now();
173
+ var deviceId = getDeviceId();
174
+ var mySessionId = getSessionId();
175
+ var orphans = [];
176
+ for (var _i2 = 0, _Object$keys2 = Object.keys(registry); _i2 < _Object$keys2.length; _i2++) {
177
+ var sessionId = _Object$keys2[_i2];
178
+ // 跳过当前标签页的 session
179
+ if (sessionId === mySessionId) continue;
180
+ var createdAt = registry[sessionId];
181
+
182
+ // 跳过过期的 session(由 cleanupStaleSessions 处理)
183
+ if (now - createdAt > _constants.SESSION_MAX_AGE) continue;
184
+
185
+ // 只处理近期的 session(ORPHAN_SESSION_MAX_AGE 范围内)
186
+ if (now - createdAt > _constants.ORPHAN_SESSION_MAX_AGE) continue;
187
+ var storageKey = "".concat(deviceId, "_").concat(sessionId);
188
+ var dataKey = "".concat(_constants.STORAGE_KEY_DATA_PREFIX).concat(storageKey);
189
+
190
+ // 检查是否有残留数据
191
+ var rawData = _safeStorage.safeStorage.getItem(dataKey);
192
+ if (!rawData || rawData === '[]') continue;
193
+ orphans.push({
194
+ sessionId: sessionId,
195
+ storageKey: storageKey
196
+ });
197
+ }
198
+ return orphans;
199
+ } catch (e) {
200
+ return [];
201
+ }
202
+ }
203
+
204
+ /**
205
+ * 检查孤儿 session 的数据是否在合理的时间跨度内
206
+ * 用于过滤掉可能是其他无关项目或异常的数据
207
+ *
208
+ * @param events 事件数组
209
+ * @returns 是否在合理范围内
210
+ */
211
+ function isOrphanDataValid(events) {
212
+ if (!events || events.length === 0) return false;
213
+
214
+ // 找到最早和最晚的事件时间戳
215
+ var minTime = Infinity;
216
+ var maxTime = -Infinity;
217
+ var _iterator = _createForOfIteratorHelper(events),
218
+ _step;
219
+ try {
220
+ for (_iterator.s(); !(_step = _iterator.n()).done;) {
221
+ var event = _step.value;
222
+ if (event && typeof event.timestamp === 'number') {
223
+ if (event.timestamp < minTime) minTime = event.timestamp;
224
+ if (event.timestamp > maxTime) maxTime = event.timestamp;
225
+ }
226
+ }
227
+
228
+ // 如果没有有效的时间戳,不上传
229
+ } catch (err) {
230
+ _iterator.e(err);
231
+ } finally {
232
+ _iterator.f();
233
+ }
234
+ if (minTime === Infinity || maxTime === -Infinity) return false;
235
+
236
+ // 检查数据时间跨度是否在合理范围内
237
+ var span = maxTime - minTime;
238
+ if (span > _constants.ORPHAN_DATA_MAX_SPAN) return false;
239
+
240
+ // 检查数据是否太旧(最新事件距今超过 ORPHAN_SESSION_MAX_AGE)
241
+ var now = Date.now();
242
+ if (now - maxTime > _constants.ORPHAN_SESSION_MAX_AGE) return false;
243
+ return true;
244
+ }
245
+
246
+ /**
247
+ * 清理指定孤儿 session 的数据和注册信息
248
+ */
249
+ function cleanupOrphanSession(sessionId) {
250
+ try {
251
+ var deviceId = getDeviceId();
252
+ var storageKey = "".concat(_constants.STORAGE_KEY_DATA_PREFIX).concat(deviceId, "_").concat(sessionId);
253
+ var lockKey = "".concat(_constants.STORAGE_KEY_LOCK_PREFIX).concat(deviceId, "_").concat(sessionId);
254
+ _safeStorage.safeStorage.removeItem(storageKey);
255
+ _safeStorage.safeStorage.removeItem(lockKey);
256
+ unregisterSession(sessionId);
257
+ } catch (e) {
258
+ // 静默忽略
259
+ }
260
+ }
261
+
262
+ /**
263
+ * 检查值是否为纯对象(非数组、非null)
264
+ */
265
+ var isPlainObject = exports.isPlainObject = function isPlainObject(value) {
266
+ return value !== null && _typeof(value) === 'object' && !Array.isArray(value);
267
+ };
268
+
269
+ /**
270
+ * 深度合并配置对象
271
+ * @param target 目标配置(默认配置)
272
+ * @param source 源配置(新配置)
273
+ * @returns 合并后的配置
274
+ */
275
+ var deepMergeConfig = exports.deepMergeConfig = function deepMergeConfig(target, source) {
276
+ var result = _objectSpread({}, target);
277
+ for (var key in source) {
278
+ if (source.hasOwnProperty(key)) {
279
+ var sourceValue = source[key];
280
+ var targetValue = target[key];
281
+
282
+ // 如果两个值都是纯对象,则递归合并
283
+ if (isPlainObject(sourceValue) && isPlainObject(targetValue)) {
284
+ result[key] = deepMergeConfig(targetValue, sourceValue);
285
+ } else if (sourceValue !== undefined) {
286
+ // 其他情况(包括数组、基本类型、null)直接覆盖
287
+ result[key] = sourceValue;
288
+ }
289
+ }
290
+ }
291
+ return result;
22
292
  };