@lark-sentry/core 1.0.0 → 1.0.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/dist/index.cjs +104 -66
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +105 -67
- package/dist/index.js.map +1 -1
- package/dist/index.min.cjs +5 -5
- package/dist/index.min.cjs.map +1 -1
- package/dist/index.min.js +5 -5
- package/dist/index.min.js.map +1 -1
- package/index.ts +70 -0
- package/package.json +5 -21
- package/package.prod.json +39 -0
- package/src/breadcrumb.ts +26 -0
- package/src/bus.ts +31 -0
- package/src/decorate-publish.ts +276 -0
- package/src/handlers.ts +230 -0
- package/src/setup.ts +48 -0
- package/src/white-screen.ts +146 -0
package/index.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { Status, type IOptions, type SentryPlugin } from "@lark-sentry/types";
|
|
2
|
+
|
|
3
|
+
import { getBaseData, sentry } from "@lark-sentry/utils";
|
|
4
|
+
|
|
5
|
+
import { DEFAULT_OPTIONS } from "@lark-sentry/constants";
|
|
6
|
+
|
|
7
|
+
import { handleError } from "./src/handlers.js";
|
|
8
|
+
import setup from "./src/setup.js";
|
|
9
|
+
|
|
10
|
+
import { type Plugin, type ComponentPublicInstance } from "vue";
|
|
11
|
+
import { Component, type ErrorInfo } from "react";
|
|
12
|
+
import { EventType } from "@lark-sentry/types/dist/index.cjs";
|
|
13
|
+
|
|
14
|
+
function init(
|
|
15
|
+
options: Partial<Omit<IOptions, "dsn">> & NonNullable<Pick<IOptions, "dsn">>,
|
|
16
|
+
) {
|
|
17
|
+
sentry.setOptions({ ...DEFAULT_OPTIONS, ...options });
|
|
18
|
+
const { dsn } = sentry.options;
|
|
19
|
+
if (dsn === "") {
|
|
20
|
+
console.error("[lark-sentry] dsn is empty");
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
setup();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const vuePlugin: Plugin = (app, options: IOptions) => {
|
|
27
|
+
const handler = app.config.errorHandler;
|
|
28
|
+
app.config.errorHandler = (
|
|
29
|
+
err: unknown,
|
|
30
|
+
vueInstance: ComponentPublicInstance | null,
|
|
31
|
+
info: string,
|
|
32
|
+
) => {
|
|
33
|
+
handleError({
|
|
34
|
+
...getBaseData(),
|
|
35
|
+
type: EventType.Vue,
|
|
36
|
+
status: Status.Error,
|
|
37
|
+
extra: err,
|
|
38
|
+
});
|
|
39
|
+
if (handler) {
|
|
40
|
+
handler.call(null, err, vueInstance, info);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
init(options);
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
class ReactErrorBoundary extends Component {
|
|
47
|
+
override componentDidCatch(error: Error, errorInfo: ErrorInfo): void {
|
|
48
|
+
handleError({
|
|
49
|
+
...getBaseData(),
|
|
50
|
+
type: EventType.React,
|
|
51
|
+
status: Status.Error,
|
|
52
|
+
extra: {
|
|
53
|
+
error,
|
|
54
|
+
errorInfo,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function use<T extends SentryPlugin, U = unknown>(
|
|
61
|
+
Plugin: new (options?: U) => T,
|
|
62
|
+
options?: U,
|
|
63
|
+
) {
|
|
64
|
+
const plugin = new Plugin(options);
|
|
65
|
+
plugin.init();
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export { init, vuePlugin, use, ReactErrorBoundary };
|
|
69
|
+
|
|
70
|
+
// init({ dsn: "http://localhost:3000" });
|
package/package.json
CHANGED
|
@@ -1,24 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lark-sentry/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Sentry sdk core",
|
|
5
5
|
"type": "module",
|
|
6
|
-
"main": "./dist/index.cjs",
|
|
7
|
-
"module": "./dist/index.js",
|
|
8
|
-
"types": "./dist/index.d.ts",
|
|
9
|
-
"exports": {
|
|
10
|
-
".": {
|
|
11
|
-
"types": "./dist/index.d.ts",
|
|
12
|
-
"import": "./dist/index.js",
|
|
13
|
-
"require": "./dist/index.cjs"
|
|
14
|
-
}
|
|
15
|
-
},
|
|
16
|
-
"files": [
|
|
17
|
-
"dist"
|
|
18
|
-
],
|
|
19
|
-
"publishConfig": {
|
|
20
|
-
"access": "public"
|
|
21
|
-
},
|
|
22
6
|
"keywords": [
|
|
23
7
|
"sentry",
|
|
24
8
|
"sdk",
|
|
@@ -27,10 +11,10 @@
|
|
|
27
11
|
"author": "github.com/161043261",
|
|
28
12
|
"license": "MIT",
|
|
29
13
|
"dependencies": {
|
|
30
|
-
"@lark-sentry/constants": "^1.0.
|
|
31
|
-
"@lark-sentry/utils": "^1.0.
|
|
32
|
-
"@lark-sentry/reporter": "^1.0.
|
|
33
|
-
"@lark-sentry/types": "^1.0.
|
|
14
|
+
"@lark-sentry/constants": "^1.0.1",
|
|
15
|
+
"@lark-sentry/utils": "^1.0.1",
|
|
16
|
+
"@lark-sentry/reporter": "^1.0.1",
|
|
17
|
+
"@lark-sentry/types": "^1.0.1"
|
|
34
18
|
},
|
|
35
19
|
"devDependencies": {
|
|
36
20
|
"@types/react": "^19.2.7",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@lark-sentry/core",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Sentry sdk core",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"require": "./dist/index.cjs"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": ["dist"],
|
|
17
|
+
"publishConfig": {
|
|
18
|
+
"access": "public"
|
|
19
|
+
},
|
|
20
|
+
"keywords": ["sentry", "sdk", "core"],
|
|
21
|
+
"author": "github.com/161043261",
|
|
22
|
+
"license": "MIT",
|
|
23
|
+
"dependencies": {
|
|
24
|
+
"@lark-sentry/constants": "workspace:^",
|
|
25
|
+
"@lark-sentry/reporter": "workspace:^",
|
|
26
|
+
"@lark-sentry/types": "workspace:^",
|
|
27
|
+
"@lark-sentry/utils": "workspace:^"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@types/react": "^19.2.7",
|
|
31
|
+
"@types/react-dom": "^19.2.3",
|
|
32
|
+
"react": "^19.2.3",
|
|
33
|
+
"vue": "^3.5.26"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"react": "^19.2.3",
|
|
37
|
+
"vue": "^3.5.26"
|
|
38
|
+
}
|
|
39
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { IBreadcrumbItem } from "@lark-sentry/types";
|
|
2
|
+
|
|
3
|
+
import { MinHeap, sentry } from "@lark-sentry/utils";
|
|
4
|
+
|
|
5
|
+
export class Breadcrumb extends MinHeap<IBreadcrumbItem> {
|
|
6
|
+
static #instance: Breadcrumb;
|
|
7
|
+
|
|
8
|
+
public static get instance() {
|
|
9
|
+
if (!Breadcrumb.#instance) {
|
|
10
|
+
Breadcrumb.#instance = new Breadcrumb();
|
|
11
|
+
}
|
|
12
|
+
return Breadcrumb.#instance;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
override push(data: IBreadcrumbItem) {
|
|
16
|
+
const { onBeforePushBreadcrumb } = sentry.options;
|
|
17
|
+
if (onBeforePushBreadcrumb) {
|
|
18
|
+
data = onBeforePushBreadcrumb(data);
|
|
19
|
+
}
|
|
20
|
+
return super.push(data);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const breadcrumb = Breadcrumb.instance;
|
|
25
|
+
|
|
26
|
+
export default breadcrumb;
|
package/src/bus.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EventType,
|
|
3
|
+
type IPub,
|
|
4
|
+
type ISub,
|
|
5
|
+
type TEventHandler,
|
|
6
|
+
} from "@lark-sentry/types";
|
|
7
|
+
|
|
8
|
+
const event2handlers = new Map<EventType, Set<TEventHandler>>();
|
|
9
|
+
|
|
10
|
+
export const pub: IPub = (type, data) => {
|
|
11
|
+
const handlers = event2handlers.get(type);
|
|
12
|
+
if (!handlers) {
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
for (const handler of handlers) {
|
|
17
|
+
handler(data);
|
|
18
|
+
}
|
|
19
|
+
} catch (err) {
|
|
20
|
+
console.log("[lark-sentry] error", err);
|
|
21
|
+
}
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const sub: ISub = (type, handler) => {
|
|
25
|
+
const handlers = event2handlers.get(type);
|
|
26
|
+
if (!handlers) {
|
|
27
|
+
event2handlers.set(type, new Set([handler]));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
handlers.add(handler);
|
|
31
|
+
};
|
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EventType,
|
|
3
|
+
HttpMethod,
|
|
4
|
+
HttpStatusCode,
|
|
5
|
+
type IHttpData,
|
|
6
|
+
type WithSentry,
|
|
7
|
+
} from "@lark-sentry/types";
|
|
8
|
+
|
|
9
|
+
import {
|
|
10
|
+
throttle,
|
|
11
|
+
sentry,
|
|
12
|
+
decorateProp,
|
|
13
|
+
getBaseData,
|
|
14
|
+
isExcludedApi,
|
|
15
|
+
} from "@lark-sentry/utils";
|
|
16
|
+
|
|
17
|
+
import { pub } from "./bus.js";
|
|
18
|
+
|
|
19
|
+
function decoratePublish(type: EventType) {
|
|
20
|
+
switch (type) {
|
|
21
|
+
case EventType.Click: {
|
|
22
|
+
pubClick();
|
|
23
|
+
break;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
case EventType.Error: {
|
|
27
|
+
pubError();
|
|
28
|
+
break;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
case EventType.Xhr: {
|
|
32
|
+
pubXhr();
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
case EventType.Fetch: {
|
|
37
|
+
pubFetch();
|
|
38
|
+
break;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
case EventType.History: {
|
|
42
|
+
pubHistory();
|
|
43
|
+
break;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
case EventType.UnhandledRejection: {
|
|
47
|
+
pubUnhandledRejection();
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
case EventType.HashChange: {
|
|
52
|
+
pubHashChange();
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
case EventType.WhiteScreen: {
|
|
57
|
+
pubWhiteScreen();
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
default: {
|
|
62
|
+
break;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function pubClick() {
|
|
68
|
+
const throttledPub = throttle(pub, sentry.options.clickThrottleDelay);
|
|
69
|
+
document.addEventListener("click", function (ctx: MouseEvent) {
|
|
70
|
+
// publish
|
|
71
|
+
throttledPub(EventType.Click, {
|
|
72
|
+
...getBaseData(),
|
|
73
|
+
type: EventType.Click,
|
|
74
|
+
extra: ctx,
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function pubError() {
|
|
80
|
+
globalThis.addEventListener("error", function (ctx: ErrorEvent) {
|
|
81
|
+
// publish
|
|
82
|
+
pub(EventType.Error, {
|
|
83
|
+
...getBaseData(),
|
|
84
|
+
type: EventType.Error,
|
|
85
|
+
extra: ctx,
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function pubXhr() {
|
|
91
|
+
type TXhrProtoOpen = (
|
|
92
|
+
method: string,
|
|
93
|
+
url: string,
|
|
94
|
+
async?: boolean,
|
|
95
|
+
...rest: string[]
|
|
96
|
+
) => void;
|
|
97
|
+
|
|
98
|
+
const xhrProto = XMLHttpRequest.prototype;
|
|
99
|
+
|
|
100
|
+
decorateProp(xhrProto, "open", (oldPropVal: TXhrProtoOpen) => {
|
|
101
|
+
return function (
|
|
102
|
+
this: WithSentry<XMLHttpRequest, IHttpData>,
|
|
103
|
+
method: string,
|
|
104
|
+
url: string,
|
|
105
|
+
async?: boolean,
|
|
106
|
+
...rest: string[]
|
|
107
|
+
) {
|
|
108
|
+
const httpData: IHttpData = {
|
|
109
|
+
...getBaseData(),
|
|
110
|
+
name: "XMLHttpRequest",
|
|
111
|
+
type: EventType.Xhr,
|
|
112
|
+
method: method.toUpperCase(),
|
|
113
|
+
api: url,
|
|
114
|
+
elapsedTime: 0,
|
|
115
|
+
statusCode: HttpStatusCode.OK,
|
|
116
|
+
};
|
|
117
|
+
this.__sentry__ = httpData;
|
|
118
|
+
return oldPropVal.call(this, method, url, async, ...rest);
|
|
119
|
+
};
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
decorateProp(xhrProto, "send", (oldPropVal) => {
|
|
123
|
+
return function (
|
|
124
|
+
this: WithSentry<XMLHttpRequest, IHttpData>,
|
|
125
|
+
body?: Document | XMLHttpRequestBodyInit | null | undefined,
|
|
126
|
+
) {
|
|
127
|
+
const { method, api } = this.__sentry__;
|
|
128
|
+
this.addEventListener("loadend", () => {
|
|
129
|
+
if (
|
|
130
|
+
(method.toUpperCase() === HttpMethod.Post &&
|
|
131
|
+
api === sentry.options.dsn) ||
|
|
132
|
+
isExcludedApi(api)
|
|
133
|
+
) {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const { status, responseType, response } = this;
|
|
137
|
+
this.__sentry__.statusCode = status;
|
|
138
|
+
this.__sentry__.requestData = { body };
|
|
139
|
+
this.__sentry__.responseData = {
|
|
140
|
+
responseType,
|
|
141
|
+
response,
|
|
142
|
+
};
|
|
143
|
+
const endTime = Date.now();
|
|
144
|
+
this.__sentry__.elapsedTime = endTime - this.__sentry__.timestamp;
|
|
145
|
+
|
|
146
|
+
// publish
|
|
147
|
+
pub(EventType.Xhr, this.__sentry__);
|
|
148
|
+
});
|
|
149
|
+
return oldPropVal.call(this, body);
|
|
150
|
+
};
|
|
151
|
+
});
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function pubFetch() {
|
|
155
|
+
decorateProp(globalThis, "fetch", (oldPropVal) => {
|
|
156
|
+
return async function (
|
|
157
|
+
url: RequestInfo | URL,
|
|
158
|
+
options?: RequestInit | undefined,
|
|
159
|
+
) {
|
|
160
|
+
const method = options?.method?.toUpperCase() ?? HttpMethod.Get;
|
|
161
|
+
const httpData: IHttpData = {
|
|
162
|
+
...getBaseData(),
|
|
163
|
+
type: EventType.Fetch,
|
|
164
|
+
method,
|
|
165
|
+
requestData: { body: options?.body },
|
|
166
|
+
name: "Fetch",
|
|
167
|
+
api: url.toString(),
|
|
168
|
+
elapsedTime: 0,
|
|
169
|
+
statusCode: HttpStatusCode.OK,
|
|
170
|
+
};
|
|
171
|
+
return oldPropVal.call(globalThis, url, options).then((res: Response) => {
|
|
172
|
+
const resClone = res.clone();
|
|
173
|
+
const endTime = Date.now();
|
|
174
|
+
httpData.elapsedTime = endTime - httpData.timestamp;
|
|
175
|
+
httpData.statusCode = resClone.status;
|
|
176
|
+
resClone.text().then((res: string) => {
|
|
177
|
+
if (
|
|
178
|
+
(method === HttpMethod.Post &&
|
|
179
|
+
url.toString() === sentry.options.dsn) ||
|
|
180
|
+
isExcludedApi(url.toString())
|
|
181
|
+
) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
httpData.responseData = res;
|
|
185
|
+
|
|
186
|
+
// publish
|
|
187
|
+
pub(EventType.Fetch, httpData);
|
|
188
|
+
});
|
|
189
|
+
return res;
|
|
190
|
+
});
|
|
191
|
+
};
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
let latestHref = document.location.href;
|
|
196
|
+
function pubHistory() {
|
|
197
|
+
const oldOnpopstate = globalThis.onpopstate;
|
|
198
|
+
if (typeof oldOnpopstate !== "function") {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
globalThis.onpopstate = function (this: Window, ev: PopStateEvent) {
|
|
203
|
+
const from = latestHref;
|
|
204
|
+
const to = document.location.href;
|
|
205
|
+
latestHref = to;
|
|
206
|
+
pub(EventType.History, {
|
|
207
|
+
...getBaseData(),
|
|
208
|
+
type: EventType.History,
|
|
209
|
+
from,
|
|
210
|
+
to,
|
|
211
|
+
});
|
|
212
|
+
return oldOnpopstate.call(this, ev);
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const historyDecorator = (oldPropsVal: History["pushState"]) => {
|
|
216
|
+
return function (
|
|
217
|
+
this: History,
|
|
218
|
+
data: unknown,
|
|
219
|
+
unused: string,
|
|
220
|
+
url?: string | URL | null,
|
|
221
|
+
) {
|
|
222
|
+
if (url) {
|
|
223
|
+
const from = latestHref;
|
|
224
|
+
const to = url.toString();
|
|
225
|
+
latestHref = to;
|
|
226
|
+
|
|
227
|
+
// publish
|
|
228
|
+
pub(EventType.History, {
|
|
229
|
+
...getBaseData(),
|
|
230
|
+
type: EventType.History,
|
|
231
|
+
from,
|
|
232
|
+
to,
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
return oldPropsVal.call(this, data, unused, url);
|
|
236
|
+
};
|
|
237
|
+
};
|
|
238
|
+
decorateProp(globalThis.history, "pushState", historyDecorator);
|
|
239
|
+
decorateProp(globalThis.history, "replaceState", historyDecorator);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function pubUnhandledRejection() {
|
|
243
|
+
globalThis.addEventListener(
|
|
244
|
+
"unhandledrejection",
|
|
245
|
+
function (ctx: PromiseRejectionEvent) {
|
|
246
|
+
// publish
|
|
247
|
+
pub(EventType.UnhandledRejection, {
|
|
248
|
+
...getBaseData(),
|
|
249
|
+
type: EventType.UnhandledRejection,
|
|
250
|
+
extra: ctx,
|
|
251
|
+
});
|
|
252
|
+
},
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function pubHashChange() {
|
|
257
|
+
globalThis.addEventListener("hashchange", function (ctx: HashChangeEvent) {
|
|
258
|
+
// publish
|
|
259
|
+
pub(EventType.HashChange, {
|
|
260
|
+
...getBaseData(),
|
|
261
|
+
type: EventType.HashChange,
|
|
262
|
+
extra: ctx,
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
function pubWhiteScreen() {
|
|
268
|
+
// publish
|
|
269
|
+
pub(EventType.WhiteScreen, {
|
|
270
|
+
...getBaseData(),
|
|
271
|
+
type: EventType.WhiteScreen,
|
|
272
|
+
extra: "WhiteScreen",
|
|
273
|
+
});
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export default decoratePublish;
|
package/src/handlers.ts
ADDED
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
import {
|
|
2
|
+
EventType,
|
|
3
|
+
Status,
|
|
4
|
+
type IReportPayload,
|
|
5
|
+
type ICodeError,
|
|
6
|
+
type IHttpData,
|
|
7
|
+
type IRouteData,
|
|
8
|
+
type IResourceError,
|
|
9
|
+
type TEventHandler,
|
|
10
|
+
type IBaseDataWithEvent,
|
|
11
|
+
} from "@lark-sentry/types";
|
|
12
|
+
|
|
13
|
+
import {
|
|
14
|
+
sentry,
|
|
15
|
+
getBaseData,
|
|
16
|
+
event2breadcrumb,
|
|
17
|
+
base64v2,
|
|
18
|
+
transformHttpData,
|
|
19
|
+
dom2str,
|
|
20
|
+
isIExtendedErrorEvent,
|
|
21
|
+
isErrorEvent,
|
|
22
|
+
isError,
|
|
23
|
+
} from "@lark-sentry/utils";
|
|
24
|
+
|
|
25
|
+
import { UNKNOWN } from "@lark-sentry/constants";
|
|
26
|
+
|
|
27
|
+
import reporter from "@lark-sentry/reporter";
|
|
28
|
+
|
|
29
|
+
import breadcrumb from "./breadcrumb.js";
|
|
30
|
+
import checkWhiteScreen from "./white-screen.js";
|
|
31
|
+
|
|
32
|
+
const handleHttp: TEventHandler<IHttpData> = (data: IHttpData) => {
|
|
33
|
+
data = transformHttpData(data);
|
|
34
|
+
const { id, name, time, timestamp, message, status, type } = data;
|
|
35
|
+
if (!data.api.includes(sentry.options.dsn)) {
|
|
36
|
+
breadcrumb.push({
|
|
37
|
+
id,
|
|
38
|
+
name,
|
|
39
|
+
time,
|
|
40
|
+
timestamp,
|
|
41
|
+
message,
|
|
42
|
+
status,
|
|
43
|
+
type,
|
|
44
|
+
userAction: event2breadcrumb(type),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
if (status === Status.Error) {
|
|
48
|
+
reporter.send(data);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const handleError: TEventHandler<IBaseDataWithEvent> = ({
|
|
53
|
+
extra: err,
|
|
54
|
+
...rest
|
|
55
|
+
}) => {
|
|
56
|
+
if (isErrorEvent(err)) {
|
|
57
|
+
handleCodeError(err);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
if (isIExtendedErrorEvent(err)) {
|
|
61
|
+
const { localName, src, href } = err.target;
|
|
62
|
+
const { message } = err;
|
|
63
|
+
const resourceError: IResourceError = {
|
|
64
|
+
...rest,
|
|
65
|
+
type: EventType.Resource,
|
|
66
|
+
status: Status.Error,
|
|
67
|
+
name: localName,
|
|
68
|
+
src,
|
|
69
|
+
href,
|
|
70
|
+
message,
|
|
71
|
+
};
|
|
72
|
+
breadcrumb.push({
|
|
73
|
+
...resourceError,
|
|
74
|
+
userAction: event2breadcrumb(EventType.Resource),
|
|
75
|
+
});
|
|
76
|
+
reporter.send(resourceError);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (isError(err)) {
|
|
81
|
+
const { name, message } = err;
|
|
82
|
+
const data: IBaseDataWithEvent = {
|
|
83
|
+
...rest,
|
|
84
|
+
type: EventType.Error,
|
|
85
|
+
name,
|
|
86
|
+
message,
|
|
87
|
+
status: Status.Error,
|
|
88
|
+
extra: err,
|
|
89
|
+
};
|
|
90
|
+
breadcrumb.push({
|
|
91
|
+
...data,
|
|
92
|
+
userAction: event2breadcrumb(EventType.Error),
|
|
93
|
+
});
|
|
94
|
+
reporter.send(data);
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// Unknown error
|
|
99
|
+
const data: IBaseDataWithEvent = {
|
|
100
|
+
...rest,
|
|
101
|
+
type: EventType.Error,
|
|
102
|
+
name: "Unknown Error",
|
|
103
|
+
message: JSON.stringify(err),
|
|
104
|
+
status: Status.Error,
|
|
105
|
+
extra: err,
|
|
106
|
+
};
|
|
107
|
+
breadcrumb.push({
|
|
108
|
+
...data,
|
|
109
|
+
userAction: event2breadcrumb(EventType.Error),
|
|
110
|
+
});
|
|
111
|
+
reporter.send(data);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const handleHistory: TEventHandler<IRouteData> = ({
|
|
115
|
+
from,
|
|
116
|
+
to,
|
|
117
|
+
...rest
|
|
118
|
+
}: IRouteData) => {
|
|
119
|
+
const routeChange = `${from} => ${to}`;
|
|
120
|
+
const routeData: IRouteData = {
|
|
121
|
+
...rest,
|
|
122
|
+
name: routeChange,
|
|
123
|
+
message: routeChange,
|
|
124
|
+
type: EventType.History,
|
|
125
|
+
from,
|
|
126
|
+
to,
|
|
127
|
+
};
|
|
128
|
+
breadcrumb.push({
|
|
129
|
+
...routeData,
|
|
130
|
+
userAction: event2breadcrumb(EventType.History),
|
|
131
|
+
});
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
const handleHashChange: TEventHandler<IBaseDataWithEvent> = ({
|
|
135
|
+
extra,
|
|
136
|
+
...rest
|
|
137
|
+
}: IBaseDataWithEvent) => {
|
|
138
|
+
const { oldURL: from = UNKNOWN, newURL: to = UNKNOWN } =
|
|
139
|
+
extra as HashChangeEvent;
|
|
140
|
+
const pathChange = `${from} => ${to}`;
|
|
141
|
+
const routeData: IRouteData = {
|
|
142
|
+
...rest,
|
|
143
|
+
name: pathChange,
|
|
144
|
+
message: pathChange,
|
|
145
|
+
type: EventType.HashChange,
|
|
146
|
+
from,
|
|
147
|
+
to,
|
|
148
|
+
};
|
|
149
|
+
breadcrumb.push({
|
|
150
|
+
...routeData,
|
|
151
|
+
userAction: event2breadcrumb(EventType.HashChange),
|
|
152
|
+
});
|
|
153
|
+
};
|
|
154
|
+
|
|
155
|
+
const handleUnhandledRejection: TEventHandler<IBaseDataWithEvent> = (
|
|
156
|
+
data: IBaseDataWithEvent,
|
|
157
|
+
) => {
|
|
158
|
+
if (!isIExtendedErrorEvent(data.extra)) {
|
|
159
|
+
handleError(data);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
handleCodeError(data.extra);
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
const handleWhiteScreen: TEventHandler<IBaseDataWithEvent> = (
|
|
166
|
+
data: IBaseDataWithEvent,
|
|
167
|
+
) => {
|
|
168
|
+
checkWhiteScreen(() => {
|
|
169
|
+
reporter.send(data);
|
|
170
|
+
});
|
|
171
|
+
return;
|
|
172
|
+
};
|
|
173
|
+
|
|
174
|
+
const handleClick: TEventHandler<IBaseDataWithEvent> = ({
|
|
175
|
+
extra,
|
|
176
|
+
...rest
|
|
177
|
+
}: IBaseDataWithEvent) => {
|
|
178
|
+
const typedEvent = extra as PointerEvent;
|
|
179
|
+
const str =
|
|
180
|
+
typedEvent.target instanceof HTMLElement ? dom2str(typedEvent.target) : "";
|
|
181
|
+
breadcrumb.push({
|
|
182
|
+
...rest,
|
|
183
|
+
type: EventType.Click,
|
|
184
|
+
name: str,
|
|
185
|
+
message: str,
|
|
186
|
+
userAction: event2breadcrumb(EventType.Click),
|
|
187
|
+
});
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export {
|
|
191
|
+
handleError,
|
|
192
|
+
handleHistory,
|
|
193
|
+
handleHashChange,
|
|
194
|
+
handleHttp,
|
|
195
|
+
handleUnhandledRejection,
|
|
196
|
+
handleWhiteScreen,
|
|
197
|
+
handleClick,
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
const handleCodeError = (err: ErrorEvent) => {
|
|
201
|
+
const { filename, colno: column, lineno: line, message } = err;
|
|
202
|
+
const data: IReportPayload = {
|
|
203
|
+
...getBaseData(),
|
|
204
|
+
type: EventType.Error,
|
|
205
|
+
name: filename,
|
|
206
|
+
message,
|
|
207
|
+
status: Status.Error,
|
|
208
|
+
};
|
|
209
|
+
const codeError: ICodeError = {
|
|
210
|
+
...data,
|
|
211
|
+
column,
|
|
212
|
+
line,
|
|
213
|
+
};
|
|
214
|
+
breadcrumb.push({
|
|
215
|
+
...data,
|
|
216
|
+
userAction: event2breadcrumb(EventType.Error),
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
const errorId = base64v2(
|
|
220
|
+
`${EventType.Error}-${message}-${filename}-${line}-${column}`,
|
|
221
|
+
);
|
|
222
|
+
if (
|
|
223
|
+
errorId.includes(UNKNOWN) ||
|
|
224
|
+
sentry.options.repeatCodeError ||
|
|
225
|
+
(!sentry.options.repeatCodeError && !sentry.codeErrors.has(errorId))
|
|
226
|
+
) {
|
|
227
|
+
sentry.codeErrors.add(errorId);
|
|
228
|
+
reporter.send(codeError);
|
|
229
|
+
}
|
|
230
|
+
};
|