@zyui/error-monitor-sdk 0.1.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.
- package/dist/client.d.ts +6 -0
- package/dist/client.js +102 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +3 -0
- package/dist/transport.d.ts +2 -0
- package/dist/transport.js +55 -0
- package/dist/types.d.ts +68 -0
- package/dist/types.js +1 -0
- package/dist/utils/reactNative.d.ts +2 -0
- package/dist/utils/reactNative.js +25 -0
- package/dist/utils/route.d.ts +8 -0
- package/dist/utils/route.js +12 -0
- package/dist/utils/web.d.ts +2 -0
- package/dist/utils/web.js +29 -0
- package/package.json +43 -0
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CaptureOptions, DeviceInfo, InitConfig, User } from "./types";
|
|
2
|
+
export declare function init(config: InitConfig): void;
|
|
3
|
+
export declare function setCustomContext(ctx: Record<string, unknown>): void;
|
|
4
|
+
export declare function setUser(user: User): void;
|
|
5
|
+
export declare function setDevice(device: DeviceInfo): void;
|
|
6
|
+
export declare function captureError(error: unknown, options?: CaptureOptions): Promise<void>;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { send } from "./transport";
|
|
2
|
+
import { getRouteInfo } from "./utils/route";
|
|
3
|
+
const state = {
|
|
4
|
+
context: {},
|
|
5
|
+
};
|
|
6
|
+
const throttleMap = new Map();
|
|
7
|
+
function genId() {
|
|
8
|
+
const buf = typeof crypto !== "undefined" && "randomUUID" in crypto
|
|
9
|
+
? crypto.randomUUID()
|
|
10
|
+
: `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
11
|
+
return buf;
|
|
12
|
+
}
|
|
13
|
+
function normalizeError(e) {
|
|
14
|
+
if (e instanceof Error) {
|
|
15
|
+
return {
|
|
16
|
+
message: e.message || String(e),
|
|
17
|
+
name: e.name,
|
|
18
|
+
type: e.name,
|
|
19
|
+
stack: e.stack,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
if (typeof e === "string") {
|
|
23
|
+
return {
|
|
24
|
+
message: e,
|
|
25
|
+
type: "String",
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return {
|
|
30
|
+
message: JSON.stringify(e),
|
|
31
|
+
type: Array.isArray(e) ? "Array" : typeof e,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return {
|
|
36
|
+
message: String(e),
|
|
37
|
+
type: typeof e,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function init(config) {
|
|
42
|
+
state.config = config;
|
|
43
|
+
}
|
|
44
|
+
export function setCustomContext(ctx) {
|
|
45
|
+
state.context = { ...state.context, ...ctx };
|
|
46
|
+
}
|
|
47
|
+
export function setUser(user) {
|
|
48
|
+
state.user = { ...state.user, ...user };
|
|
49
|
+
}
|
|
50
|
+
export function setDevice(device) {
|
|
51
|
+
state.device = { ...state.device, ...device };
|
|
52
|
+
}
|
|
53
|
+
function makeKey(details) {
|
|
54
|
+
const m = (details.message || "").toLowerCase();
|
|
55
|
+
const s = (details.stack || details.type || details.name || "").toLowerCase();
|
|
56
|
+
return `${m}|${s}`;
|
|
57
|
+
}
|
|
58
|
+
function buildPayload(details, options) {
|
|
59
|
+
const level = (options === null || options === void 0 ? void 0 : options.level) || "error";
|
|
60
|
+
const tags = options === null || options === void 0 ? void 0 : options.tags;
|
|
61
|
+
const extra = options === null || options === void 0 ? void 0 : options.extra;
|
|
62
|
+
const cfg = state.config;
|
|
63
|
+
const route = getRouteInfo();
|
|
64
|
+
const mergedContext = Object.keys(route).length
|
|
65
|
+
? { ...state.context, route }
|
|
66
|
+
: state.context;
|
|
67
|
+
return {
|
|
68
|
+
id: genId(),
|
|
69
|
+
ts: Date.now(),
|
|
70
|
+
level,
|
|
71
|
+
environment: cfg === null || cfg === void 0 ? void 0 : cfg.environment,
|
|
72
|
+
appKey: cfg === null || cfg === void 0 ? void 0 : cfg.appKey,
|
|
73
|
+
error: details,
|
|
74
|
+
user: state.user,
|
|
75
|
+
device: state.device,
|
|
76
|
+
context: mergedContext,
|
|
77
|
+
tags,
|
|
78
|
+
extra,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export async function captureError(error, options) {
|
|
82
|
+
var _a;
|
|
83
|
+
const details = normalizeError(error);
|
|
84
|
+
const cfg = state.config;
|
|
85
|
+
const throttleMs = (_a = cfg === null || cfg === void 0 ? void 0 : cfg.throttleIntervalMs) !== null && _a !== void 0 ? _a : 0;
|
|
86
|
+
if (throttleMs > 0) {
|
|
87
|
+
const key = makeKey(details);
|
|
88
|
+
const now = Date.now();
|
|
89
|
+
const last = throttleMap.get(key);
|
|
90
|
+
if (last && now - last < throttleMs)
|
|
91
|
+
return;
|
|
92
|
+
throttleMap.set(key, now);
|
|
93
|
+
}
|
|
94
|
+
const payload = buildPayload(details, options);
|
|
95
|
+
if (!cfg || !cfg.endpoint)
|
|
96
|
+
return;
|
|
97
|
+
const finalPayload = cfg.beforeSend ? cfg.beforeSend(payload) : payload;
|
|
98
|
+
if (!finalPayload)
|
|
99
|
+
return;
|
|
100
|
+
const transport = cfg.transport || send;
|
|
101
|
+
await transport(finalPayload, cfg);
|
|
102
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { init, captureError, setCustomContext, setUser, setDevice, } from "./client";
|
|
2
|
+
export { getWebInfo } from "./utils/web";
|
|
3
|
+
export { getRouteInfo } from "./utils/route";
|
|
4
|
+
export type { InitConfig, User, DeviceInfo, ErrorPayload, Level, CaptureOptions, Transport, } from "./types";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
function mergeHeaders(a, b) {
|
|
2
|
+
const r = {};
|
|
3
|
+
if (a)
|
|
4
|
+
Object.keys(a).forEach((k) => {
|
|
5
|
+
r[k] = a[k];
|
|
6
|
+
});
|
|
7
|
+
if (b)
|
|
8
|
+
Object.keys(b).forEach((k) => {
|
|
9
|
+
r[k] = b[k];
|
|
10
|
+
});
|
|
11
|
+
return r;
|
|
12
|
+
}
|
|
13
|
+
export async function send(payload, config) {
|
|
14
|
+
var _a;
|
|
15
|
+
const controller = typeof AbortController !== "undefined" ? new AbortController() : undefined;
|
|
16
|
+
const timeout = (_a = config.timeoutMs) !== null && _a !== void 0 ? _a : 8000;
|
|
17
|
+
let timer;
|
|
18
|
+
if (controller) {
|
|
19
|
+
timer = setTimeout(() => {
|
|
20
|
+
try {
|
|
21
|
+
controller.abort();
|
|
22
|
+
}
|
|
23
|
+
catch { }
|
|
24
|
+
}, timeout);
|
|
25
|
+
}
|
|
26
|
+
const headers = mergeHeaders({ "Content-Type": "application/json" }, config.headers);
|
|
27
|
+
const url = config.endpoint;
|
|
28
|
+
const body = JSON.stringify(payload);
|
|
29
|
+
try {
|
|
30
|
+
if (typeof fetch === "function") {
|
|
31
|
+
await fetch(url, {
|
|
32
|
+
method: "POST",
|
|
33
|
+
headers,
|
|
34
|
+
body,
|
|
35
|
+
signal: controller ? controller.signal : undefined,
|
|
36
|
+
});
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
if (typeof XMLHttpRequest !== "undefined") {
|
|
40
|
+
await new Promise((resolve, reject) => {
|
|
41
|
+
const xhr = new XMLHttpRequest();
|
|
42
|
+
xhr.open("POST", url, true);
|
|
43
|
+
Object.keys(headers).forEach((k) => xhr.setRequestHeader(k, headers[k]));
|
|
44
|
+
xhr.onload = () => resolve();
|
|
45
|
+
xhr.onerror = () => reject(new Error("XMLHttpRequest error"));
|
|
46
|
+
xhr.send(body);
|
|
47
|
+
});
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
if (timer)
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
}
|
|
55
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type Level = "debug" | "info" | "warn" | "error" | "fatal";
|
|
2
|
+
export type Transport = (payload: ErrorPayload, config: InitConfig) => Promise<void>;
|
|
3
|
+
export interface InitConfig {
|
|
4
|
+
endpoint: string;
|
|
5
|
+
appKey?: string;
|
|
6
|
+
environment?: string;
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
transport?: Transport;
|
|
9
|
+
beforeSend?: (payload: ErrorPayload) => ErrorPayload | null;
|
|
10
|
+
timeoutMs?: number;
|
|
11
|
+
throttleIntervalMs?: number;
|
|
12
|
+
}
|
|
13
|
+
export interface User {
|
|
14
|
+
id?: string;
|
|
15
|
+
name?: string;
|
|
16
|
+
email?: string;
|
|
17
|
+
phone?: string;
|
|
18
|
+
username?: string;
|
|
19
|
+
avatarUrl?: string;
|
|
20
|
+
[k: string]: unknown;
|
|
21
|
+
}
|
|
22
|
+
export interface DeviceInfo {
|
|
23
|
+
os?: string;
|
|
24
|
+
osVersion?: string;
|
|
25
|
+
model?: string;
|
|
26
|
+
brand?: string;
|
|
27
|
+
screen?: {
|
|
28
|
+
width?: number;
|
|
29
|
+
height?: number;
|
|
30
|
+
scale?: number;
|
|
31
|
+
dpi?: number;
|
|
32
|
+
};
|
|
33
|
+
viewport?: {
|
|
34
|
+
width?: number;
|
|
35
|
+
height?: number;
|
|
36
|
+
};
|
|
37
|
+
language?: string;
|
|
38
|
+
timezone?: string;
|
|
39
|
+
online?: boolean;
|
|
40
|
+
platform?: string;
|
|
41
|
+
userAgent?: string;
|
|
42
|
+
referrer?: string;
|
|
43
|
+
[k: string]: unknown;
|
|
44
|
+
}
|
|
45
|
+
export interface ErrorDetails {
|
|
46
|
+
message: string;
|
|
47
|
+
name?: string;
|
|
48
|
+
type?: string;
|
|
49
|
+
stack?: string;
|
|
50
|
+
}
|
|
51
|
+
export interface CaptureOptions {
|
|
52
|
+
level?: Level;
|
|
53
|
+
tags?: Record<string, string>;
|
|
54
|
+
extra?: Record<string, unknown>;
|
|
55
|
+
}
|
|
56
|
+
export interface ErrorPayload {
|
|
57
|
+
id: string;
|
|
58
|
+
ts: number;
|
|
59
|
+
level: Level;
|
|
60
|
+
environment?: string;
|
|
61
|
+
appKey?: string;
|
|
62
|
+
error: ErrorDetails;
|
|
63
|
+
user?: User;
|
|
64
|
+
device?: DeviceInfo;
|
|
65
|
+
context?: Record<string, unknown>;
|
|
66
|
+
tags?: Record<string, string>;
|
|
67
|
+
extra?: Record<string, unknown>;
|
|
68
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Dimensions, Platform, NativeModules } from "react-native";
|
|
2
|
+
function getLocale() {
|
|
3
|
+
const I18nManager = NativeModules.I18nManager;
|
|
4
|
+
const SettingsManager = NativeModules.SettingsManager;
|
|
5
|
+
const localeIOS = SettingsManager && SettingsManager.settings ? (SettingsManager.settings.AppleLocale || (SettingsManager.settings.AppleLanguages && SettingsManager.settings.AppleLanguages[0])) : undefined;
|
|
6
|
+
const localeAndroid = I18nManager && I18nManager.localeIdentifier ? I18nManager.localeIdentifier : undefined;
|
|
7
|
+
return localeIOS || localeAndroid;
|
|
8
|
+
}
|
|
9
|
+
export function getReactNativeInfo() {
|
|
10
|
+
const win = Dimensions.get("window");
|
|
11
|
+
const scale = win.scale || 1;
|
|
12
|
+
const os = Platform.OS;
|
|
13
|
+
const version = typeof Platform.Version === "string" ? Platform.Version : String(Platform.Version);
|
|
14
|
+
return {
|
|
15
|
+
os,
|
|
16
|
+
osVersion: version,
|
|
17
|
+
language: getLocale(),
|
|
18
|
+
screen: {
|
|
19
|
+
width: win.width,
|
|
20
|
+
height: win.height,
|
|
21
|
+
scale
|
|
22
|
+
},
|
|
23
|
+
platform: "ReactNative"
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export function getWebInfo() {
|
|
2
|
+
const nav = typeof navigator !== "undefined" ? navigator : undefined;
|
|
3
|
+
const win = typeof window !== "undefined" ? window : undefined;
|
|
4
|
+
const doc = typeof document !== "undefined" ? document : undefined;
|
|
5
|
+
const screen = win === null || win === void 0 ? void 0 : win.screen;
|
|
6
|
+
const viewportWidth = win ? win.innerWidth : undefined;
|
|
7
|
+
const viewportHeight = win ? win.innerHeight : undefined;
|
|
8
|
+
const scale = win ? win.devicePixelRatio || 1 : undefined;
|
|
9
|
+
const tz = typeof Intl !== "undefined"
|
|
10
|
+
? Intl.DateTimeFormat().resolvedOptions().timeZone
|
|
11
|
+
: undefined;
|
|
12
|
+
return {
|
|
13
|
+
userAgent: nav === null || nav === void 0 ? void 0 : nav.userAgent,
|
|
14
|
+
language: nav === null || nav === void 0 ? void 0 : nav.language,
|
|
15
|
+
platform: nav === null || nav === void 0 ? void 0 : nav.platform,
|
|
16
|
+
timezone: tz,
|
|
17
|
+
online: nav ? nav.onLine : undefined,
|
|
18
|
+
referrer: doc === null || doc === void 0 ? void 0 : doc.referrer,
|
|
19
|
+
screen: {
|
|
20
|
+
width: screen === null || screen === void 0 ? void 0 : screen.width,
|
|
21
|
+
height: screen === null || screen === void 0 ? void 0 : screen.height,
|
|
22
|
+
scale,
|
|
23
|
+
},
|
|
24
|
+
viewport: {
|
|
25
|
+
width: viewportWidth,
|
|
26
|
+
height: viewportHeight,
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@zyui/error-monitor-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"private": false,
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./react-native": {
|
|
14
|
+
"types": "./dist/utils/reactNative.d.ts",
|
|
15
|
+
"default": "./dist/utils/reactNative.js"
|
|
16
|
+
},
|
|
17
|
+
"./web": {
|
|
18
|
+
"types": "./dist/utils/web.d.ts",
|
|
19
|
+
"default": "./dist/utils/web.js"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"files": [
|
|
23
|
+
"dist"
|
|
24
|
+
],
|
|
25
|
+
"scripts": {
|
|
26
|
+
"build": "tsc -p tsconfig.json",
|
|
27
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
28
|
+
"example": "npm run build && node examples/dev-server.js",
|
|
29
|
+
"changeset": "changeset",
|
|
30
|
+
"version-packages": "changeset version",
|
|
31
|
+
"release": "npm run build && changeset publish"
|
|
32
|
+
},
|
|
33
|
+
"engines": {
|
|
34
|
+
"node": ">=16"
|
|
35
|
+
},
|
|
36
|
+
"publishConfig": {
|
|
37
|
+
"access": "public"
|
|
38
|
+
},
|
|
39
|
+
"devDependencies": {
|
|
40
|
+
"typescript": "^5.6.3",
|
|
41
|
+
"@changesets/cli": "^2.27.7"
|
|
42
|
+
}
|
|
43
|
+
}
|