@arms/rum-reactnative 0.1.3-beta.5 → 0.1.4-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/android/src/main/java/com/rumsdkreactnative/RumSdkReactnativeModule.kt +31 -0
- package/docs/ReactNative SDK/351/205/215/347/275/256/345/217/202/350/200/203.md" +25 -0
- package/docs/SDK /347/211/210/346/234/254/350/257/264/346/230/216.md" +14 -0
- package/ios/RumAppStateRecorder.h +69 -0
- package/ios/RumAppStateRecorder.mm +547 -0
- package/ios/RumCrashReporter.h +32 -0
- package/ios/RumCrashReporter.mm +97 -11
- package/ios/RumSdkReactnative.mm +81 -1
- package/lib/commonjs/NativeRumSdkReactnative.js +1 -54
- package/lib/commonjs/collector/action/index.js +1 -108
- package/lib/commonjs/collector/exception/crash.js +1 -148
- package/lib/commonjs/collector/exception/index.js +1 -238
- package/lib/commonjs/collector/exception/oom.js +1 -0
- package/lib/commonjs/collector/index.js +1 -42
- package/lib/commonjs/collector/resource/api.js +1 -292
- package/lib/commonjs/collector/view/perf.js +1 -79
- package/lib/commonjs/collector/view/pv.js +1 -88
- package/lib/commonjs/expoConfigPlugin.js +1 -37
- package/lib/commonjs/index.js +1 -29
- package/lib/commonjs/plugin.js +1 -47
- package/lib/commonjs/processor/default-processor.js +1 -27
- package/lib/commonjs/processor/session-processor.js +1 -47
- package/lib/commonjs/reporter/index.js +1 -148
- package/lib/commonjs/reporter/monitor-reporter.js +1 -43
- package/lib/commonjs/shell.js +1 -91
- package/lib/commonjs/types/client.js +1 -6
- package/lib/commonjs/types/crash.js +1 -37
- package/lib/commonjs/types/index.js +1 -2
- package/lib/commonjs/types/oom.js +1 -0
- package/lib/commonjs/utils/action.js +1 -305
- package/lib/commonjs/utils/api.js +1 -84
- package/lib/commonjs/utils/base.js +1 -95
- package/lib/commonjs/utils/crash.js +1 -149
- package/lib/commonjs/utils/platform.js +1 -162
- package/lib/commonjs/utils/session.js +1 -158
- package/lib/commonjs/utils/url.js +1 -59
- package/lib/commonjs/utils/view.js +1 -93
- package/lib/module/NativeRumSdkReactnative.js +1 -51
- package/lib/module/collector/action/index.js +1 -103
- package/lib/module/collector/exception/crash.js +1 -143
- package/lib/module/collector/exception/index.js +1 -233
- package/lib/module/collector/exception/oom.js +1 -0
- package/lib/module/collector/index.js +1 -8
- package/lib/module/collector/resource/api.js +1 -287
- package/lib/module/collector/view/perf.js +1 -79
- package/lib/module/collector/view/pv.js +1 -83
- package/lib/module/expoConfigPlugin.js +1 -33
- package/lib/module/index.js +1 -7
- package/lib/module/plugin.js +1 -42
- package/lib/module/processor/default-processor.js +1 -22
- package/lib/module/processor/session-processor.js +1 -42
- package/lib/module/reporter/index.js +1 -144
- package/lib/module/reporter/monitor-reporter.js +1 -38
- package/lib/module/shell.js +1 -84
- package/lib/module/types/client.js +1 -4
- package/lib/module/types/crash.js +1 -33
- package/lib/module/types/index.js +1 -2
- package/lib/module/types/oom.js +1 -0
- package/lib/module/utils/action.js +1 -299
- package/lib/module/utils/api.js +1 -76
- package/lib/module/utils/base.js +1 -90
- package/lib/module/utils/crash.js +1 -144
- package/lib/module/utils/platform.js +1 -150
- package/lib/module/utils/session.js +1 -154
- package/lib/module/utils/url.js +1 -54
- package/lib/module/utils/view.js +1 -88
- package/lib/typescript/commonjs/src/NativeRumSdkReactnative.d.ts +10 -0
- package/lib/typescript/commonjs/src/collector/exception/oom.d.ts +34 -0
- package/lib/typescript/commonjs/src/collector/index.d.ts +1 -0
- package/lib/typescript/commonjs/src/shell.d.ts +1 -1
- package/lib/typescript/commonjs/src/types/client.d.ts +27 -0
- package/lib/typescript/commonjs/src/types/oom.d.ts +58 -0
- package/lib/typescript/commonjs/src/utils/crash.d.ts +13 -0
- package/lib/typescript/module/src/NativeRumSdkReactnative.d.ts +10 -0
- package/lib/typescript/module/src/collector/exception/oom.d.ts +34 -0
- package/lib/typescript/module/src/collector/index.d.ts +1 -0
- package/lib/typescript/module/src/shell.d.ts +1 -1
- package/lib/typescript/module/src/types/client.d.ts +27 -0
- package/lib/typescript/module/src/types/oom.d.ts +58 -0
- package/lib/typescript/module/src/utils/crash.d.ts +13 -0
- package/package.json +1 -2
- package/src/NativeRumSdkReactnative.ts +18 -0
package/lib/module/utils/api.js
CHANGED
|
@@ -1,76 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { isFunction, isNumber, isObject, isString, ResourceStatus } from '@arms/rum-core';
|
|
4
|
-
export const ApiType = {
|
|
5
|
-
FETCH: 'fetch',
|
|
6
|
-
XHR: 'xmlhttprequest'
|
|
7
|
-
// NativeXHR: 'fetch',
|
|
8
|
-
};
|
|
9
|
-
export function reviseApiAttr(attrs) {
|
|
10
|
-
if (!attrs || !isObject(attrs)) return;
|
|
11
|
-
const obj = {};
|
|
12
|
-
if (isString(attrs.name)) {
|
|
13
|
-
obj.name = attrs.name.substring(0, 1e3);
|
|
14
|
-
}
|
|
15
|
-
if (isString(attrs.message)) {
|
|
16
|
-
obj.message = attrs.message.substring(0, 1e3);
|
|
17
|
-
}
|
|
18
|
-
// 对齐 Browser 端:保留三态 (-1/0/1),避免 Unknown(-1) 被误转为 Success(1)
|
|
19
|
-
if (isNumber(attrs.success) && attrs.success >= -1 && attrs.success <= 1) {
|
|
20
|
-
obj.success = attrs.success;
|
|
21
|
-
}
|
|
22
|
-
if (isNumber(attrs.duration) && attrs.duration >= 0) {
|
|
23
|
-
obj.duration = attrs.duration;
|
|
24
|
-
}
|
|
25
|
-
if (isString(attrs.status_code)) {
|
|
26
|
-
obj.status_code = attrs.status_code.substring(0, 100);
|
|
27
|
-
}
|
|
28
|
-
if (isNumber(attrs.status_code)) {
|
|
29
|
-
obj.status_code = attrs.status_code;
|
|
30
|
-
}
|
|
31
|
-
if (isString(attrs.snapshots)) {
|
|
32
|
-
obj.snapshots = attrs.snapshots.substring(0, 5e3);
|
|
33
|
-
}
|
|
34
|
-
return obj;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 根据指定 URL 获取视图的名称,默认为其 path 部分
|
|
39
|
-
* @param url 需要提取路径部分的 URL
|
|
40
|
-
* @param spaMode 页面 SPA 路由模式
|
|
41
|
-
*/
|
|
42
|
-
export function getPathByURL(url) {
|
|
43
|
-
try {
|
|
44
|
-
const urlObj = new URL(url);
|
|
45
|
-
return urlObj.pathname || '/';
|
|
46
|
-
} catch (error) {
|
|
47
|
-
return url;
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
export function getResourceName(url, parseFunction) {
|
|
51
|
-
let name;
|
|
52
|
-
if (parseFunction && isFunction(parseFunction)) {
|
|
53
|
-
name = parseFunction(url);
|
|
54
|
-
} else {
|
|
55
|
-
name = getPathByURL(url);
|
|
56
|
-
}
|
|
57
|
-
return name;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/**
|
|
61
|
-
* 判断成功还是失败
|
|
62
|
-
* @param status_code
|
|
63
|
-
* @returns
|
|
64
|
-
*/
|
|
65
|
-
export function getResourceSuccessByCode(status_code) {
|
|
66
|
-
let status;
|
|
67
|
-
const THRESHOLD = [200, 300];
|
|
68
|
-
if (status_code) {
|
|
69
|
-
const code = Number(status_code);
|
|
70
|
-
status = code >= THRESHOLD[0] && code < THRESHOLD[1] ? ResourceStatus.Success : ResourceStatus.Failed;
|
|
71
|
-
} else {
|
|
72
|
-
status = ResourceStatus.Unknown;
|
|
73
|
-
}
|
|
74
|
-
return status;
|
|
75
|
-
}
|
|
76
|
-
//# sourceMappingURL=api.js.map
|
|
1
|
+
"use strict";import{isFunction,isNumber,isObject,isString,ResourceStatus}from"@arms/rum-core";export const ApiType={FETCH:"fetch",XHR:"xmlhttprequest"};export function reviseApiAttr(s){if(!s||!isObject(s))return;const t={};return isString(s.name)&&(t.name=s.name.substring(0,1e3)),isString(s.message)&&(t.message=s.message.substring(0,1e3)),isNumber(s.success)&&s.success>=-1&&s.success<=1&&(t.success=s.success),isNumber(s.duration)&&s.duration>=0&&(t.duration=s.duration),isString(s.status_code)&&(t.status_code=s.status_code.substring(0,100)),isNumber(s.status_code)&&(t.status_code=s.status_code),isString(s.snapshots)&&(t.snapshots=s.snapshots.substring(0,5e3)),t}export function getPathByURL(s){try{return new URL(s).pathname||"/"}catch(t){return s}}export function getResourceName(s,t){let e;return e=t&&isFunction(t)?t(s):getPathByURL(s),e}export function getResourceSuccessByCode(s){let t;const e=[200,300];if(s){const r=Number(s);t=r>=e[0]&&r<e[1]?ResourceStatus.Success:ResourceStatus.Failed}else t=ResourceStatus.Unknown;return t}
|
package/lib/module/utils/base.js
CHANGED
|
@@ -1,90 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
// /**
|
|
4
|
-
// * 保留指定位数的小数
|
|
5
|
-
// * @param num 原数据
|
|
6
|
-
// * @param decimal 小数位数
|
|
7
|
-
// * @returns
|
|
8
|
-
// */
|
|
9
|
-
// export function formatNumber(num: number, decimal: number = 3): number {
|
|
10
|
-
// if (!num) {
|
|
11
|
-
// return num;
|
|
12
|
-
// }
|
|
13
|
-
// let str = num.toString();
|
|
14
|
-
// const index = str.indexOf('.');
|
|
15
|
-
// if (index !== -1) {
|
|
16
|
-
// str = str.substring(0, decimal + index + 1);
|
|
17
|
-
// } else {
|
|
18
|
-
// str = str.substring(0);
|
|
19
|
-
// }
|
|
20
|
-
// return parseFloat(str);
|
|
21
|
-
// }
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* 获取获取当前时间 fix Data.now() 存在的缺陷
|
|
25
|
-
* duration方法用于计算时间跨度,由于Date.now存在bug,可能为负数,尽可能使用performance.now计算
|
|
26
|
-
* @returns
|
|
27
|
-
*/
|
|
28
|
-
export function getCurrentTime() {
|
|
29
|
-
return new Date().getTime();
|
|
30
|
-
}
|
|
31
|
-
export function getStringSize(str, encode = 'utf8') {
|
|
32
|
-
if (typeof str !== 'string') {
|
|
33
|
-
throw new TypeError('Input must be a string');
|
|
34
|
-
}
|
|
35
|
-
const encoding = encode.toLowerCase();
|
|
36
|
-
if (encoding === 'utf16') {
|
|
37
|
-
let bytes = 0;
|
|
38
|
-
for (let i = 0; i < str.length; i++) {
|
|
39
|
-
const code = str.charCodeAt(i);
|
|
40
|
-
|
|
41
|
-
// 检查代理对(有效的高位代理后跟低位代理)
|
|
42
|
-
if (code >= 0xd800 && code <= 0xdbff) {
|
|
43
|
-
if (i + 1 < str.length) {
|
|
44
|
-
const nextCode = str.charCodeAt(i + 1);
|
|
45
|
-
if (nextCode >= 0xdc00 && nextCode <= 0xdfff) {
|
|
46
|
-
bytes += 4; // 有效的代理对(4字节)
|
|
47
|
-
i++; // 跳过低位代理
|
|
48
|
-
continue;
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
bytes += 2; // 基本字符或无效代理(2字节)
|
|
53
|
-
}
|
|
54
|
-
return bytes;
|
|
55
|
-
}
|
|
56
|
-
if (encoding === 'utf8') {
|
|
57
|
-
let totalBytes = 0;
|
|
58
|
-
for (let i = 0; i < str.length; i++) {
|
|
59
|
-
let code = str.charCodeAt(i);
|
|
60
|
-
|
|
61
|
-
// 处理代理对(UTF-16辅助平面)
|
|
62
|
-
if (code >= 0xd800 && code <= 0xdbff) {
|
|
63
|
-
if (i + 1 < str.length) {
|
|
64
|
-
const nextCode = str.charCodeAt(i + 1);
|
|
65
|
-
if (nextCode >= 0xdc00 && nextCode <= 0xdfff) {
|
|
66
|
-
// 计算实际的Unicode码点
|
|
67
|
-
code = (code - 0xd800) * 0x400 + (nextCode - 0xdc00) + 0x10000;
|
|
68
|
-
i++; // 跳过低位代理
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// 根据码点值计算UTF-8字节长度
|
|
74
|
-
if (code <= 0x7f) {
|
|
75
|
-
totalBytes += 1; // ASCII字符(1字节)
|
|
76
|
-
} else if (code <= 0x7ff) {
|
|
77
|
-
totalBytes += 2; // 拉丁文补充等(2字节)
|
|
78
|
-
} else if (code <= 0xffff) {
|
|
79
|
-
totalBytes += 3; // 基本多语言平面(3字节)
|
|
80
|
-
} else if (code <= 0x10ffff) {
|
|
81
|
-
totalBytes += 4; // 辅助平面(4字节)
|
|
82
|
-
} else {
|
|
83
|
-
totalBytes += 3; // 无效码点,使用替换字符长度
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
return totalBytes;
|
|
87
|
-
}
|
|
88
|
-
throw new Error('Unsupported encoding. Use "utf8" or "utf16".');
|
|
89
|
-
}
|
|
90
|
-
//# sourceMappingURL=base.js.map
|
|
1
|
+
"use strict";export function getCurrentTime(){return(new Date).getTime()}export function getStringSize(t,e="utf8"){if("string"!=typeof t)throw new TypeError("Input must be a string");const r=e.toLowerCase();if("utf16"===r){let e=0;for(let r=0;r<t.length;r++){const n=t.charCodeAt(r);if(n>=55296&&n<=56319&&r+1<t.length){const n=t.charCodeAt(r+1);if(n>=56320&&n<=57343){e+=4,r++;continue}}e+=2}return e}if("utf8"===r){let e=0;for(let r=0;r<t.length;r++){let n=t.charCodeAt(r);if(n>=55296&&n<=56319&&r+1<t.length){const e=t.charCodeAt(r+1);e>=56320&&e<=57343&&(n=1024*(n-55296)+(e-56320)+65536,r++)}e+=n<=127?1:n<=2047?2:n<=65535?3:n<=1114111?4:3}return e}throw new Error('Unsupported encoding. Use "utf8" or "utf16".')}
|
|
@@ -1,144 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { RumEventType, logger } from '@arms/rum-core';
|
|
4
|
-
/**
|
|
5
|
-
* 将原生崩溃数据转换为 RumEvent 异常事件,对齐存储模型 Exception 表的
|
|
6
|
-
* Attributes(session/view/exception 基础信息)+ Metadata(堆栈、快照等)字段。
|
|
7
|
-
*/
|
|
8
|
-
export function convertCrashToRumEvent(crashData) {
|
|
9
|
-
const exceptionName = crashData.signal?.name || crashData.exception?.class_name || 'NativeCrash';
|
|
10
|
-
const exceptionMessage = buildMessage(crashData);
|
|
11
|
-
// NDK 崩溃的 frames 在顶层,Java 崩溃的 frames 在 crashed_thread 内
|
|
12
|
-
const frames = crashData.frames || crashData.crashed_thread?.frames || [];
|
|
13
|
-
const stack = formatStack(frames);
|
|
14
|
-
// 兼容旧版字符串格式:frames[0] 可能是字符串
|
|
15
|
-
const firstFrame = frames[0];
|
|
16
|
-
const file = typeof firstFrame === 'object' ? firstFrame?.library || '' : '';
|
|
17
|
-
|
|
18
|
-
// 从第一帧提取 line,原生崩溃无列号概念,column 固定为 0
|
|
19
|
-
let line = 0;
|
|
20
|
-
let column = 0;
|
|
21
|
-
if (frames.length > 0) {
|
|
22
|
-
const topFrame = frames[0];
|
|
23
|
-
if (topFrame && typeof topFrame === 'object' && typeof topFrame.line === 'number') {
|
|
24
|
-
line = topFrame.line;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
const view = {
|
|
28
|
-
id: crashData.context?.view_id || '',
|
|
29
|
-
name: crashData.context?.view_name || ''
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// 防御性转换:NDK 旧版本使用秒级 timestamp,新版本已改为毫秒
|
|
33
|
-
// 如果 timestamp 小于 1e12(约 2001 年的毫秒值),说明是秒级,需乘以 1000
|
|
34
|
-
let timestamp = crashData.timestamp || Date.now();
|
|
35
|
-
if (timestamp < 1e12) {
|
|
36
|
-
timestamp = timestamp * 1000;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// binary_images uuid 字段兼容:统一为 uuid,保留原 build_id/debug_id
|
|
40
|
-
const rawImages = crashData.binary_images || [];
|
|
41
|
-
const normalizedImages = rawImages.map(img => {
|
|
42
|
-
if (!img.uuid && (img.build_id || img.debug_id)) {
|
|
43
|
-
return {
|
|
44
|
-
...img,
|
|
45
|
-
uuid: img.build_id || img.debug_id
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
return img;
|
|
49
|
-
});
|
|
50
|
-
return {
|
|
51
|
-
event_type: RumEventType.EXCEPTION,
|
|
52
|
-
timestamp,
|
|
53
|
-
// 设置崩溃时的原始 session_id,新版 rum-core dispatchEvents 会按
|
|
54
|
-
// session_id 分组上报,不再丢弃非当前 session 的事件
|
|
55
|
-
session_id: crashData.context?.session_id,
|
|
56
|
-
view,
|
|
57
|
-
times: 1,
|
|
58
|
-
// === Attributes ===
|
|
59
|
-
source: 'event',
|
|
60
|
-
type: 'crash',
|
|
61
|
-
name: exceptionName,
|
|
62
|
-
message: exceptionMessage,
|
|
63
|
-
file,
|
|
64
|
-
line,
|
|
65
|
-
column,
|
|
66
|
-
// === Metadata ===
|
|
67
|
-
stack,
|
|
68
|
-
caused_by: crashData.exception?.message || (crashData.signal ? `${crashData.signal.name || ''} at ${crashData.signal.fault_address || ''}` : ''),
|
|
69
|
-
binary_images: JSON.stringify(normalizedImages),
|
|
70
|
-
snapshots: JSON.stringify({
|
|
71
|
-
device: crashData.device || {},
|
|
72
|
-
registers: crashData.registers || {},
|
|
73
|
-
app: crashData.app || {},
|
|
74
|
-
crash_context: crashData.context || {},
|
|
75
|
-
// NDK 特有字段透传:arch 决定后端符号化的寄存器解释方式和地址宽度;
|
|
76
|
-
// pid 用于关联系统日志;signal.number 为 NDK 写入的原始信号编号
|
|
77
|
-
arch: crashData.arch || '',
|
|
78
|
-
pid: crashData.pid,
|
|
79
|
-
signal_number: crashData.signal?.number,
|
|
80
|
-
// 崩溃线程 ID:NDK 崩溃使用顶层 tid,Java 崩溃使用 crashed_thread.id
|
|
81
|
-
thread_id: String(crashData.crashed_thread?.id ?? crashData.tid ?? ''),
|
|
82
|
-
// 崩溃机制信息放入 snapshots 容器
|
|
83
|
-
...(crashData.mechanism ? {
|
|
84
|
-
mechanism: crashData.mechanism
|
|
85
|
-
} : {})
|
|
86
|
-
})
|
|
87
|
-
};
|
|
88
|
-
}
|
|
89
|
-
function buildMessage(crashData) {
|
|
90
|
-
if (crashData.exception?.message) {
|
|
91
|
-
return crashData.exception.message;
|
|
92
|
-
}
|
|
93
|
-
const sig = crashData.signal;
|
|
94
|
-
if (sig) {
|
|
95
|
-
const addr = sig.fault_address || '';
|
|
96
|
-
return `${sig.name || ''} (${sig.code ?? ''})${addr ? ' at ' + addr : ''}`.trim();
|
|
97
|
-
}
|
|
98
|
-
return 'Native crash';
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* 格式化堆栈为可读字符串。
|
|
103
|
-
* 兼容两种 frames 格式:
|
|
104
|
-
* - 新版(对象数组):[{address, library, symbol, offset}, ...]
|
|
105
|
-
* - 旧版(字符串数组):["0x1234", ...](旧版 NDK 崩溃文件)
|
|
106
|
-
*/
|
|
107
|
-
function formatStack(frames) {
|
|
108
|
-
if (!frames || frames.length === 0) return '';
|
|
109
|
-
return frames.map((frame, index) => {
|
|
110
|
-
// 兼容旧版 NDK 的纯字符串格式
|
|
111
|
-
if (typeof frame === 'string') {
|
|
112
|
-
return `#${index} <unknown> ${frame} ()`;
|
|
113
|
-
}
|
|
114
|
-
// 截断标记帧:双侧截断时插入的中间标记
|
|
115
|
-
if (frame.truncated) {
|
|
116
|
-
const count = frame.omitted_count ?? -1;
|
|
117
|
-
if (count < 0) {
|
|
118
|
-
return `#${index} ... frames omitted (unknown count) ...`;
|
|
119
|
-
}
|
|
120
|
-
return `#${index} ... ${count} frames omitted ...`;
|
|
121
|
-
}
|
|
122
|
-
const library = frame.library || '<unknown>';
|
|
123
|
-
const symbol = frame.symbol || '';
|
|
124
|
-
const address = frame.address || '';
|
|
125
|
-
const offset = frame.offset || '';
|
|
126
|
-
if (symbol) {
|
|
127
|
-
return `#${index} ${library} ${symbol} + ${offset}`;
|
|
128
|
-
}
|
|
129
|
-
return `#${index} ${library} ${address} (${offset})`;
|
|
130
|
-
}).join('\n');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/**
|
|
134
|
-
* 安全调用原生桥方法,异常时静默降级。
|
|
135
|
-
*/
|
|
136
|
-
export async function safeNativeCall(fn, label) {
|
|
137
|
-
try {
|
|
138
|
-
return await fn();
|
|
139
|
-
} catch (e) {
|
|
140
|
-
logger.warn('native-bridge', `${label || 'native call'} failed`, e);
|
|
141
|
-
return undefined;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
//# sourceMappingURL=crash.js.map
|
|
1
|
+
"use strict";import{RumEventType,logger}from"@arms/rum-core";export function convertCrashToRumEvent(e){const t=e.signal?.name||e.exception?.class_name||"NativeCrash",n=buildMessage(e),a=e.frames||e.crashed_thread?.frames||[],i=formatStack(a),s=a[0],r="object"==typeof s&&s?.library||"";let o=0;if(a.length>0){const e=a[0];e&&"object"==typeof e&&"number"==typeof e.line&&(o=e.line)}const c={id:e.context?.view_id||"",name:e.context?.view_name||""};let m=e.timestamp||Date.now();m<1e12&&(m*=1e3);const d=(e.binary_images||[]).map(e=>e.uuid||!e.build_id&&!e.debug_id?e:{...e,uuid:e.build_id||e.debug_id});return{event_type:RumEventType.EXCEPTION,timestamp:m,session_id:e.context?.session_id,view:c,times:1,source:"event",type:"crash",name:t,message:n,file:r,line:o,column:0,stack:i,caused_by:e.exception?.message||(e.signal?`${e.signal.name||""} at ${e.signal.fault_address||""}`:""),binary_images:JSON.stringify(d),snapshots:JSON.stringify({device:e.device||{},registers:e.registers||{},app:e.app||{},crash_context:e.context||{},arch:e.arch||"",pid:e.pid,signal_number:e.signal?.number,thread_id:String(e.crashed_thread?.id??e.tid??""),...e.mechanism?{mechanism:e.mechanism}:{}})}}const OOM_DEFAULT_MESSAGE="App was killed while active with no crash report (suspected watchdog termination)",OOM_DEFAULT_MECHANISM={type:"watchdog_termination",handled:!1};export function convertOomToRumEvent(e){let t=e.timestamp||Date.now();return t<1e12&&(t*=1e3),{event_type:RumEventType.EXCEPTION,timestamp:t,session_id:e.context?.session_id,view:{id:e.context?.view_id||"",name:e.context?.view_name||""},times:1,source:"event",type:"crash",subtype:"oom",name:e.name||"WatchdogTermination",message:e.message||OOM_DEFAULT_MESSAGE,stack:"",snapshots:JSON.stringify({mechanism:e.mechanism||OOM_DEFAULT_MECHANISM,platform:e.platform||"ios",app_state:e.app_state||{},crash_context:e.context||{},estimated:!0})}}function buildMessage(e){if(e.exception?.message)return e.exception.message;const t=e.signal;if(t){const e=t.fault_address||"";return`${t.name||""} (${t.code??""})${e?" at "+e:""}`.trim()}return"Native crash"}function formatStack(e){return e&&0!==e.length?e.map((e,t)=>{if("string"==typeof e)return`#${t} <unknown> ${e} ()`;if(e.truncated){const n=e.omitted_count??-1;return n<0?`#${t} ... frames omitted (unknown count) ...`:`#${t} ... ${n} frames omitted ...`}const n=e.library||"<unknown>",a=e.symbol||"",i=e.address||"",s=e.offset||"";return a?`#${t} ${n} ${a} + ${s}`:`#${t} ${n} ${i} (${s})`}).join("\n"):""}export async function safeNativeCall(e,t){try{return await e()}catch(e){return void logger.warn("native-bridge",`${t||"native call"} failed`,e)}}
|
|
@@ -1,150 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { AppType } from '@arms/rum-core';
|
|
4
|
-
import { Dimensions, Platform } from 'react-native';
|
|
5
|
-
import NativeRumSdkReactnative from "../NativeRumSdkReactnative.js";
|
|
6
|
-
const _pkg = {"version":"0.1.3-beta.5"};
|
|
7
|
-
export const VERSION = _pkg.version;
|
|
8
|
-
|
|
9
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
10
|
-
|
|
11
|
-
export const appName = 'react-native';
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* 从 react-native/package.json 获取 RN 运行时版本号,
|
|
15
|
-
* 用于 os.container_version。
|
|
16
|
-
*/
|
|
17
|
-
function getReactNativeVersion() {
|
|
18
|
-
try {
|
|
19
|
-
const pkg = require('react-native/package.json');
|
|
20
|
-
return pkg.version ?? '';
|
|
21
|
-
} catch {
|
|
22
|
-
const info = Platform.constants?.reactNativeVersion;
|
|
23
|
-
if (info) {
|
|
24
|
-
return `${info.major}.${info.minor}.${info.patch}`;
|
|
25
|
-
}
|
|
26
|
-
return '';
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
// region Storage
|
|
31
|
-
|
|
32
|
-
export function getStorage(key) {
|
|
33
|
-
return NativeRumSdkReactnative.getItem(key);
|
|
34
|
-
}
|
|
35
|
-
export function setStorage(key, data) {
|
|
36
|
-
return NativeRumSdkReactnative.setItem(key, data);
|
|
37
|
-
}
|
|
38
|
-
export function removeStorage(key) {
|
|
39
|
-
return NativeRumSdkReactnative.removeItem(key);
|
|
40
|
-
}
|
|
41
|
-
export function clearStorage() {
|
|
42
|
-
return NativeRumSdkReactnative.clear();
|
|
43
|
-
}
|
|
44
|
-
export function getAllStorageKeys() {
|
|
45
|
-
return NativeRumSdkReactnative.getAllKeys();
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
// endregion
|
|
49
|
-
|
|
50
|
-
// region Device Info
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* 调用原生桥采集设备信息。
|
|
54
|
-
* 失败时静默降级到 JS Platform API 填充基础字段。
|
|
55
|
-
*/
|
|
56
|
-
async function fetchDeviceInfo() {
|
|
57
|
-
try {
|
|
58
|
-
return await NativeRumSdkReactnative.getDeviceInfo();
|
|
59
|
-
} catch (err) {
|
|
60
|
-
console.warn('[rum] getDeviceInfo failed, falling back to JS defaults', err);
|
|
61
|
-
return {
|
|
62
|
-
os_type: Platform.OS === 'ios' ? 'iOS' : 'Android',
|
|
63
|
-
os_version: String(Platform.Version ?? '')
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* 模块级缓存,首次调用 fixAttrs 时懒初始化,避免模块加载时原生桥尚未就绪。
|
|
70
|
-
* null 表示尚未触发采集。
|
|
71
|
-
*/
|
|
72
|
-
let _cachedDeviceInfo = null;
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* 获取设备信息(懒初始化,仅触发一次原生桥调用)。
|
|
76
|
-
*/
|
|
77
|
-
function getDeviceInfo() {
|
|
78
|
-
if (!_cachedDeviceInfo) {
|
|
79
|
-
_cachedDeviceInfo = fetchDeviceInfo();
|
|
80
|
-
}
|
|
81
|
-
return _cachedDeviceInfo;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// endregion
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* 将设备 / 系统 / 网络等公共属性注入 bundle。
|
|
88
|
-
* 在 Reporter.request 中被调用;首次调用时懒触发设备信息采集。
|
|
89
|
-
*/
|
|
90
|
-
export const fixAttrs = async function (bundle) {
|
|
91
|
-
if (!bundle) return;
|
|
92
|
-
const native = await getDeviceInfo();
|
|
93
|
-
|
|
94
|
-
// device.*
|
|
95
|
-
const device = {
|
|
96
|
-
id: native.device_id,
|
|
97
|
-
type: native.device_type,
|
|
98
|
-
brand: native.device_brand,
|
|
99
|
-
model: native.device_model,
|
|
100
|
-
name: native.device_name
|
|
101
|
-
};
|
|
102
|
-
|
|
103
|
-
// os.*
|
|
104
|
-
const rnVersion = getReactNativeVersion();
|
|
105
|
-
const os = {
|
|
106
|
-
type: native.os_type ?? (Platform.OS === 'ios' ? 'iOS' : 'Android'),
|
|
107
|
-
version: native.os_version ?? String(Platform.Version ?? ''),
|
|
108
|
-
container: appName,
|
|
109
|
-
container_version: rnVersion || undefined
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
// viewport:优先使用原生采集的物理像素,兜底 JS Dimensions(逻辑像素)
|
|
113
|
-
let viewport;
|
|
114
|
-
if (native.viewport_width && native.viewport_height) {
|
|
115
|
-
viewport = {
|
|
116
|
-
width: native.viewport_width,
|
|
117
|
-
height: native.viewport_height
|
|
118
|
-
};
|
|
119
|
-
} else {
|
|
120
|
-
try {
|
|
121
|
-
const screen = Dimensions.get('screen');
|
|
122
|
-
viewport = {
|
|
123
|
-
width: Math.round(screen.width),
|
|
124
|
-
height: Math.round(screen.height)
|
|
125
|
-
};
|
|
126
|
-
} catch {
|
|
127
|
-
// 忽略
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
bundle.app.type = AppType.reactnative;
|
|
131
|
-
bundle.app.package = bundle.app.package ?? native.app_package;
|
|
132
|
-
bundle.app.version = bundle.app.version ?? native.app_version;
|
|
133
|
-
bundle._v = VERSION;
|
|
134
|
-
bundle.device = {
|
|
135
|
-
...device,
|
|
136
|
-
...bundle.device
|
|
137
|
-
};
|
|
138
|
-
bundle.os = {
|
|
139
|
-
...os,
|
|
140
|
-
...bundle.os
|
|
141
|
-
};
|
|
142
|
-
if (viewport) {
|
|
143
|
-
bundle.viewport = {
|
|
144
|
-
...bundle.viewport,
|
|
145
|
-
...viewport
|
|
146
|
-
};
|
|
147
|
-
}
|
|
148
|
-
return bundle;
|
|
149
|
-
};
|
|
150
|
-
//# sourceMappingURL=platform.js.map
|
|
1
|
+
"use strict";import{AppType}from"@arms/rum-core";import{Dimensions,Platform}from"react-native";import NativeRumSdkReactnative from"../NativeRumSdkReactnative.js";const _pkg={version:"0.1.4-beta.1"};export const VERSION=_pkg.version;export const appName="react-native";function getReactNativeVersion(){try{return require("react-native/package.json").version??""}catch{const e=Platform.constants?.reactNativeVersion;return e?`${e.major}.${e.minor}.${e.patch}`:""}}export function getStorage(e){return NativeRumSdkReactnative.getItem(e)}export function setStorage(e,t){return NativeRumSdkReactnative.setItem(e,t)}export function removeStorage(e){return NativeRumSdkReactnative.removeItem(e)}export function clearStorage(){return NativeRumSdkReactnative.clear()}export function getAllStorageKeys(){return NativeRumSdkReactnative.getAllKeys()}async function fetchDeviceInfo(){try{return await NativeRumSdkReactnative.getDeviceInfo()}catch(e){return console.warn("[rum] getDeviceInfo failed, falling back to JS defaults",e),{os_type:"ios"===Platform.OS?"iOS":"Android",os_version:String(Platform.Version??"")}}}let _cachedDeviceInfo=null;function getDeviceInfo(){return _cachedDeviceInfo||(_cachedDeviceInfo=fetchDeviceInfo()),_cachedDeviceInfo}export const fixAttrs=async function(e){if(!e)return;const t=await getDeviceInfo(),i={id:t.device_id,type:t.device_type,brand:t.device_brand,model:t.device_model,name:t.device_name},r=getReactNativeVersion(),n={type:t.os_type??("ios"===Platform.OS?"iOS":"Android"),version:t.os_version??String(Platform.Version??""),container:appName,container_version:r||void 0};let a;if(t.viewport_width&&t.viewport_height)a={width:t.viewport_width,height:t.viewport_height};else try{const e=Dimensions.get("screen");a={width:Math.round(e.width),height:Math.round(e.height)}}catch{}return e.app.type=AppType.reactnative,e.app.package=e.app.package??t.app_package,e.app.version=e.app.version??t.app_version,e._v=VERSION,e.device={...i,...e.device},e.os={...n,...e.os},a&&(e.viewport={...e.viewport,...a}),e};
|
|
@@ -1,154 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
import { generateEventId, generateGUID, generateSpanId, isNumber, ONE_DAY, ONE_HOUR, ONE_MINUTE, performDraw } from '@arms/rum-core';
|
|
4
|
-
import { getCurrentTime } from "./base.js";
|
|
5
|
-
import { getCurView } from "./view.js";
|
|
6
|
-
import { getStorage, setStorage } from "./platform.js";
|
|
7
|
-
|
|
8
|
-
// 存储userID的键名
|
|
9
|
-
const USER_ID = '_rum_uid';
|
|
10
|
-
// 旧版键名(用于迁移)
|
|
11
|
-
const LEGACY_USER_ID = '_arms_uid';
|
|
12
|
-
// 存储session
|
|
13
|
-
// const RUM_SESSION = '_rum_session';
|
|
14
|
-
|
|
15
|
-
export class RumSession {
|
|
16
|
-
/** 平台类型标识 */
|
|
17
|
-
appType = 'reactnative';
|
|
18
|
-
|
|
19
|
-
/** SDK 版本号(延迟导入避免循环依赖) */
|
|
20
|
-
get sdkVersion() {
|
|
21
|
-
return require('./platform').VERSION;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
// @ts-ignore
|
|
25
|
-
|
|
26
|
-
// private sessionId = '';
|
|
27
|
-
|
|
28
|
-
session = '';
|
|
29
|
-
userId = '';
|
|
30
|
-
constructor() {
|
|
31
|
-
this.initUser();
|
|
32
|
-
}
|
|
33
|
-
init(ctx) {
|
|
34
|
-
this.ctx = ctx;
|
|
35
|
-
this.sessionConfig = this.fixSessionConfig(ctx.config?.sessionConfig);
|
|
36
|
-
}
|
|
37
|
-
getSessionId() {
|
|
38
|
-
return this.getSessionInfo().sessionId;
|
|
39
|
-
}
|
|
40
|
-
getSampled() {
|
|
41
|
-
return this.getSessionInfo().sampled;
|
|
42
|
-
}
|
|
43
|
-
checkSession(info) {
|
|
44
|
-
const {
|
|
45
|
-
overtime = 0,
|
|
46
|
-
maxDuration = 0
|
|
47
|
-
} = this.sessionConfig;
|
|
48
|
-
const now = getCurrentTime();
|
|
49
|
-
return !(info.startTime + maxDuration < now || info.lastTime + overtime < now);
|
|
50
|
-
}
|
|
51
|
-
updateSession() {
|
|
52
|
-
const info = this.getSessionInfo();
|
|
53
|
-
if (info.isNew) {
|
|
54
|
-
return;
|
|
55
|
-
}
|
|
56
|
-
const startTime = info.startTime;
|
|
57
|
-
const lastTime = getCurrentTime();
|
|
58
|
-
const sampled = info.sampled ? 1 : 0;
|
|
59
|
-
this.session = `${info.sessionId}-${sampled}-${startTime}-${lastTime}`;
|
|
60
|
-
// setStorage(RUM_SESSION, `${info.sessionId}-${sampled}-${startTime}-${lastTime}`)
|
|
61
|
-
}
|
|
62
|
-
getSessionInfo() {
|
|
63
|
-
const [sid, sampled, startTime, lastTime] = this.session.split('-');
|
|
64
|
-
let info = {
|
|
65
|
-
sessionId: sid,
|
|
66
|
-
sampled: sampled !== '0',
|
|
67
|
-
startTime: parseInt(startTime || '', 10) || 0,
|
|
68
|
-
lastTime: parseInt(lastTime || '', 10) || 0
|
|
69
|
-
};
|
|
70
|
-
if (!this.checkSession(info)) {
|
|
71
|
-
info = this.resetSession();
|
|
72
|
-
}
|
|
73
|
-
return info;
|
|
74
|
-
}
|
|
75
|
-
getEventId() {
|
|
76
|
-
const sid = this.getSessionId();
|
|
77
|
-
return generateEventId(sid);
|
|
78
|
-
}
|
|
79
|
-
getViewId() {
|
|
80
|
-
return this.getUUID();
|
|
81
|
-
}
|
|
82
|
-
async initUser() {
|
|
83
|
-
this.userId = await getStorage(USER_ID);
|
|
84
|
-
// 迁移旧版键名 _arms_uid → _rum_uid
|
|
85
|
-
if (!this.userId) {
|
|
86
|
-
const legacyId = await getStorage(LEGACY_USER_ID);
|
|
87
|
-
if (legacyId) {
|
|
88
|
-
this.userId = legacyId;
|
|
89
|
-
await setStorage(USER_ID, this.userId);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
if (!this.userId) {
|
|
94
|
-
this.userId = `uid_${generateSpanId(16, 36)}`;
|
|
95
|
-
await setStorage(USER_ID, this.userId);
|
|
96
|
-
}
|
|
97
|
-
}
|
|
98
|
-
getUserId() {
|
|
99
|
-
return this.userId;
|
|
100
|
-
}
|
|
101
|
-
resetSession() {
|
|
102
|
-
const {
|
|
103
|
-
sampleRate = 1
|
|
104
|
-
} = this.sessionConfig;
|
|
105
|
-
const sid = this.getUUID();
|
|
106
|
-
const now = getCurrentTime();
|
|
107
|
-
const sampled = performDraw(sampleRate * 100);
|
|
108
|
-
this.session = `${sid}-${sampled ? 1 : 0}-${now}-${now}`;
|
|
109
|
-
// setStorage(RUM_SESSION, this.session);
|
|
110
|
-
return {
|
|
111
|
-
sessionId: sid,
|
|
112
|
-
sampled: sampled,
|
|
113
|
-
startTime: now,
|
|
114
|
-
lastTime: now,
|
|
115
|
-
isNew: true
|
|
116
|
-
};
|
|
117
|
-
}
|
|
118
|
-
getUUID() {
|
|
119
|
-
return generateGUID().replace(/-/g, '');
|
|
120
|
-
}
|
|
121
|
-
fixSessionConfig(sessionConfig = {}) {
|
|
122
|
-
let {
|
|
123
|
-
sampleRate,
|
|
124
|
-
maxDuration,
|
|
125
|
-
overtime
|
|
126
|
-
} = sessionConfig;
|
|
127
|
-
if (!isNumber(sampleRate) || sampleRate < 0 || sampleRate > 1) {
|
|
128
|
-
sampleRate = 1;
|
|
129
|
-
}
|
|
130
|
-
if (!isNumber(maxDuration) || maxDuration < 4 * ONE_HOUR || maxDuration > ONE_DAY) {
|
|
131
|
-
maxDuration = ONE_DAY;
|
|
132
|
-
}
|
|
133
|
-
if (!isNumber(overtime) || overtime > ONE_HOUR || overtime < 10 * ONE_MINUTE) {
|
|
134
|
-
overtime = 30 * ONE_MINUTE;
|
|
135
|
-
}
|
|
136
|
-
return {
|
|
137
|
-
sampleRate,
|
|
138
|
-
maxDuration,
|
|
139
|
-
overtime
|
|
140
|
-
};
|
|
141
|
-
}
|
|
142
|
-
getBaseEvent() {
|
|
143
|
-
const session_id = this.getSessionId();
|
|
144
|
-
const event_id = this.getEventId();
|
|
145
|
-
return {
|
|
146
|
-
timestamp: getCurrentTime(),
|
|
147
|
-
session_id,
|
|
148
|
-
event_id,
|
|
149
|
-
view: this.ctx ? getCurView(this.ctx) : undefined,
|
|
150
|
-
times: 1
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
//# sourceMappingURL=session.js.map
|
|
1
|
+
"use strict";import{generateEventId,generateGUID,generateSpanId,isNumber,ONE_DAY,ONE_HOUR,ONE_MINUTE,performDraw}from"@arms/rum-core";import{getCurrentTime}from"./base.js";import{getCurView}from"./view.js";import{getStorage,setStorage}from"./platform.js";const USER_ID="_rum_uid",LEGACY_USER_ID="_arms_uid";export class RumSession{appType="reactnative";get sdkVersion(){return require("./platform").VERSION}session="";userId="";constructor(){this.initUser()}init(e){this.ctx=e,this.sessionConfig=this.fixSessionConfig(e.config?.sessionConfig)}getSessionId(){return this.getSessionInfo().sessionId}getSampled(){return this.getSessionInfo().sampled}checkSession(e){const{overtime:s=0,maxDuration:t=0}=this.sessionConfig,i=getCurrentTime();return!(e.startTime+t<i||e.lastTime+s<i)}updateSession(){const e=this.getSessionInfo();if(e.isNew)return;const s=e.startTime,t=getCurrentTime(),i=e.sampled?1:0;this.session=`${e.sessionId}-${i}-${s}-${t}`}getSessionInfo(){const[e,s,t,i]=this.session.split("-");let r={sessionId:e,sampled:"0"!==s,startTime:parseInt(t||"",10)||0,lastTime:parseInt(i||"",10)||0};return this.checkSession(r)||(r=this.resetSession()),r}getEventId(){const e=this.getSessionId();return generateEventId(e)}getViewId(){return this.getUUID()}async initUser(){if(this.userId=await getStorage(USER_ID),!this.userId){const e=await getStorage("_arms_uid");if(e)return this.userId=e,void await setStorage(USER_ID,this.userId)}this.userId||(this.userId=`uid_${generateSpanId(16,36)}`,await setStorage(USER_ID,this.userId))}getUserId(){return this.userId}resetSession(){const{sampleRate:e=1}=this.sessionConfig,s=this.getUUID(),t=getCurrentTime(),i=performDraw(100*e);return this.session=`${s}-${i?1:0}-${t}-${t}`,{sessionId:s,sampled:i,startTime:t,lastTime:t,isNew:!0}}getUUID(){return generateGUID().replace(/-/g,"")}fixSessionConfig(e={}){let{sampleRate:s,maxDuration:t,overtime:i}=e;return(!isNumber(s)||s<0||s>1)&&(s=1),(!isNumber(t)||t<4*ONE_HOUR||t>ONE_DAY)&&(t=ONE_DAY),(!isNumber(i)||i>ONE_HOUR||i<10*ONE_MINUTE)&&(i=30*ONE_MINUTE),{sampleRate:s,maxDuration:t,overtime:i}}getBaseEvent(){const e=this.getSessionId(),s=this.getEventId();return{timestamp:getCurrentTime(),session_id:e,event_id:s,view:this.ctx?getCurView(this.ctx):void 0,times:1}}}
|
package/lib/module/utils/url.js
CHANGED
|
@@ -1,54 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* 根据指定 URL 获取视图的名称,默认为其path部分
|
|
5
|
-
* @param url 需要提取路径部分的 URL
|
|
6
|
-
* @param isHash 是否为 hash 模式路由的 URL
|
|
7
|
-
*/
|
|
8
|
-
export function getPathByURL(url, isHash = false) {
|
|
9
|
-
try {
|
|
10
|
-
const urlObj = getURL(url);
|
|
11
|
-
if (!urlObj) return;
|
|
12
|
-
if (isHash) {
|
|
13
|
-
return urlObj.hash;
|
|
14
|
-
} else {
|
|
15
|
-
return urlObj.pathname;
|
|
16
|
-
}
|
|
17
|
-
} catch (error) {
|
|
18
|
-
return '';
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
// /**
|
|
23
|
-
// * 检查是否为上报域名
|
|
24
|
-
// * @param ctx
|
|
25
|
-
// * @param url 需要提取路径部分的 URL
|
|
26
|
-
// */
|
|
27
|
-
// export function isEndpoint(ctx: IContext, url: string): boolean {
|
|
28
|
-
// const { endpoint } = ctx.getConfig();
|
|
29
|
-
// try {
|
|
30
|
-
// return getURL(url).hostname === getURL(endpoint).hostname
|
|
31
|
-
// } catch (e) {
|
|
32
|
-
// return false;
|
|
33
|
-
// }
|
|
34
|
-
// }
|
|
35
|
-
|
|
36
|
-
const REGEX = /^(?:([^:\/?#]+):\/\/)?((?:([^\/?#@]*)@)?([^\/?#:]*)(?:\:(\d*))?)?([^?#]*)(?:\?([^#]*))?(?:#((?:.|\n)*))?/i;
|
|
37
|
-
export function getURL(url) {
|
|
38
|
-
const parts = decodeURIComponent(url).match(REGEX);
|
|
39
|
-
if (!parts) return null;
|
|
40
|
-
const auth = (parts[3] || '').split(':');
|
|
41
|
-
const host = auth.length ? (parts[2] || '').replace(/(.*\@)/, '') : parts[2];
|
|
42
|
-
return {
|
|
43
|
-
uri: parts[0],
|
|
44
|
-
protocol: parts[1],
|
|
45
|
-
host: host,
|
|
46
|
-
hostname: parts[4],
|
|
47
|
-
port: parts[5],
|
|
48
|
-
pathname: parts[6],
|
|
49
|
-
search: parts[7],
|
|
50
|
-
// query: mapSearchParams(parts[7]),
|
|
51
|
-
hash: parts[8]
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
//# sourceMappingURL=url.js.map
|
|
1
|
+
"use strict";export function getPathByURL(t,e=!1){try{const n=getURL(t);if(!n)return;return e?n.hash:n.pathname}catch(t){return""}}const REGEX=/^(?:([^:\/?#]+):\/\/)?((?:([^\/?#@]*)@)?([^\/?#:]*)(?:\:(\d*))?)?([^?#]*)(?:\?([^#]*))?(?:#((?:.|\n)*))?/i;export function getURL(t){const e=decodeURIComponent(t).match(REGEX);if(!e)return null;const n=(e[3]||"").split(":").length?(e[2]||"").replace(/(.*\@)/,""):e[2];return{uri:e[0],protocol:e[1],host:n,hostname:e[4],port:e[5],pathname:e[6],search:e[7],hash:e[8]}}
|