error-monitor-plugin-behavior 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 +2 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +162 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +32 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});class o{constructor(e={}){this.name="behavior",this.version="1.0.0",this.core=null,this.originalPush=null,this.originalReplace=null,this.config={trackClicks:!0,trackInput:!0,trackNavigation:!0,trackHttp:!0,maxTraces:100,...e}}setup(e){typeof window>"u"||(this.core=e,this.config.trackClicks&&this.setupClickTracking(),this.config.trackInput&&this.setupInputTracking(),this.config.trackNavigation&&this.setupNavigationTracking(),this.config.trackHttp&&this.setupHttpTracking(),this.trackPageView())}setupClickTracking(){document.addEventListener("click",e=>{var t,i;const a=e.target;(i=this.core)==null||i.addBreadcrumb({timestamp:Date.now(),type:"ui",message:"click",data:{tagName:a.tagName,id:a.id,className:a.className,text:(t=a.textContent)==null?void 0:t.slice(0,50)}})},!0)}setupInputTracking(){["input","textarea","select"].forEach(a=>{document.addEventListener("input",t=>{var r;const i=t.target;if(i.matches(a)){let s=i.value;i.type==="password"?s="******":s.length>50&&(s=s.slice(0,50)+"..."),(r=this.core)==null||r.addBreadcrumb({timestamp:Date.now(),type:"ui",message:"input",data:{tagName:i.tagName,type:i.type,name:i.name,id:i.id,value:s}})}},!0)})}setupNavigationTracking(){this.originalPush=history.pushState,this.originalReplace=history.replaceState;const e=this;history.pushState=function(...a){var t;(t=e.originalPush)==null||t.apply(this,a),e.trackPageView()},history.replaceState=function(...a){var t;(t=e.originalReplace)==null||t.apply(this,a),e.trackPageView()},window.addEventListener("popstate",()=>{this.trackPageView()}),window.addEventListener("hashchange",()=>{this.trackPageView()})}setupHttpTracking(){const e=window.fetch,a=this;window.fetch=function(...t){var u;const i=typeof t[0]=="string"?t[0]:String(t[0]),r=((u=t[1])==null?void 0:u.method)||"GET",s=Date.now();return e.apply(this,t).then(n=>{var c;return(c=a.core)==null||c.addBreadcrumb({timestamp:Date.now(),type:"http",message:`${r} ${i}`,data:{url:i,method:r,status:n.status,duration:Date.now()-s}}),n}).catch(n=>{var c;throw(c=a.core)==null||c.addBreadcrumb({timestamp:Date.now(),type:"http",message:`${r} ${i} - Error`,data:{url:i,method:r,error:n.message,duration:Date.now()-s}}),n})}}trackPageView(){this.core&&this.core.addBreadcrumb({timestamp:Date.now(),type:"navigation",message:"pageview",data:{url:location.href,path:location.pathname,search:location.search,hash:location.hash}})}track(e,a){var t;(t=this.core)==null||t.addBreadcrumb({timestamp:Date.now(),type:"custom",message:e,data:a})}teardown(){this.originalPush&&history.pushState!==this.originalPush&&(history.pushState=this.originalPush),this.originalReplace&&history.replaceState!==this.originalReplace&&(history.replaceState=this.originalReplace)}}function l(h){return new o(h)}exports.BehaviorPlugin=o;exports.createBehaviorPlugin=l;exports.default=o;
|
|
2
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * Behavior Plugin\n * 用户行为追踪插件\n */\n\nimport type { Plugin, Core } from 'error-monitor-core'\n\n/**\n * 行为配置\n */\nexport interface BehaviorConfig {\n // 是否追踪点击\n trackClicks?: boolean\n // 是否追踪输入\n trackInput?: boolean\n // 是否追踪路由变化\n trackNavigation?: boolean\n // 是否追踪HTTP请求\n trackHttp?: boolean\n // 最大追踪数量\n maxTraces?: number\n}\n\n/**\n * 用户行为插件\n */\nexport class BehaviorPlugin implements Plugin {\n name = 'behavior'\n version = '1.0.0'\n private config: BehaviorConfig\n private core: Core | null = null\n private originalPush: typeof History.prototype.pushState | null = null\n private originalReplace: typeof History.prototype.replaceState | null = null\n\n constructor(config: BehaviorConfig = {}) {\n this.config = {\n trackClicks: true,\n trackInput: true,\n trackNavigation: true,\n trackHttp: true,\n maxTraces: 100,\n ...config\n }\n }\n\n /**\n * 插件设置\n */\n setup(core: Core): void {\n if (typeof window === 'undefined') {\n return\n }\n\n this.core = core\n\n // 追踪点击\n if (this.config.trackClicks) {\n this.setupClickTracking()\n }\n\n // 追踪输入\n if (this.config.trackInput) {\n this.setupInputTracking()\n }\n\n // 追踪路由\n if (this.config.trackNavigation) {\n this.setupNavigationTracking()\n }\n\n // 追踪HTTP\n if (this.config.trackHttp) {\n this.setupHttpTracking()\n }\n\n // 记录初始页面访问\n this.trackPageView()\n }\n\n /**\n * 追踪点击事件\n */\n private setupClickTracking(): void {\n document.addEventListener('click', (e) => {\n const target = e.target as HTMLElement\n\n this.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'ui',\n message: 'click',\n data: {\n tagName: target.tagName,\n id: target.id,\n className: target.className,\n text: target.textContent?.slice(0, 50)\n }\n })\n }, true)\n }\n\n /**\n * 追踪输入事件\n */\n private setupInputTracking(): void {\n const inputs = ['input', 'textarea', 'select']\n\n inputs.forEach(selector => {\n document.addEventListener('input', (e) => {\n const target = e.target as HTMLInputElement\n\n if (target.matches(selector)) {\n // 脱敏处理\n let value = target.value\n if (target.type === 'password') {\n value = '******'\n } else if (value.length > 50) {\n value = value.slice(0, 50) + '...'\n }\n\n this.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'ui',\n message: 'input',\n data: {\n tagName: target.tagName,\n type: target.type,\n name: target.name,\n id: target.id,\n value\n }\n })\n }\n }, true)\n })\n }\n\n /**\n * 追踪路由变化\n */\n private setupNavigationTracking(): void {\n // 拦截History API\n this.originalPush = history.pushState\n this.originalReplace = history.replaceState\n const self = this\n\n history.pushState = function (...args) {\n self.originalPush?.apply(this, args)\n self.trackPageView()\n }\n\n history.replaceState = function (...args) {\n self.originalReplace?.apply(this, args)\n self.trackPageView()\n }\n\n // 监听popstate事件(浏览器前进后退)\n window.addEventListener('popstate', () => {\n this.trackPageView()\n })\n\n // 监听hash变化\n window.addEventListener('hashchange', () => {\n this.trackPageView()\n })\n }\n\n /**\n * 追踪HTTP请求\n */\n private setupHttpTracking(): void {\n // 拦截fetch\n const originalFetch = window.fetch\n const self = this\n\n window.fetch = function (...args) {\n const url = typeof args[0] === 'string' ? args[0] : String(args[0])\n const method = args[1]?.method || 'GET'\n\n const startTime = Date.now()\n\n return originalFetch\n .apply(this, args)\n .then(response => {\n self.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'http',\n message: `${method} ${url}`,\n data: {\n url,\n method,\n status: response.status,\n duration: Date.now() - startTime\n }\n })\n\n return response\n })\n .catch(error => {\n self.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'http',\n message: `${method} ${url} - Error`,\n data: {\n url,\n method,\n error: error.message,\n duration: Date.now() - startTime\n }\n })\n\n throw error\n })\n }\n }\n\n /**\n * 记录页面访问\n */\n private trackPageView(): void {\n if (!this.core) return\n\n this.core.addBreadcrumb({\n timestamp: Date.now(),\n type: 'navigation',\n message: 'pageview',\n data: {\n url: location.href,\n path: location.pathname,\n search: location.search,\n hash: location.hash\n }\n })\n }\n\n /**\n * 手动追踪自定义事件\n */\n track(event: string, data?: Record<string, any>): void {\n this.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'custom',\n message: event,\n data\n })\n }\n\n /**\n * 插件销毁\n */\n teardown(): void {\n // 恢复原生方法\n if (this.originalPush && history.pushState !== this.originalPush) {\n history.pushState = this.originalPush\n }\n\n if (this.originalReplace && history.replaceState !== this.originalReplace) {\n history.replaceState = this.originalReplace\n }\n }\n}\n\n/**\n * 创建行为插件实例\n */\nexport function createBehaviorPlugin(config?: BehaviorConfig): BehaviorPlugin {\n return new BehaviorPlugin(config)\n}\n\nexport default BehaviorPlugin\n"],"names":["BehaviorPlugin","config","core","target","_b","_a","selector","e","value","self","args","originalFetch","url","method","startTime","response","error","event","data","createBehaviorPlugin"],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Plugin, Core } from 'error-monitor-core';
|
|
2
|
+
|
|
3
|
+
export interface BehaviorConfig {
|
|
4
|
+
trackClicks?: boolean;
|
|
5
|
+
trackInput?: boolean;
|
|
6
|
+
trackNavigation?: boolean;
|
|
7
|
+
trackHttp?: boolean;
|
|
8
|
+
maxTraces?: number;
|
|
9
|
+
}
|
|
10
|
+
export declare class BehaviorPlugin implements Plugin {
|
|
11
|
+
name: string;
|
|
12
|
+
version: string;
|
|
13
|
+
private config;
|
|
14
|
+
private core;
|
|
15
|
+
private originalPush;
|
|
16
|
+
private originalReplace;
|
|
17
|
+
constructor(config?: BehaviorConfig);
|
|
18
|
+
setup(core: Core): void;
|
|
19
|
+
private setupClickTracking;
|
|
20
|
+
private setupInputTracking;
|
|
21
|
+
private setupNavigationTracking;
|
|
22
|
+
private setupHttpTracking;
|
|
23
|
+
private trackPageView;
|
|
24
|
+
track(event: string, data?: Record<string, any>): void;
|
|
25
|
+
teardown(): void;
|
|
26
|
+
}
|
|
27
|
+
export declare function createBehaviorPlugin(config?: BehaviorConfig): BehaviorPlugin;
|
|
28
|
+
export default BehaviorPlugin;
|
|
29
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAA;AAKtD,MAAM,WAAW,cAAc;IAE7B,WAAW,CAAC,EAAE,OAAO,CAAA;IAErB,UAAU,CAAC,EAAE,OAAO,CAAA;IAEpB,eAAe,CAAC,EAAE,OAAO,CAAA;IAEzB,SAAS,CAAC,EAAE,OAAO,CAAA;IAEnB,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAKD,qBAAa,cAAe,YAAW,MAAM;IAC3C,IAAI,SAAa;IACjB,OAAO,SAAU;IACjB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,IAAI,CAAoB;IAChC,OAAO,CAAC,YAAY,CAAkD;IACtE,OAAO,CAAC,eAAe,CAAqD;gBAEhE,MAAM,GAAE,cAAmB;IAcvC,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAkCvB,OAAO,CAAC,kBAAkB;IAqB1B,OAAO,CAAC,kBAAkB;IAoC1B,OAAO,CAAC,uBAAuB;IA8B/B,OAAO,CAAC,iBAAiB;IAiDzB,OAAO,CAAC,aAAa;IAmBrB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI;IAYtD,QAAQ,IAAI,IAAI;CAUjB;AAKD,wBAAgB,oBAAoB,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,cAAc,CAE5E;AAED,eAAe,cAAc,CAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
class u {
|
|
2
|
+
constructor(e = {}) {
|
|
3
|
+
this.name = "behavior", this.version = "1.0.0", this.core = null, this.originalPush = null, this.originalReplace = null, this.config = {
|
|
4
|
+
trackClicks: !0,
|
|
5
|
+
trackInput: !0,
|
|
6
|
+
trackNavigation: !0,
|
|
7
|
+
trackHttp: !0,
|
|
8
|
+
maxTraces: 100,
|
|
9
|
+
...e
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* 插件设置
|
|
14
|
+
*/
|
|
15
|
+
setup(e) {
|
|
16
|
+
typeof window > "u" || (this.core = e, this.config.trackClicks && this.setupClickTracking(), this.config.trackInput && this.setupInputTracking(), this.config.trackNavigation && this.setupNavigationTracking(), this.config.trackHttp && this.setupHttpTracking(), this.trackPageView());
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* 追踪点击事件
|
|
20
|
+
*/
|
|
21
|
+
setupClickTracking() {
|
|
22
|
+
document.addEventListener("click", (e) => {
|
|
23
|
+
var t, i;
|
|
24
|
+
const a = e.target;
|
|
25
|
+
(i = this.core) == null || i.addBreadcrumb({
|
|
26
|
+
timestamp: Date.now(),
|
|
27
|
+
type: "ui",
|
|
28
|
+
message: "click",
|
|
29
|
+
data: {
|
|
30
|
+
tagName: a.tagName,
|
|
31
|
+
id: a.id,
|
|
32
|
+
className: a.className,
|
|
33
|
+
text: (t = a.textContent) == null ? void 0 : t.slice(0, 50)
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
}, !0);
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* 追踪输入事件
|
|
40
|
+
*/
|
|
41
|
+
setupInputTracking() {
|
|
42
|
+
["input", "textarea", "select"].forEach((a) => {
|
|
43
|
+
document.addEventListener("input", (t) => {
|
|
44
|
+
var r;
|
|
45
|
+
const i = t.target;
|
|
46
|
+
if (i.matches(a)) {
|
|
47
|
+
let s = i.value;
|
|
48
|
+
i.type === "password" ? s = "******" : s.length > 50 && (s = s.slice(0, 50) + "..."), (r = this.core) == null || r.addBreadcrumb({
|
|
49
|
+
timestamp: Date.now(),
|
|
50
|
+
type: "ui",
|
|
51
|
+
message: "input",
|
|
52
|
+
data: {
|
|
53
|
+
tagName: i.tagName,
|
|
54
|
+
type: i.type,
|
|
55
|
+
name: i.name,
|
|
56
|
+
id: i.id,
|
|
57
|
+
value: s
|
|
58
|
+
}
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
}, !0);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* 追踪路由变化
|
|
66
|
+
*/
|
|
67
|
+
setupNavigationTracking() {
|
|
68
|
+
this.originalPush = history.pushState, this.originalReplace = history.replaceState;
|
|
69
|
+
const e = this;
|
|
70
|
+
history.pushState = function(...a) {
|
|
71
|
+
var t;
|
|
72
|
+
(t = e.originalPush) == null || t.apply(this, a), e.trackPageView();
|
|
73
|
+
}, history.replaceState = function(...a) {
|
|
74
|
+
var t;
|
|
75
|
+
(t = e.originalReplace) == null || t.apply(this, a), e.trackPageView();
|
|
76
|
+
}, window.addEventListener("popstate", () => {
|
|
77
|
+
this.trackPageView();
|
|
78
|
+
}), window.addEventListener("hashchange", () => {
|
|
79
|
+
this.trackPageView();
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 追踪HTTP请求
|
|
84
|
+
*/
|
|
85
|
+
setupHttpTracking() {
|
|
86
|
+
const e = window.fetch, a = this;
|
|
87
|
+
window.fetch = function(...t) {
|
|
88
|
+
var h;
|
|
89
|
+
const i = typeof t[0] == "string" ? t[0] : String(t[0]), r = ((h = t[1]) == null ? void 0 : h.method) || "GET", s = Date.now();
|
|
90
|
+
return e.apply(this, t).then((n) => {
|
|
91
|
+
var c;
|
|
92
|
+
return (c = a.core) == null || c.addBreadcrumb({
|
|
93
|
+
timestamp: Date.now(),
|
|
94
|
+
type: "http",
|
|
95
|
+
message: `${r} ${i}`,
|
|
96
|
+
data: {
|
|
97
|
+
url: i,
|
|
98
|
+
method: r,
|
|
99
|
+
status: n.status,
|
|
100
|
+
duration: Date.now() - s
|
|
101
|
+
}
|
|
102
|
+
}), n;
|
|
103
|
+
}).catch((n) => {
|
|
104
|
+
var c;
|
|
105
|
+
throw (c = a.core) == null || c.addBreadcrumb({
|
|
106
|
+
timestamp: Date.now(),
|
|
107
|
+
type: "http",
|
|
108
|
+
message: `${r} ${i} - Error`,
|
|
109
|
+
data: {
|
|
110
|
+
url: i,
|
|
111
|
+
method: r,
|
|
112
|
+
error: n.message,
|
|
113
|
+
duration: Date.now() - s
|
|
114
|
+
}
|
|
115
|
+
}), n;
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* 记录页面访问
|
|
121
|
+
*/
|
|
122
|
+
trackPageView() {
|
|
123
|
+
this.core && this.core.addBreadcrumb({
|
|
124
|
+
timestamp: Date.now(),
|
|
125
|
+
type: "navigation",
|
|
126
|
+
message: "pageview",
|
|
127
|
+
data: {
|
|
128
|
+
url: location.href,
|
|
129
|
+
path: location.pathname,
|
|
130
|
+
search: location.search,
|
|
131
|
+
hash: location.hash
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* 手动追踪自定义事件
|
|
137
|
+
*/
|
|
138
|
+
track(e, a) {
|
|
139
|
+
var t;
|
|
140
|
+
(t = this.core) == null || t.addBreadcrumb({
|
|
141
|
+
timestamp: Date.now(),
|
|
142
|
+
type: "custom",
|
|
143
|
+
message: e,
|
|
144
|
+
data: a
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* 插件销毁
|
|
149
|
+
*/
|
|
150
|
+
teardown() {
|
|
151
|
+
this.originalPush && history.pushState !== this.originalPush && (history.pushState = this.originalPush), this.originalReplace && history.replaceState !== this.originalReplace && (history.replaceState = this.originalReplace);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function p(o) {
|
|
155
|
+
return new u(o);
|
|
156
|
+
}
|
|
157
|
+
export {
|
|
158
|
+
u as BehaviorPlugin,
|
|
159
|
+
p as createBehaviorPlugin,
|
|
160
|
+
u as default
|
|
161
|
+
};
|
|
162
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","sources":["../src/index.ts"],"sourcesContent":["/**\n * Behavior Plugin\n * 用户行为追踪插件\n */\n\nimport type { Plugin, Core } from 'error-monitor-core'\n\n/**\n * 行为配置\n */\nexport interface BehaviorConfig {\n // 是否追踪点击\n trackClicks?: boolean\n // 是否追踪输入\n trackInput?: boolean\n // 是否追踪路由变化\n trackNavigation?: boolean\n // 是否追踪HTTP请求\n trackHttp?: boolean\n // 最大追踪数量\n maxTraces?: number\n}\n\n/**\n * 用户行为插件\n */\nexport class BehaviorPlugin implements Plugin {\n name = 'behavior'\n version = '1.0.0'\n private config: BehaviorConfig\n private core: Core | null = null\n private originalPush: typeof History.prototype.pushState | null = null\n private originalReplace: typeof History.prototype.replaceState | null = null\n\n constructor(config: BehaviorConfig = {}) {\n this.config = {\n trackClicks: true,\n trackInput: true,\n trackNavigation: true,\n trackHttp: true,\n maxTraces: 100,\n ...config\n }\n }\n\n /**\n * 插件设置\n */\n setup(core: Core): void {\n if (typeof window === 'undefined') {\n return\n }\n\n this.core = core\n\n // 追踪点击\n if (this.config.trackClicks) {\n this.setupClickTracking()\n }\n\n // 追踪输入\n if (this.config.trackInput) {\n this.setupInputTracking()\n }\n\n // 追踪路由\n if (this.config.trackNavigation) {\n this.setupNavigationTracking()\n }\n\n // 追踪HTTP\n if (this.config.trackHttp) {\n this.setupHttpTracking()\n }\n\n // 记录初始页面访问\n this.trackPageView()\n }\n\n /**\n * 追踪点击事件\n */\n private setupClickTracking(): void {\n document.addEventListener('click', (e) => {\n const target = e.target as HTMLElement\n\n this.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'ui',\n message: 'click',\n data: {\n tagName: target.tagName,\n id: target.id,\n className: target.className,\n text: target.textContent?.slice(0, 50)\n }\n })\n }, true)\n }\n\n /**\n * 追踪输入事件\n */\n private setupInputTracking(): void {\n const inputs = ['input', 'textarea', 'select']\n\n inputs.forEach(selector => {\n document.addEventListener('input', (e) => {\n const target = e.target as HTMLInputElement\n\n if (target.matches(selector)) {\n // 脱敏处理\n let value = target.value\n if (target.type === 'password') {\n value = '******'\n } else if (value.length > 50) {\n value = value.slice(0, 50) + '...'\n }\n\n this.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'ui',\n message: 'input',\n data: {\n tagName: target.tagName,\n type: target.type,\n name: target.name,\n id: target.id,\n value\n }\n })\n }\n }, true)\n })\n }\n\n /**\n * 追踪路由变化\n */\n private setupNavigationTracking(): void {\n // 拦截History API\n this.originalPush = history.pushState\n this.originalReplace = history.replaceState\n const self = this\n\n history.pushState = function (...args) {\n self.originalPush?.apply(this, args)\n self.trackPageView()\n }\n\n history.replaceState = function (...args) {\n self.originalReplace?.apply(this, args)\n self.trackPageView()\n }\n\n // 监听popstate事件(浏览器前进后退)\n window.addEventListener('popstate', () => {\n this.trackPageView()\n })\n\n // 监听hash变化\n window.addEventListener('hashchange', () => {\n this.trackPageView()\n })\n }\n\n /**\n * 追踪HTTP请求\n */\n private setupHttpTracking(): void {\n // 拦截fetch\n const originalFetch = window.fetch\n const self = this\n\n window.fetch = function (...args) {\n const url = typeof args[0] === 'string' ? args[0] : String(args[0])\n const method = args[1]?.method || 'GET'\n\n const startTime = Date.now()\n\n return originalFetch\n .apply(this, args)\n .then(response => {\n self.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'http',\n message: `${method} ${url}`,\n data: {\n url,\n method,\n status: response.status,\n duration: Date.now() - startTime\n }\n })\n\n return response\n })\n .catch(error => {\n self.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'http',\n message: `${method} ${url} - Error`,\n data: {\n url,\n method,\n error: error.message,\n duration: Date.now() - startTime\n }\n })\n\n throw error\n })\n }\n }\n\n /**\n * 记录页面访问\n */\n private trackPageView(): void {\n if (!this.core) return\n\n this.core.addBreadcrumb({\n timestamp: Date.now(),\n type: 'navigation',\n message: 'pageview',\n data: {\n url: location.href,\n path: location.pathname,\n search: location.search,\n hash: location.hash\n }\n })\n }\n\n /**\n * 手动追踪自定义事件\n */\n track(event: string, data?: Record<string, any>): void {\n this.core?.addBreadcrumb({\n timestamp: Date.now(),\n type: 'custom',\n message: event,\n data\n })\n }\n\n /**\n * 插件销毁\n */\n teardown(): void {\n // 恢复原生方法\n if (this.originalPush && history.pushState !== this.originalPush) {\n history.pushState = this.originalPush\n }\n\n if (this.originalReplace && history.replaceState !== this.originalReplace) {\n history.replaceState = this.originalReplace\n }\n }\n}\n\n/**\n * 创建行为插件实例\n */\nexport function createBehaviorPlugin(config?: BehaviorConfig): BehaviorPlugin {\n return new BehaviorPlugin(config)\n}\n\nexport default BehaviorPlugin\n"],"names":["BehaviorPlugin","config","core","_a","_b","target","selector","e","value","self","args","originalFetch","url","method","startTime","response","error","event","data","createBehaviorPlugin"],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "error-monitor-plugin-behavior",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"description": "User behavior tracking plugin for error-monitor-sdk",
|
|
5
|
+
"main": "./dist/index.cjs",
|
|
6
|
+
"module": "./dist/index.mjs",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist"
|
|
10
|
+
],
|
|
11
|
+
"keywords": [
|
|
12
|
+
"error",
|
|
13
|
+
"monitor",
|
|
14
|
+
"plugin",
|
|
15
|
+
"behavior",
|
|
16
|
+
"tracking"
|
|
17
|
+
],
|
|
18
|
+
"author": "",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"error-monitor-core": "workspace:*"
|
|
22
|
+
},
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "vite build",
|
|
25
|
+
"dev": "vite build --watch",
|
|
26
|
+
"clean": "rm -rf dist"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"vite": "^5.1.6",
|
|
30
|
+
"vite-plugin-dts": "^3.7.3"
|
|
31
|
+
}
|
|
32
|
+
}
|