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 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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"}
@@ -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
+ }