@antglobal/rlog-sdk 0.0.1755855517-dev.8 → 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 +14 -16
  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 -116
  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 +14 -16
  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 -117
  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,45 +1,64 @@
1
1
  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); }
2
2
  import { getConfig } from "./config";
3
3
  import { record } from 'rrweb';
4
+ import logger from "./logger";
5
+ import { EVENT_CUSTOM_ERROR } from "./constants";
4
6
 
5
- // 存储事件监听器的引用,用于清理
6
- var eventListeners = [];
7
+ // 错误触发器引用(错误采集模式下由 init.ts 注入)
8
+ var errorTriggerInstance = null;
7
9
 
8
- // 错误数据发送函数 - 使用 rrweb 的自定义事件功能
9
- export var sendErrorToAnalytics = function sendErrorToAnalytics(data) {
10
- var config = getConfig();
10
+ // 标记是否已初始化
11
+ var isInitialized = false;
11
12
 
12
- // 如果错误处理未启用,直接返回
13
- if (!config.error) {
14
- return;
15
- }
13
+ /**
14
+ * 设置错误触发器实例(错误采集模式下由 init.ts 调用)
15
+ */
16
+ export function setErrorTrigger(trigger) {
17
+ errorTriggerInstance = trigger;
18
+ }
16
19
 
20
+ /**
21
+ * 获取错误触发器实例
22
+ */
23
+ export function getErrorTrigger() {
24
+ return errorTriggerInstance;
25
+ }
26
+
27
+ // 错误数据发送函数 - 使用 rrweb 的自定义事件功能
28
+ export var sendErrorToAnalytics = function sendErrorToAnalytics(data) {
17
29
  // 使用 rrweb 的自定义事件功能上报错误
18
30
  try {
19
- record.addCustomEvent('custom-error-event', data);
31
+ record.addCustomEvent(EVENT_CUSTOM_ERROR, data);
20
32
  } catch (error) {
21
33
  // 降级方案:直接控制台输出
22
- console.log('RLog Error captured:', data);
34
+ logger.error('Error captured', data);
23
35
  }
24
- };
25
-
26
- // 初始化错误处理
27
- export function initErrorHandler() {
28
- var config = getConfig();
29
36
 
30
- // 如果错误处理未启用,不注册任何事件监听器
31
- if (!config.error) {
32
- console.log('RLog error handling is disabled by config');
33
- return;
37
+ // 错误采集模式下,通知错误触发器
38
+ try {
39
+ var config = getConfig();
40
+ if (config.captureMode === 'error' && errorTriggerInstance) {
41
+ errorTriggerInstance.onError({
42
+ type: data.type,
43
+ message: data.message || data.type,
44
+ timestamp: data.timestamp || Date.now(),
45
+ detail: data
46
+ });
47
+ }
48
+ } catch (error) {
49
+ logger.warn('Failed to notify error trigger:', error);
34
50
  }
35
- console.log('RLog error handling is enabled');
51
+ };
36
52
 
37
- // JavaScript 运行时错误处理
38
- var errorHandler = function errorHandler(event) {
53
+ /**
54
+ * JavaScript 运行时错误 & 资源加载错误处理
55
+ */
56
+ function handleError(event) {
57
+ try {
39
58
  var errorEvent = event;
59
+
40
60
  // 检查是否是资源加载错误
41
61
  if (event.target !== window) {
42
- // 资源加载错误
43
62
  var _errorData = {
44
63
  type: 'RESOURCE_ERROR',
45
64
  resourceType: event.target.tagName,
@@ -71,20 +90,20 @@ export function initErrorHandler() {
71
90
  location: window.location.href
72
91
  };
73
92
  sendErrorToAnalytics(errorData);
93
+ } catch (e) {
94
+ // SDK 错误处理自身不能再抛异常,避免死循环
95
+ logger.warn('Failed to handle unhandled rejection:', e);
96
+ }
74
97
 
75
- // 控制台保留原始错误显示
76
- return false;
77
- };
78
- window.addEventListener('error', errorHandler, true);
79
- eventListeners.push({
80
- target: window,
81
- type: 'error',
82
- listener: errorHandler,
83
- options: true
84
- });
98
+ // 控制台保留原始错误显示
99
+ return false;
100
+ }
85
101
 
86
- // 拦截未处理的 Promise 错误
87
- var unhandledRejectionHandler = function unhandledRejectionHandler(event) {
102
+ /**
103
+ * 未处理的 Promise 错误处理
104
+ */
105
+ function handleUnhandledRejection(event) {
106
+ try {
88
107
  var rejectionEvent = event;
89
108
  var reason = rejectionEvent.reason || 'Unknown rejection';
90
109
  var errorData = {
@@ -95,91 +114,24 @@ export function initErrorHandler() {
95
114
  location: window.location.href
96
115
  };
97
116
  sendErrorToAnalytics(errorData);
98
- // 阻止默认控制台报错
99
- event.preventDefault();
100
- };
101
- window.addEventListener('unhandledrejection', unhandledRejectionHandler);
102
- eventListeners.push({
103
- target: window,
104
- type: 'unhandledrejection',
105
- listener: unhandledRejectionHandler
106
- });
107
-
108
- // 监控页面性能相关事件
109
- var loadHandler = function loadHandler() {
110
- sendErrorToAnalytics({
111
- type: 'PAGE_LOAD',
112
- url: window.location.href,
113
- timestamp: Date.now()
114
- });
115
- };
116
- window.addEventListener('load', loadHandler);
117
- eventListeners.push({
118
- target: window,
119
- type: 'load',
120
- listener: loadHandler
121
- });
122
-
123
- // 监控页面卸载事件
124
- var beforeUnloadHandler = function beforeUnloadHandler() {
125
- sendErrorToAnalytics({
126
- type: 'PAGE_UNLOAD',
127
- url: window.location.href,
128
- timestamp: Date.now()
129
- });
130
- };
131
- window.addEventListener('beforeunload', beforeUnloadHandler);
132
- eventListeners.push({
133
- target: window,
134
- type: 'beforeunload',
135
- listener: beforeUnloadHandler
136
- });
117
+ } catch (e) {
118
+ // SDK 错误处理自身不能再抛异常,避免死循环
119
+ logger.warn('Failed to handle unhandled rejection:', e);
120
+ }
121
+ }
137
122
 
138
- // 监控网络连接状态变化
139
- var onlineHandler = function onlineHandler() {
140
- sendErrorToAnalytics({
141
- type: 'NETWORK_ONLINE',
142
- timestamp: Date.now()
143
- });
144
- };
145
- window.addEventListener('online', onlineHandler);
146
- eventListeners.push({
147
- target: window,
148
- type: 'online',
149
- listener: onlineHandler
150
- });
151
- var offlineHandler = function offlineHandler() {
152
- sendErrorToAnalytics({
153
- type: 'NETWORK_OFFLINE',
154
- timestamp: Date.now()
155
- });
156
- };
157
- window.addEventListener('offline', offlineHandler);
158
- eventListeners.push({
159
- target: window,
160
- type: 'offline',
161
- listener: offlineHandler
162
- });
123
+ // 初始化错误处理
124
+ export function initErrorHandler() {
125
+ if (isInitialized) return;
126
+ window.addEventListener('error', handleError, true);
127
+ window.addEventListener('unhandledrejection', handleUnhandledRejection);
128
+ isInitialized = true;
163
129
  }
164
130
 
165
131
  // 清理错误监听器
166
132
  export function cleanupErrorHandler() {
167
- console.log('Cleaning up RLog error handlers...');
168
-
169
- // 移除所有注册的事件监听器
170
- eventListeners.forEach(function (_ref) {
171
- var target = _ref.target,
172
- type = _ref.type,
173
- listener = _ref.listener,
174
- options = _ref.options;
175
- try {
176
- target.removeEventListener(type, listener, options);
177
- } catch (error) {
178
- console.warn("Failed to remove event listener for ".concat(type, ":"), error);
179
- }
180
- });
181
-
182
- // 清空监听器数组
183
- eventListeners.length = 0;
184
- console.log('RLog error handlers cleaned up successfully');
133
+ if (!isInitialized) return;
134
+ window.removeEventListener('error', handleError, true);
135
+ window.removeEventListener('unhandledrejection', handleUnhandledRejection);
136
+ isInitialized = false;
185
137
  }
@@ -10,10 +10,6 @@ export declare function cancelRlog(options?: {
10
10
  * 重置取消状态(用于重新初始化)
11
11
  */
12
12
  export declare function resetCancelState(): void;
13
- /**
14
- * 获取当前取消状态
15
- */
16
- export declare function getCancelState(): boolean;
17
13
  /**
18
14
  * 初始化 RLog SDK
19
15
  * @param serv 服务器地址
@@ -1 +1 @@
1
- {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/lib/init.ts"],"names":[],"mappings":"AAYA;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,EACrC,OAAO,GAAE,MAAuB,GAC/B,IAAI,CAwCN;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED;;GAEG;AACH,wBAAgB,cAAc,IAAI,OAAO,CAExC;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI,CAuCN"}
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../../src/lib/init.ts"],"names":[],"mappings":"AAsBA;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAO,EACrC,OAAO,GAAE,MAAuB,GAC/B,IAAI,CA2DN;AAED;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAEvC;AAED;;;;;GAKG;AACH,wBAAgB,QAAQ,CACtB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,YAAY,CAAC,EAAE,MAAM,GACpB,IAAI,CAwGN"}
@@ -1,15 +1,25 @@
1
+ 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); }
2
+ function _regeneratorRuntime() { "use strict"; /*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */ _regeneratorRuntime = function _regeneratorRuntime() { return e; }; var t, e = {}, r = Object.prototype, n = r.hasOwnProperty, o = Object.defineProperty || function (t, e, r) { t[e] = r.value; }, i = "function" == typeof Symbol ? Symbol : {}, a = i.iterator || "@@iterator", c = i.asyncIterator || "@@asyncIterator", u = i.toStringTag || "@@toStringTag"; function define(t, e, r) { return Object.defineProperty(t, e, { value: r, enumerable: !0, configurable: !0, writable: !0 }), t[e]; } try { define({}, ""); } catch (t) { define = function define(t, e, r) { return t[e] = r; }; } function wrap(t, e, r, n) { var i = e && e.prototype instanceof Generator ? e : Generator, a = Object.create(i.prototype), c = new Context(n || []); return o(a, "_invoke", { value: makeInvokeMethod(t, r, c) }), a; } function tryCatch(t, e, r) { try { return { type: "normal", arg: t.call(e, r) }; } catch (t) { return { type: "throw", arg: t }; } } e.wrap = wrap; var h = "suspendedStart", l = "suspendedYield", f = "executing", s = "completed", y = {}; function Generator() {} function GeneratorFunction() {} function GeneratorFunctionPrototype() {} var p = {}; define(p, a, function () { return this; }); var d = Object.getPrototypeOf, v = d && d(d(values([]))); v && v !== r && n.call(v, a) && (p = v); var g = GeneratorFunctionPrototype.prototype = Generator.prototype = Object.create(p); function defineIteratorMethods(t) { ["next", "throw", "return"].forEach(function (e) { define(t, e, function (t) { return this._invoke(e, t); }); }); } function AsyncIterator(t, e) { function invoke(r, o, i, a) { var c = tryCatch(t[r], t, o); if ("throw" !== c.type) { var u = c.arg, h = u.value; return h && "object" == _typeof(h) && n.call(h, "__await") ? e.resolve(h.__await).then(function (t) { invoke("next", t, i, a); }, function (t) { invoke("throw", t, i, a); }) : e.resolve(h).then(function (t) { u.value = t, i(u); }, function (t) { return invoke("throw", t, i, a); }); } a(c.arg); } var r; o(this, "_invoke", { value: function value(t, n) { function callInvokeWithMethodAndArg() { return new e(function (e, r) { invoke(t, n, e, r); }); } return r = r ? r.then(callInvokeWithMethodAndArg, callInvokeWithMethodAndArg) : callInvokeWithMethodAndArg(); } }); } function makeInvokeMethod(e, r, n) { var o = h; return function (i, a) { if (o === f) throw new Error("Generator is already running"); if (o === s) { if ("throw" === i) throw a; return { value: t, done: !0 }; } for (n.method = i, n.arg = a;;) { var c = n.delegate; if (c) { var u = maybeInvokeDelegate(c, n); if (u) { if (u === y) continue; return u; } } if ("next" === n.method) n.sent = n._sent = n.arg;else if ("throw" === n.method) { if (o === h) throw o = s, n.arg; n.dispatchException(n.arg); } else "return" === n.method && n.abrupt("return", n.arg); o = f; var p = tryCatch(e, r, n); if ("normal" === p.type) { if (o = n.done ? s : l, p.arg === y) continue; return { value: p.arg, done: n.done }; } "throw" === p.type && (o = s, n.method = "throw", n.arg = p.arg); } }; } function maybeInvokeDelegate(e, r) { var n = r.method, o = e.iterator[n]; if (o === t) return r.delegate = null, "throw" === n && e.iterator.return && (r.method = "return", r.arg = t, maybeInvokeDelegate(e, r), "throw" === r.method) || "return" !== n && (r.method = "throw", r.arg = new TypeError("The iterator does not provide a '" + n + "' method")), y; var i = tryCatch(o, e.iterator, r.arg); if ("throw" === i.type) return r.method = "throw", r.arg = i.arg, r.delegate = null, y; var a = i.arg; return a ? a.done ? (r[e.resultName] = a.value, r.next = e.nextLoc, "return" !== r.method && (r.method = "next", r.arg = t), r.delegate = null, y) : a : (r.method = "throw", r.arg = new TypeError("iterator result is not an object"), r.delegate = null, y); } function pushTryEntry(t) { var e = { tryLoc: t[0] }; 1 in t && (e.catchLoc = t[1]), 2 in t && (e.finallyLoc = t[2], e.afterLoc = t[3]), this.tryEntries.push(e); } function resetTryEntry(t) { var e = t.completion || {}; e.type = "normal", delete e.arg, t.completion = e; } function Context(t) { this.tryEntries = [{ tryLoc: "root" }], t.forEach(pushTryEntry, this), this.reset(!0); } function values(e) { if (e || "" === e) { var r = e[a]; if (r) return r.call(e); if ("function" == typeof e.next) return e; if (!isNaN(e.length)) { var o = -1, i = function next() { for (; ++o < e.length;) if (n.call(e, o)) return next.value = e[o], next.done = !1, next; return next.value = t, next.done = !0, next; }; return i.next = i; } } throw new TypeError(_typeof(e) + " is not iterable"); } return GeneratorFunction.prototype = GeneratorFunctionPrototype, o(g, "constructor", { value: GeneratorFunctionPrototype, configurable: !0 }), o(GeneratorFunctionPrototype, "constructor", { value: GeneratorFunction, configurable: !0 }), GeneratorFunction.displayName = define(GeneratorFunctionPrototype, u, "GeneratorFunction"), e.isGeneratorFunction = function (t) { var e = "function" == typeof t && t.constructor; return !!e && (e === GeneratorFunction || "GeneratorFunction" === (e.displayName || e.name)); }, e.mark = function (t) { return Object.setPrototypeOf ? Object.setPrototypeOf(t, GeneratorFunctionPrototype) : (t.__proto__ = GeneratorFunctionPrototype, define(t, u, "GeneratorFunction")), t.prototype = Object.create(g), t; }, e.awrap = function (t) { return { __await: t }; }, defineIteratorMethods(AsyncIterator.prototype), define(AsyncIterator.prototype, c, function () { return this; }), e.AsyncIterator = AsyncIterator, e.async = function (t, r, n, o, i) { void 0 === i && (i = Promise); var a = new AsyncIterator(wrap(t, r, n, o), i); return e.isGeneratorFunction(r) ? a : a.next().then(function (t) { return t.done ? t.value : a.next(); }); }, defineIteratorMethods(g), define(g, u, "Generator"), define(g, a, function () { return this; }), define(g, "toString", function () { return "[object Generator]"; }), e.keys = function (t) { var e = Object(t), r = []; for (var n in e) r.push(n); return r.reverse(), function next() { for (; r.length;) { var t = r.pop(); if (t in e) return next.value = t, next.done = !1, next; } return next.done = !0, next; }; }, e.values = values, Context.prototype = { constructor: Context, reset: function reset(e) { if (this.prev = 0, this.next = 0, this.sent = this._sent = t, this.done = !1, this.delegate = null, this.method = "next", this.arg = t, this.tryEntries.forEach(resetTryEntry), !e) for (var r in this) "t" === r.charAt(0) && n.call(this, r) && !isNaN(+r.slice(1)) && (this[r] = t); }, stop: function stop() { this.done = !0; var t = this.tryEntries[0].completion; if ("throw" === t.type) throw t.arg; return this.rval; }, dispatchException: function dispatchException(e) { if (this.done) throw e; var r = this; function handle(n, o) { return a.type = "throw", a.arg = e, r.next = n, o && (r.method = "next", r.arg = t), !!o; } for (var o = this.tryEntries.length - 1; o >= 0; --o) { var i = this.tryEntries[o], a = i.completion; if ("root" === i.tryLoc) return handle("end"); if (i.tryLoc <= this.prev) { var c = n.call(i, "catchLoc"), u = n.call(i, "finallyLoc"); if (c && u) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } else if (c) { if (this.prev < i.catchLoc) return handle(i.catchLoc, !0); } else { if (!u) throw new Error("try statement without catch or finally"); if (this.prev < i.finallyLoc) return handle(i.finallyLoc); } } } }, abrupt: function abrupt(t, e) { for (var r = this.tryEntries.length - 1; r >= 0; --r) { var o = this.tryEntries[r]; if (o.tryLoc <= this.prev && n.call(o, "finallyLoc") && this.prev < o.finallyLoc) { var i = o; break; } } i && ("break" === t || "continue" === t) && i.tryLoc <= e && e <= i.finallyLoc && (i = null); var a = i ? i.completion : {}; return a.type = t, a.arg = e, i ? (this.method = "next", this.next = i.finallyLoc, y) : this.complete(a); }, complete: function complete(t, e) { if ("throw" === t.type) throw t.arg; return "break" === t.type || "continue" === t.type ? this.next = t.arg : "return" === t.type ? (this.rval = this.arg = t.arg, this.method = "return", this.next = "end") : "normal" === t.type && e && (this.next = e), y; }, finish: function finish(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.finallyLoc === t) return this.complete(r.completion, r.afterLoc), resetTryEntry(r), y; } }, catch: function _catch(t) { for (var e = this.tryEntries.length - 1; e >= 0; --e) { var r = this.tryEntries[e]; if (r.tryLoc === t) { var n = r.completion; if ("throw" === n.type) { var o = n.arg; resetTryEntry(r); } return o; } } throw new Error("illegal catch attempt"); }, delegateYield: function delegateYield(e, r, n) { return this.delegate = { iterator: values(e), resultName: r, nextLoc: n }, "next" === this.method && (this.arg = t), y; } }, e; }
3
+ function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { Promise.resolve(value).then(_next, _throw); } }
4
+ function _asyncToGenerator(fn) { return function () { var self = this, args = arguments; return new Promise(function (resolve, reject) { var gen = fn.apply(self, args); function _next(value) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); } function _throw(err) { asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); } _next(undefined); }); }; }
1
5
  import { startRecord, stopRecord } from "./rrweb";
2
- import { initConfigManager, getConfig } from "./config";
3
- import { startUploadLoop, resetUploadLoop, cancelUploadLoop } from "./uploader";
6
+ import { initConfigManager, getConfig, stopConfigUpdate } from "./config";
7
+ import { startUploadLoop, resetUploadLoop, cancelUploadLoop, flushOrphanSessions, setCancelCallback } from "./uploader";
8
+ import { setWorkerCancelCallback } from "./upload-worker-manager";
4
9
  import { initRouterMonitor, stopRouterMonitor } from "./router-monitor";
5
- import { initErrorHandler, cleanupErrorHandler } from "./error";
6
- import { setSdkLogEndpoint, restoreXhr } from "./net";
10
+ import { initErrorHandler, cleanupErrorHandler, setErrorTrigger } from "./error";
11
+ import { setSdkLogEndpoint, restoreXhr, setNetErrorTrigger, normalizeUrl } from "./net";
7
12
  import { storage } from "./storage-manager";
8
- import { getDeviceId } from "./utils";
13
+ import { getStorageKey, getSessionId, unregisterSession, cleanupStaleSessions } from "./utils";
14
+ import { ErrorTrigger } from "./error-trigger";
15
+ import logger from "./logger";
9
16
 
10
17
  // 全局取消状态管理
11
18
  var isCancelled = false;
12
19
 
20
+ // 错误采集模式下的实例引用
21
+ var errorTriggerInstance = null;
22
+
13
23
  /**
14
24
  * 执行取消操作的核心逻辑
15
25
  * @param options 取消选项
@@ -19,7 +29,7 @@ export function cancelRlog() {
19
29
  var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
20
30
  var context = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 'SDK instance';
21
31
  if (isCancelled) {
22
- console.warn('RLog SDK has already been cancelled');
32
+ logger.warn('SDK has already been cancelled');
23
33
  return;
24
34
  }
25
35
  isCancelled = true;
@@ -38,21 +48,40 @@ export function cancelRlog() {
38
48
  // 4. 清理路由监控
39
49
  stopRouterMonitor();
40
50
 
41
- // 5. 清理错误监听
51
+ // 5. 停止配置定时更新
52
+ stopConfigUpdate();
53
+
54
+ // 6. 清理错误监听
42
55
  cleanupErrorHandler();
43
56
 
44
- // 6. 可选:清除已存储的数据
57
+ // 7. 销毁错误采集模式相关实例
58
+ if (errorTriggerInstance) {
59
+ errorTriggerInstance.destroy();
60
+ errorTriggerInstance = null;
61
+ }
62
+ // 清理各模块的错误触发器引用
63
+ setErrorTrigger(null);
64
+ setNetErrorTrigger(null);
65
+
66
+ // 清理取消回调
67
+ setCancelCallback(null);
68
+ setWorkerCancelCallback(null);
69
+
70
+ // 8. 可选:清除已存储的数据
45
71
  if (options.clearData) {
46
- var deviceId = getDeviceId();
47
- if (deviceId) {
48
- storage.clear(deviceId).catch(function (error) {
49
- console.error('Error clearing storage:', error);
72
+ var storageKey = getStorageKey();
73
+ if (storageKey) {
74
+ storage.clear(storageKey).catch(function (error) {
75
+ logger.error('Error clearing storage', error);
50
76
  });
51
77
  }
52
78
  }
53
- console.log("RLog SDK cancelled successfully via ".concat(context));
79
+
80
+ // 9. 从 session 注册表中移除当前 session
81
+ unregisterSession(getSessionId());
82
+ logger.log("SDK cancelled successfully via ".concat(context));
54
83
  } catch (error) {
55
- console.error("Error cancelling RLog SDK via ".concat(context, ":"), error);
84
+ logger.error("Error cancelling SDK via ".concat(context), error);
56
85
  }
57
86
  }
58
87
 
@@ -63,13 +92,6 @@ export function resetCancelState() {
63
92
  isCancelled = false;
64
93
  }
65
94
 
66
- /**
67
- * 获取当前取消状态
68
- */
69
- export function getCancelState() {
70
- return isCancelled;
71
- }
72
-
73
95
  /**
74
96
  * 初始化 RLog SDK
75
97
  * @param serv 服务器地址
@@ -83,34 +105,113 @@ export function initRLog(serv, appId, cdnConfigUrl) {
83
105
  // 重置上传循环状态
84
106
  resetUploadLoop();
85
107
 
86
- // 设置SDK日志上报接口地址,并自动加入黑名单避免循环上报
87
- if (serv) {
88
- setSdkLogEndpoint(serv);
89
- }
90
-
91
- // 初始化配置管理器
92
- initConfigManager(cdnConfigUrl).then(function () {
93
- // 获取配置
94
- var config = getConfig();
95
-
96
- // 检查采集总开关
97
- if (!config.enable) {
98
- console.log('RLog is disabled by config');
99
- return;
108
+ // 清理过期的 session 数据(异步,不阻塞初始化)
109
+ setTimeout(function () {
110
+ try {
111
+ cleanupStaleSessions();
112
+ } catch (error) {
113
+ logger.warn('Failed to cleanup stale sessions:', error);
100
114
  }
115
+ }, 0);
101
116
 
102
- // 启动录制
103
- startRecord();
104
-
105
- // 启动数据上传
106
- startUploadLoop(serv, appId);
107
-
108
- // 初始化路由监控
109
- initRouterMonitor(config.routerMonitor);
117
+ // 设置SDK日志上报接口地址,并自动加入黑名单避免循环上报
118
+ var normalizedServUrl = normalizeUrl(serv);
119
+ setSdkLogEndpoint(normalizedServUrl);
110
120
 
111
- // 初始化错误处理
112
- initErrorHandler();
113
- }).catch(function (error) {
114
- console.error('Failed to initialize RLog:', error);
121
+ // 初始化配置管理器
122
+ initConfigManager(cdnConfigUrl).then( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee() {
123
+ var _config$error;
124
+ var config, isErrorMode, _config$errorCapture, _config$errorCapture2, cancelCallback, enableError;
125
+ return _regeneratorRuntime().wrap(function _callee$(_context) {
126
+ while (1) switch (_context.prev = _context.next) {
127
+ case 0:
128
+ // 获取配置
129
+ config = getConfig(); // 检查采集总开关
130
+ if (config.enable) {
131
+ _context.next = 3;
132
+ break;
133
+ }
134
+ return _context.abrupt("return");
135
+ case 3:
136
+ isErrorMode = config.captureMode === 'error';
137
+ if (isErrorMode) {
138
+ // ===== 错误采集模式初始化 =====
139
+ // 创建 ErrorTrigger 实例(只负责状态切换)
140
+ errorTriggerInstance = new ErrorTrigger({
141
+ beforeDuration: (_config$errorCapture = config.errorCapture) === null || _config$errorCapture === void 0 ? void 0 : _config$errorCapture.beforeDuration,
142
+ afterDuration: (_config$errorCapture2 = config.errorCapture) === null || _config$errorCapture2 === void 0 ? void 0 : _config$errorCapture2.afterDuration
143
+ });
144
+
145
+ // 将 errorTrigger 注入到 error 和 net 模块
146
+ setErrorTrigger(errorTriggerInstance);
147
+ setNetErrorTrigger(errorTriggerInstance);
148
+ }
149
+
150
+ // 启动录制(事件将写入 Storage)
151
+ try {
152
+ startRecord();
153
+ } catch (error) {
154
+ logger.error('Failed to start recording:', error);
155
+ }
156
+
157
+ // 在启动上传循环前,先将孤儿 session 的残留数据塞入当前 storage 队列头部
158
+ // 确保上传循环启动时这些数据已经就位,会被优先消费上传
159
+ _context.prev = 6;
160
+ _context.next = 9;
161
+ return flushOrphanSessions();
162
+ case 9:
163
+ _context.next = 14;
164
+ break;
165
+ case 11:
166
+ _context.prev = 11;
167
+ _context.t0 = _context["catch"](6);
168
+ logger.warn('Failed to flush orphan sessions:', _context.t0);
169
+ case 14:
170
+ // 注入取消回调(解除 uploader/worker-manager → init 的循环依赖)
171
+ cancelCallback = function cancelCallback() {
172
+ try {
173
+ cancelRlog({}, 'upload failure');
174
+ } catch (error) {
175
+ logger.error('Failed to cancel SDK via upload failure callback:', error);
176
+ }
177
+ };
178
+ setCancelCallback(cancelCallback);
179
+ setWorkerCancelCallback(cancelCallback);
180
+
181
+ // 启动统一上传循环
182
+ // 错误模式下:idle 时跳过上传,uploading 时上传,状态由 ErrorTrigger 控制
183
+ // 全量模式下:持续轮询上传
184
+ try {
185
+ startUploadLoop(normalizedServUrl, appId);
186
+ } catch (error) {
187
+ logger.error('Failed to start upload loop:', error);
188
+ }
189
+
190
+ // 初始化路由监控
191
+ try {
192
+ initRouterMonitor(config.routerMonitor);
193
+ } catch (error) {
194
+ logger.warn('Failed to initialize router monitor:', error);
195
+ }
196
+
197
+ // 判断是否启用错误监听上报:
198
+ // 1. 错误采集模式下强制启用(错误捕获模式必须依赖错误监听初始化)
199
+ // 2. 非错误模式下,根据用户 error 配置决定,默认不启用
200
+ enableError = isErrorMode || ((_config$error = config.error) !== null && _config$error !== void 0 ? _config$error : false);
201
+ if (enableError) {
202
+ try {
203
+ initErrorHandler();
204
+ } catch (error) {
205
+ logger.warn('Failed to initialize error handler:', error);
206
+ }
207
+ }
208
+ logger.log('Initialized successfully');
209
+ case 22:
210
+ case "end":
211
+ return _context.stop();
212
+ }
213
+ }, _callee, null, [[6, 11]]);
214
+ }))).catch(function (error) {
215
+ logger.error('Failed to initialize SDK', error);
115
216
  });
116
217
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Rlog SDK 日志工具
3
+ * 统一管理所有日志输出,添加统一前缀 [Rlog]
4
+ */
5
+ /**
6
+ * 日志工具对象
7
+ */
8
+ declare const logger: {
9
+ /**
10
+ * 普通日志
11
+ */
12
+ log(...args: any[]): void;
13
+ /**
14
+ * 信息日志
15
+ */
16
+ info(...args: any[]): void;
17
+ /**
18
+ * 警告日志
19
+ */
20
+ warn(...args: any[]): void;
21
+ /**
22
+ * 错误日志
23
+ */
24
+ error(...args: any[]): void;
25
+ };
26
+ export default logger;
27
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/lib/logger.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA+BH;;GAEG;AACH,QAAA,MAAM,MAAM;IACV;;OAEG;iBACU,GAAG,EAAE,GAAG,IAAI;IAIzB;;OAEG;kBACW,GAAG,EAAE,GAAG,IAAI;IAI1B;;OAEG;kBACW,GAAG,EAAE,GAAG,IAAI;IAI1B;;OAEG;mBACY,GAAG,EAAE,GAAG,IAAI;CAG5B,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Rlog SDK 日志工具
3
+ * 统一管理所有日志输出,添加统一前缀 [Rlog]
4
+ */
5
+
6
+ import { LOG_PREFIX } from "./constants";
7
+
8
+ /**
9
+ * 日志级别
10
+ */
11
+
12
+ /**
13
+ * 统一的日志输出函数
14
+ * @param level 日志级别
15
+ * @param args 日志参数
16
+ */
17
+ function _log(level) {
18
+ var _console, _console2, _console3, _console4;
19
+ for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
20
+ args[_key - 1] = arguments[_key];
21
+ }
22
+ switch (level) {
23
+ case 'log':
24
+ (_console = console).log.apply(_console, [LOG_PREFIX].concat(args));
25
+ break;
26
+ case 'info':
27
+ (_console2 = console).info.apply(_console2, [LOG_PREFIX].concat(args));
28
+ break;
29
+ case 'warn':
30
+ (_console3 = console).warn.apply(_console3, [LOG_PREFIX].concat(args));
31
+ break;
32
+ case 'error':
33
+ (_console4 = console).error.apply(_console4, [LOG_PREFIX].concat(args));
34
+ break;
35
+ }
36
+ }
37
+
38
+ /**
39
+ * 日志工具对象
40
+ */
41
+ var logger = {
42
+ /**
43
+ * 普通日志
44
+ */
45
+ log: function log() {
46
+ for (var _len2 = arguments.length, args = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
47
+ args[_key2] = arguments[_key2];
48
+ }
49
+ _log.apply(void 0, ['log'].concat(args));
50
+ },
51
+ /**
52
+ * 信息日志
53
+ */
54
+ info: function info() {
55
+ for (var _len3 = arguments.length, args = new Array(_len3), _key3 = 0; _key3 < _len3; _key3++) {
56
+ args[_key3] = arguments[_key3];
57
+ }
58
+ _log.apply(void 0, ['info'].concat(args));
59
+ },
60
+ /**
61
+ * 警告日志
62
+ */
63
+ warn: function warn() {
64
+ for (var _len4 = arguments.length, args = new Array(_len4), _key4 = 0; _key4 < _len4; _key4++) {
65
+ args[_key4] = arguments[_key4];
66
+ }
67
+ _log.apply(void 0, ['warn'].concat(args));
68
+ },
69
+ /**
70
+ * 错误日志
71
+ */
72
+ error: function error() {
73
+ for (var _len5 = arguments.length, args = new Array(_len5), _key5 = 0; _key5 < _len5; _key5++) {
74
+ args[_key5] = arguments[_key5];
75
+ }
76
+ _log.apply(void 0, ['error'].concat(args));
77
+ }
78
+ };
79
+ export default logger;
@@ -1,4 +1,10 @@
1
1
  import { record } from 'rrweb';
2
+ import { ErrorTrigger } from './error-trigger';
3
+ /**
4
+ * 设置网络模块的错误触发器实例
5
+ */
6
+ export declare function setNetErrorTrigger(trigger: ErrorTrigger | null): void;
7
+ export declare function normalizeUrl(url: string): string;
2
8
  export declare function shouldRecordUrl(url: string): boolean;
3
9
  export declare function watchXhr(r: typeof record): void;
4
10
  export declare function restoreXhr(): void;
@@ -29,4 +35,9 @@ export declare function getSdkLogEndpoint(): string | null;
29
35
  * @param headers 需要添加的自定义请求头对象
30
36
  */
31
37
  export declare function setCustomHeaders(headers: Record<string, string>): void;
38
+ /**
39
+ * 获取当前设置的自定义请求头
40
+ * @returns 当前自定义请求头的副本
41
+ */
42
+ export declare function getCustomHeaders(): Record<string, string>;
32
43
  //# sourceMappingURL=net.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"net.d.ts","sourceRoot":"","sources":["../../../src/lib/net.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AA2I/B,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAgBpD;AAUD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,MAAM,QA+KxC;AAGD,wBAAgB,UAAU,IAAI,IAAI,CAYjC;AAGD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAQrD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAOrD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAsBxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAEjD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAEtE"}
1
+ {"version":3,"file":"net.d.ts","sourceRoot":"","sources":["../../../src/lib/net.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAc/C;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI,GAAG,IAAI,CAErE;AAmBD,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAmBhD;AAwED,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAgBpD;AAiCD,wBAAgB,QAAQ,CAAC,CAAC,EAAE,OAAO,MAAM,QAkQxC;AAGD,wBAAgB,UAAU,IAAI,IAAI,CAgBjC;AAGD,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAQrD;AAED,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,IAAI,CAOrD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,EAAE,CAE3C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAoBxD;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,GAAG,IAAI,CAEjD;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,IAAI,CAEtE;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAEzD"}