@arms/rum-core 0.1.7 → 0.1.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,45 +1,94 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
3
+ function _interopRequireDefault(e){return e&&e.__esModule?e:{"default":e}}
4
4
  exports.__esModule = true;
5
5
  exports["default"] = void 0;
6
- var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
7
6
  var _rumEvent = require("../types/rum-event");
8
7
  var _client = _interopRequireDefault(require("../model/client"));
9
8
  var _is = require("../utils/is");
9
+ var _Shell;
10
10
  var Shell = exports["default"] = /*#__PURE__*/function () {
11
11
  function Shell(config) {
12
- // private callbacks: Function[] = [];
13
- // private initialized = false;
12
+ var _this = this;
14
13
  this.client = void 0;
14
+ this.initialized = false;
15
+ this.extensionCollectors = [];
15
16
  this.client = new _client["default"]();
17
+
18
+ // 拦截 client.init,自动在其后挂载扩展采集器
19
+ var originalInit = this.client.init.bind(this.client);
20
+ this.client.init = function () {
21
+ originalInit.apply(void 0, arguments);
22
+ _this.initClient();
23
+ };
16
24
  if (config && this.init) {
17
25
  this.init(config);
18
- // const p = this.init(config) as Promise<Shell>;
19
- // if(isFunction(p?.then)){
20
- // p.then(this.shellReady);
21
- // } else {
22
- // this.shellReady()
23
- // }
24
26
  }
25
27
  }
26
28
 
27
- // private shellReady = () => {
28
- // this.initialized = true;
29
- // this.callbacks.forEach(cb => cb());
30
- // }
31
- //
32
- // onReady(callback: Function) {
33
- // if (this.initialized) {
34
- // callback();
35
- // }
36
- // this.callbacks.push(callback);
37
- // }
38
-
39
29
  /**
40
- * 初始化
30
+ * 注册扩展采集器(实例方法,支持 per-instance 隔离)
31
+ * 支持在 init 之前或之后调用;若已初始化则立即 setup
41
32
  */
42
33
  var _proto = Shell.prototype;
34
+ _proto.useCollectors = function useCollectors() {
35
+ var _this$extensionCollec,
36
+ _this2 = this;
37
+ for (var _len = arguments.length, collectors = new Array(_len), _key = 0; _key < _len; _key++) {
38
+ collectors[_key] = arguments[_key];
39
+ }
40
+ (_this$extensionCollec = this.extensionCollectors).push.apply(_this$extensionCollec, collectors);
41
+ if (this.initialized && this.client) {
42
+ var ctx = this.client.getContext();
43
+ if (ctx) {
44
+ collectors.forEach(function (collector) {
45
+ collector.setup(ctx, _this2.client.sendEvent);
46
+ });
47
+ }
48
+ }
49
+ }
50
+
51
+ /**
52
+ * 返回当前实例装载的全部采集器(client 内置通道 + 实例扩展通道)
53
+ */;
54
+ _proto.getCollectors = function getCollectors() {
55
+ var clientCollectors = this.client && this.client.getCollectors() || [];
56
+ // 用 concat 替代数组 spread,避免依赖 babel 降级注入 helper(项目去 @babel/runtime 规范)
57
+ return clientCollectors.concat(this.extensionCollectors);
58
+ }
59
+
60
+ /**
61
+ * 向所有已初始化的实例广播事件
62
+ */;
63
+ Shell.broadcastEvent = function broadcastEvent(event, options) {
64
+ Shell.instances.forEach(function (instance) {
65
+ if (instance.initialized && instance.client) {
66
+ instance.client.sendEvent(event, options);
67
+ }
68
+ });
69
+ }
70
+
71
+ /**
72
+ * 统一初始化 Client,并在 init 完成后自动挂载扩展采集器。
73
+ * 由 client.init 拦截器自动调用,子包无需手动调用。
74
+ */;
75
+ _proto.initClient = function initClient() {
76
+ var _this3 = this;
77
+ if (this.extensionCollectors.length > 0) {
78
+ var ctx = this.client.getContext();
79
+ if (ctx) {
80
+ this.extensionCollectors.forEach(function (collector) {
81
+ collector.setup(ctx, _this3.client.sendEvent);
82
+ });
83
+ }
84
+ }
85
+ this.initialized = true;
86
+ Shell.instances.push(this);
87
+ }
88
+
89
+ /**
90
+ * 初始化
91
+ */;
43
92
  _proto.sendEvent = function sendEvent(payload, options) {
44
93
  if (this.client) {
45
94
  this.client.sendEvent(payload, options);
@@ -65,7 +114,7 @@ var Shell = exports["default"] = /*#__PURE__*/function () {
65
114
  if (!payload.name || !payload.type) {
66
115
  return;
67
116
  }
68
- var data = (0, _extends2["default"])({}, payload, {
117
+ var data = Object.assign({}, payload, {
69
118
  event_type: _rumEvent.RumEventType.CUSTOM
70
119
  });
71
120
  this.sendEvent(data);
@@ -91,7 +140,7 @@ var Shell = exports["default"] = /*#__PURE__*/function () {
91
140
  });
92
141
  if (n === 0) return;
93
142
  }
94
- var data = (0, _extends2["default"])({}, payload, {
143
+ var data = Object.assign({}, payload, {
95
144
  event_type: _rumEvent.RumEventType.VIEW
96
145
  });
97
146
  this.sendEvent(data);
@@ -107,7 +156,7 @@ var Shell = exports["default"] = /*#__PURE__*/function () {
107
156
  var name = payload.name,
108
157
  message = payload.message,
109
158
  stack = payload.stack;
110
- var data = (0, _extends2["default"])({
159
+ var data = Object.assign({
111
160
  times: 1,
112
161
  name: name,
113
162
  message: message,
@@ -127,7 +176,7 @@ var Shell = exports["default"] = /*#__PURE__*/function () {
127
176
  if (!payload.name || !payload.type || !(0, _is.isNumber)(payload.duration)) {
128
177
  return;
129
178
  }
130
- var data = (0, _extends2["default"])({
179
+ var data = Object.assign({
131
180
  times: 1
132
181
  }, payload, {
133
182
  event_type: _rumEvent.RumEventType.RESOURCE
@@ -135,4 +184,6 @@ var Shell = exports["default"] = /*#__PURE__*/function () {
135
184
  this.sendEvent(data);
136
185
  };
137
186
  return Shell;
138
- }();
187
+ }();
188
+ _Shell = Shell;
189
+ Shell.instances = [];
@@ -1,5 +1,10 @@
1
1
  import { MonitorLogEvent, MonitorLogLevel } from './types';
2
- type LogArgs = [module: string, message: string, error?: unknown, context?: Record<string, unknown>];
2
+ type LogArgs = [
3
+ module: string,
4
+ message: string,
5
+ error?: unknown,
6
+ context?: Record<string, unknown>
7
+ ];
3
8
  export interface ILogger {
4
9
  debug(...args: LogArgs): void;
5
10
  info(...args: LogArgs): void;
@@ -62,7 +62,7 @@ var Logger = /*#__PURE__*/function () {
62
62
  }
63
63
 
64
64
  // 仅上报配置中指定的级别
65
- if (!this.reportLevels.includes(level)) return;
65
+ if (this.reportLevels.indexOf(level) === -1) return;
66
66
  var stack;
67
67
  if (error instanceof Error) {
68
68
  stack = error.stack;
@@ -1,10 +1,8 @@
1
1
  "use strict";
2
2
 
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
3
  exports.__esModule = true;
5
4
  exports.Telemetry = void 0;
6
5
  exports.convertBundlesToLogGroup = convertBundlesToLogGroup;
7
- var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
8
6
  var _logger = require("./logger");
9
7
  var _url = require("../utils/url");
10
8
  var _protobuf = require("../utils/protobuf");
@@ -80,12 +78,12 @@ var Telemetry = exports.Telemetry = /*#__PURE__*/function () {
80
78
  var _this$context$getSess, _this$context, _this$context$getView, _this$context2;
81
79
  if (!this.enabled || !event) return;
82
80
  if (event.content && event.content.length > LOG_CONTENT_MAX_SIZE) {
83
- event = (0, _extends2["default"])({}, event, {
81
+ event = Object.assign({}, event, {
84
82
  content: event.content.slice(0, LOG_CONTENT_MAX_SIZE)
85
83
  });
86
84
  }
87
85
  if (event.stack && event.stack.length > LOG_CONTENT_MAX_SIZE) {
88
- event = (0, _extends2["default"])({}, event, {
86
+ event = Object.assign({}, event, {
89
87
  stack: event.stack.slice(0, LOG_CONTENT_MAX_SIZE)
90
88
  });
91
89
  }
@@ -154,7 +152,7 @@ var Telemetry = exports.Telemetry = /*#__PURE__*/function () {
154
152
  appType = _this$context3.appType,
155
153
  sdkVersion = _this$context3.sdkVersion,
156
154
  endpoint = _this$context3.endpoint;
157
- return (0, _extends2["default"])({
155
+ return Object.assign({
158
156
  'app.type': appType,
159
157
  _v: sdkVersion,
160
158
  endpoint: endpoint,
@@ -193,11 +191,11 @@ function convertBundlesToLogGroup(data) {
193
191
  var contents = [];
194
192
 
195
193
  // 遍历 bundle 顶层字段,跳过 timestamp(映射到 time),对象类型整体序列化
196
- for (var _i = 0, _Object$entries = Object.entries(bundle); _i < _Object$entries.length; _i++) {
197
- var _Object$entries$_i = _Object$entries[_i],
198
- _key = _Object$entries$_i[0],
199
- val = _Object$entries$_i[1];
194
+ var bundleKeys = Object.keys(bundle);
195
+ for (var i = 0; i < bundleKeys.length; i++) {
196
+ var _key = bundleKeys[i];
200
197
  if (_key === 'timestamp') continue;
198
+ var val = bundle[_key];
201
199
  if (val !== undefined && val !== null) {
202
200
  contents.push({
203
201
  key: _key,
@@ -1,4 +1,5 @@
1
1
  import { IConfiguration } from './client';
2
+ import { ICollector } from './collector';
2
3
  import { RumEvent, SendEventOptions } from './rum-event';
3
4
  /**
4
5
  * 每个 sdk shell 导出固定需要实现的基础 api
@@ -8,6 +9,14 @@ import { RumEvent, SendEventOptions } from './rum-event';
8
9
  * 3. 基于 Disposable 模式,对于事件的绑定、快捷键的绑定函数,返回值则是解绑函数
9
10
  */
10
11
  export interface IShell {
12
+ /**
13
+ * 注册扩展采集器(per-instance 隔离)
14
+ */
15
+ useCollectors(...collectors: ICollector[]): void;
16
+ /**
17
+ * 返回当前实例装载的全部采集器
18
+ */
19
+ getCollectors(): ICollector[];
11
20
  /**
12
21
  * 初始化
13
22
  */
package/lib/utils/base.js CHANGED
@@ -11,6 +11,7 @@ exports.interceptFunction = interceptFunction;
11
11
  exports.parseRegExpString = parseRegExpString;
12
12
  exports.restoreFunction = restoreFunction;
13
13
  var _is = require("./is");
14
+ var _logger = require("../monitor/logger");
14
15
  /**
15
16
  * 劫持函数或原型
16
17
  */
@@ -18,19 +19,74 @@ function interceptFunction(target, name, callback, isPrototype) {
18
19
  if (isPrototype === void 0) {
19
20
  isPrototype = false;
20
21
  }
21
- var registeredMethod = target[name];
22
- var proxyMethod = function proxyMethod() {
23
- var ctx = isPrototype ? this : target;
24
- for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
25
- args[_key] = arguments[_key];
22
+ try {
23
+ var registeredMethod = target[name];
24
+ var proxyMethod = function proxyMethod() {
25
+ var ctx = isPrototype ? this : target;
26
+ for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
27
+ args[_key] = arguments[_key];
28
+ }
29
+ try {
30
+ // callback 异常隔离:SDK 采集逻辑出错不能中断客户原函数执行
31
+ callback.apply(ctx, args);
32
+ } catch (e) {
33
+ _logger.logger.warn('interceptFunction', "callback error in \"" + name + "\"", e);
34
+ }
35
+ if ((0, _is.isFunction)(registeredMethod)) {
36
+ return registeredMethod.apply(ctx, args);
37
+ }
38
+ };
39
+ disguiseProxy(proxyMethod, registeredMethod);
40
+ target[name] = proxyMethod;
41
+ } catch (e) {
42
+ // 劫持安装保护:target 属性只读 accessor 或被 freeze 时(strict mode 下抛 TypeError),
43
+ // 上报后静默返回,不中断 SDK 初始化
44
+ _logger.logger.warn('interceptFunction', "install proxy failed for \"" + name + "\"", e);
45
+ }
46
+ }
47
+
48
+ /**
49
+ * 伪装代理函数,降低劫持对客户代码的感知:
50
+ * 1. toString 返回原函数源码(String()、模板字符串、console.log、日志序列化等路径可见原函数)
51
+ * 2. name/length 与原函数对齐
52
+ * 3. _rum_intercepted 不可枚举,避免污染 Object.keys / for...in
53
+ * 注意:defineProperty 在部分小程序运行时可能失败,需降级为直接挂载,不能中断劫持主流程
54
+ *
55
+ */
56
+ function disguiseProxy(proxyMethod, originalMethod) {
57
+ try {
58
+ if ((0, _is.isFunction)(originalMethod)) {
59
+ Object.defineProperty(proxyMethod, 'toString', {
60
+ value: function value() {
61
+ return originalMethod.toString();
62
+ },
63
+ writable: true,
64
+ configurable: true
65
+ });
66
+ Object.defineProperty(proxyMethod, 'name', {
67
+ value: originalMethod.name,
68
+ configurable: true
69
+ });
70
+ Object.defineProperty(proxyMethod, 'length', {
71
+ value: originalMethod.length,
72
+ configurable: true
73
+ });
26
74
  }
27
- callback.apply(ctx, args);
28
- if ((0, _is.isFunction)(registeredMethod)) {
29
- return registeredMethod.apply(ctx, args);
75
+ Object.defineProperty(proxyMethod, '_rum_intercepted', {
76
+ value: originalMethod,
77
+ enumerable: false,
78
+ writable: true,
79
+ configurable: true
80
+ });
81
+ } catch (e) {
82
+ // 降级:defineProperty 不可用时直接挂载,保证 restoreFunction 仍可用
83
+ try {
84
+ proxyMethod._rum_intercepted = originalMethod;
85
+ } catch (err) {
86
+ // 二层保护:strict mode 下对不可扩展对象直接赋值也会抛 TypeError,上报后放弃挂载
87
+ _logger.logger.warn('interceptFunction', 'disguiseProxy fallback failed', err);
30
88
  }
31
- };
32
- proxyMethod._rum_intercepted = registeredMethod;
33
- target[name] = proxyMethod;
89
+ }
34
90
  }
35
91
 
36
92
  /**
@@ -158,72 +214,6 @@ function delay(func, wait) {
158
214
  return setTimeout.apply(void 0, [func, +wait || 0].concat(args));
159
215
  }
160
216
 
161
- // // 类型匹配正则
162
- // const TYPE_REG = /^\[object ([a-z]*)\]$/;
163
- // /**
164
- // * @desc 需要严格区分object和array
165
- // * @param obj 任意对象
166
- // */
167
- // export function getType(obj: any) {
168
- // let type = Object.prototype.toString.call(obj);
169
- // type = type.toLowerCase() || '';
170
- // const arr = type.match(TYPE_REG);
171
- // return arr?.[1];
172
- // }
173
- //
174
- // /**
175
- // * @desc 将字符串转换成正则表达式
176
- // * @param str 任意字符串
177
- // * 注意,这里只支持 /xxx/ 这种格式,不支持修饰符,例如 /xxx/ig
178
- // */
179
- // export function transStrToReg(str: string) {
180
- // if (getType(str) !== 'string') return str;
181
- // if (str.length > 2 && str[0] === '/' && str[str.length - 1] === '/') {
182
- // return new RegExp(str.substr(1, str.length - 2));
183
- // }
184
- // return str;
185
- // }
186
- //
187
- // /**
188
- // *
189
- // * @param config 配置
190
- // * @param keys 需要转换的字段
191
- // */
192
- // export function toRegFormat(config: any, keys: any[]) {
193
- // if (getType(keys) === 'string') {
194
- // keys = [keys];
195
- // }
196
- // for (let i = 0, len = keys.length; i < len; i++) {
197
- // const paths = keys[i].split('.');
198
- // const lastIndex = paths.length - 1;
199
- // if (!config) break;
200
- // let tmp = config;
201
- // for (let j = 0, jlen = paths.length; j < jlen; j++) {
202
- // if (paths[j] === '[]') {
203
- // if (getType(tmp) === 'array') {
204
- // let lastPath = paths.splice(j + 1);
205
- // lastPath = lastPath.join('.');
206
- // for (let x = 0, xlen = tmp.length; x < xlen; x++) {
207
- // toRegFormat(tmp[x], lastPath);
208
- // }
209
- // }
210
- // break;
211
- // }
212
- // // 最后一层了,需要往前一层才能修改对象
213
- // if (lastIndex === j && getType(tmp[paths[j]]) === 'string') {
214
- // tmp[paths[j]] = transStrToReg(tmp[paths[j]]);
215
- // break;
216
- // }
217
- // tmp = tmp[paths[j]];
218
- // if (!tmp) break;
219
- // }
220
- // if (!tmp || getType(tmp) !== 'array') continue;
221
- // for (let j = 0, jlen = tmp.length; j < jlen; j++) {
222
- // tmp[j] = transStrToReg(tmp[j]);
223
- // }
224
- // }
225
- // }
226
-
227
217
  /**
228
218
  * 解析正则表达式字符串,支持 /pattern/flags 格式
229
219
  * @param str 正则表达式字符串,如 "/a/ig" 或 "a"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arms/rum-core",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "arms rum javascript sdk core",
5
5
  "author": "guangli.fj <guangli.fj@alibaba-inc.com>",
6
6
  "license": "ISC",
@@ -34,9 +34,6 @@
34
34
  "prepublishOnly": "npm run build",
35
35
  "test": "npm run build && jest ./__tests__"
36
36
  },
37
- "peerDependencies": {
38
- "@babel/runtime": "^7.24.5"
39
- },
40
37
  "devDependencies": {
41
38
  "typescript": "^4.9.4"
42
39
  }