@gctrack/network 0.1.2 → 0.2.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/index.cjs CHANGED
@@ -1,5 +1,28 @@
1
- Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- let _gctrack_protocol = require("@gctrack/protocol");
1
+ //#region rolldown:runtime
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __copyProps = (to, from, except, desc) => {
9
+ if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
10
+ key = keys[i];
11
+ if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
12
+ get: ((k) => from[k]).bind(null, key),
13
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
14
+ });
15
+ }
16
+ return to;
17
+ };
18
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
19
+ value: mod,
20
+ enumerable: true
21
+ }) : target, mod));
22
+
23
+ //#endregion
24
+ const __gctrack_protocol = __toESM(require("@gctrack/protocol"));
25
+
3
26
  //#region src/index.ts
4
27
  const ORIGINAL_FETCH = typeof fetch !== "undefined" ? fetch.bind(globalThis) : void 0;
5
28
  const ORIGINAL_OPEN = typeof XMLHttpRequest !== "undefined" ? XMLHttpRequest.prototype.open : void 0;
@@ -15,7 +38,7 @@ function createNetworkMonitor(tracker, options = {}) {
15
38
  };
16
39
  const report = (data) => {
17
40
  const isError = data.status === 0 || data.status >= 400;
18
- tracker.track(isError ? _gctrack_protocol.EventType.ApiError : _gctrack_protocol.EventType.ApiPerformance, {
41
+ tracker.track(isError ? __gctrack_protocol.EventType.ApiError : __gctrack_protocol.EventType.ApiPerformance, {
19
42
  ...data,
20
43
  slow: data.duration >= slowThreshold
21
44
  });
@@ -86,7 +109,7 @@ function createNetworkMonitor(tracker, options = {}) {
86
109
  }
87
110
  };
88
111
  }
112
+
89
113
  //#endregion
90
114
  exports.createNetworkMonitor = createNetworkMonitor;
91
-
92
115
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["EventType"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @gctrack/network —— 接口监控\n *\n * 劫持 fetch 与 XMLHttpRequest,自动产出 api_performance / api_error 事件。\n * flyio 底层走 XHR,会被自动覆盖;启用本包后业务层 request 封装无需重复埋点。\n */\nimport type { Tracker } from '@gctrack/core'\nimport { EventType, type ApiEventData } from '@gctrack/protocol'\n\nexport interface NetworkMonitorOptions {\n /** 忽略的 URL(字符串包含匹配或正则);上报地址自身始终被忽略以防循环 */\n ignoreUrls?: Array<string | RegExp>\n /** 慢接口阈值(ms),超过仅用于 data.slow 标记,不影响事件类型 */\n slowThreshold?: number\n}\n\nexport interface NetworkMonitor {\n start: () => void\n destroy: () => void\n}\n\nconst ORIGINAL_FETCH = typeof fetch !== 'undefined' ? fetch.bind(globalThis) : undefined\nconst ORIGINAL_OPEN =\n typeof XMLHttpRequest !== 'undefined' ? XMLHttpRequest.prototype.open : undefined\nconst ORIGINAL_SEND =\n typeof XMLHttpRequest !== 'undefined' ? XMLHttpRequest.prototype.send : undefined\n\nexport function createNetworkMonitor(\n tracker: Tracker,\n options: NetworkMonitorOptions = {},\n): NetworkMonitor {\n const { ignoreUrls = [], slowThreshold = 3000 } = options\n let installed = false\n\n const isIgnored = (url: string): boolean => {\n // 注意:必须以 tracker 为调用者保留 this 绑定,不能把 getConfig 摘出来裸调用\n const trackerCfg =\n typeof (tracker as any).getConfig === 'function' ? tracker.getConfig() : undefined\n const reportUrl = trackerCfg && trackerCfg.reportUrl\n if (reportUrl && url.includes(reportUrl)) return true\n return ignoreUrls.some((p) =>\n typeof p === 'string' ? url.includes(p) : p.test(url),\n )\n }\n\n const report = (data: ApiEventData): void => {\n const isError = data.status === 0 || data.status >= 400\n tracker.track(isError ? EventType.ApiError : EventType.ApiPerformance, {\n ...data,\n slow: data.duration >= slowThreshold,\n })\n }\n\n const patchFetch = (): void => {\n if (typeof fetch === 'undefined' || !ORIGINAL_FETCH) return\n const patched = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url\n const method = ((init && init.method) || 'GET').toUpperCase()\n const start = Date.now()\n try {\n const res = await ORIGINAL_FETCH(input as RequestInfo, init)\n if (!isIgnored(url)) {\n report({ url, method, status: res.status, duration: Date.now() - start })\n }\n return res\n } catch (err) {\n if (!isIgnored(url)) {\n report({\n url,\n method,\n status: 0,\n duration: Date.now() - start,\n reason: ((err as Error) && (err as Error).message) || 'fetch_error',\n })\n }\n throw err\n }\n }\n ;(globalThis as any).fetch = patched\n }\n\n const patchXhr = (): void => {\n if (typeof XMLHttpRequest === 'undefined' || !ORIGINAL_OPEN || !ORIGINAL_SEND) return\n XMLHttpRequest.prototype.open = function (\n this: XMLHttpRequest & Record<string, any>,\n method: string,\n url: string,\n ) {\n this.__gctrack_method = (method || 'GET').toUpperCase()\n this.__gctrack_url = url\n return ORIGINAL_OPEN.apply(this, arguments as any)\n }\n XMLHttpRequest.prototype.send = function (\n this: XMLHttpRequest & Record<string, any>,\n ) {\n this.__gctrack_start = Date.now()\n this.addEventListener('loadend', () => {\n const url = this.__gctrack_url\n if (!url || isIgnored(url)) return\n report({\n url,\n method: this.__gctrack_method || 'GET',\n status: this.status,\n duration: Date.now() - (this.__gctrack_start || Date.now()),\n })\n })\n return ORIGINAL_SEND.apply(this, arguments as any)\n }\n }\n\n return {\n start() {\n if (installed) return\n installed = true\n patchFetch()\n patchXhr()\n },\n destroy() {\n if (!installed) return\n installed = false\n if (ORIGINAL_FETCH) (globalThis as any).fetch = ORIGINAL_FETCH\n if (ORIGINAL_OPEN) XMLHttpRequest.prototype.open = ORIGINAL_OPEN\n if (ORIGINAL_SEND) XMLHttpRequest.prototype.send = ORIGINAL_SEND\n },\n }\n}\n"],"mappings":";;;AAqBA,MAAM,iBAAiB,OAAO,UAAU,cAAc,MAAM,KAAK,WAAW,GAAG,KAAA;AAC/E,MAAM,gBACJ,OAAO,mBAAmB,cAAc,eAAe,UAAU,OAAO,KAAA;AAC1E,MAAM,gBACJ,OAAO,mBAAmB,cAAc,eAAe,UAAU,OAAO,KAAA;AAE1E,SAAgB,qBACd,SACA,UAAiC,EAAE,EACnB;CAChB,MAAM,EAAE,aAAa,EAAE,EAAE,gBAAgB,QAAS;CAClD,IAAI,YAAY;CAEhB,MAAM,aAAa,QAAyB;EAE1C,MAAM,aACJ,OAAQ,QAAgB,cAAc,aAAa,QAAQ,WAAW,GAAG,KAAA;EAC3E,MAAM,YAAY,cAAc,WAAW;EAC3C,IAAI,aAAa,IAAI,SAAS,UAAU,EAAE,OAAO;EACjD,OAAO,WAAW,MAAM,MACtB,OAAO,MAAM,WAAW,IAAI,SAAS,EAAE,GAAG,EAAE,KAAK,IAAI,CACtD;;CAGH,MAAM,UAAU,SAA6B;EAC3C,MAAM,UAAU,KAAK,WAAW,KAAK,KAAK,UAAU;EACpD,QAAQ,MAAM,UAAUA,kBAAAA,UAAU,WAAWA,kBAAAA,UAAU,gBAAgB;GACrE,GAAG;GACH,MAAM,KAAK,YAAY;GACxB,CAAC;;CAGJ,MAAM,mBAAyB;EAC7B,IAAI,OAAO,UAAU,eAAe,CAAC,gBAAgB;EACrD,MAAM,UAAU,OACd,OACA,SACsB;GACtB,MAAM,MACJ,OAAO,UAAU,WACb,QACA,iBAAiB,MACf,MAAM,OACN,MAAM;GACd,MAAM,UAAW,QAAQ,KAAK,UAAW,OAAO,aAAa;GAC7D,MAAM,QAAQ,KAAK,KAAK;GACxB,IAAI;IACF,MAAM,MAAM,MAAM,eAAe,OAAsB,KAAK;IAC5D,IAAI,CAAC,UAAU,IAAI,EACjB,OAAO;KAAE;KAAK;KAAQ,QAAQ,IAAI;KAAQ,UAAU,KAAK,KAAK,GAAG;KAAO,CAAC;IAE3E,OAAO;YACA,KAAK;IACZ,IAAI,CAAC,UAAU,IAAI,EACjB,OAAO;KACL;KACA;KACA,QAAQ;KACR,UAAU,KAAK,KAAK,GAAG;KACvB,QAAU,OAAkB,IAAc,WAAY;KACvD,CAAC;IAEJ,MAAM;;;EAGT,WAAoB,QAAQ;;CAG/B,MAAM,iBAAuB;EAC3B,IAAI,OAAO,mBAAmB,eAAe,CAAC,iBAAiB,CAAC,eAAe;EAC/E,eAAe,UAAU,OAAO,SAE9B,QACA,KACA;GACA,KAAK,oBAAoB,UAAU,OAAO,aAAa;GACvD,KAAK,gBAAgB;GACrB,OAAO,cAAc,MAAM,MAAM,UAAiB;;EAEpD,eAAe,UAAU,OAAO,WAE9B;GACA,KAAK,kBAAkB,KAAK,KAAK;GACjC,KAAK,iBAAiB,iBAAiB;IACrC,MAAM,MAAM,KAAK;IACjB,IAAI,CAAC,OAAO,UAAU,IAAI,EAAE;IAC5B,OAAO;KACL;KACA,QAAQ,KAAK,oBAAoB;KACjC,QAAQ,KAAK;KACb,UAAU,KAAK,KAAK,IAAI,KAAK,mBAAmB,KAAK,KAAK;KAC3D,CAAC;KACF;GACF,OAAO,cAAc,MAAM,MAAM,UAAiB;;;CAItD,OAAO;EACL,QAAQ;GACN,IAAI,WAAW;GACf,YAAY;GACZ,YAAY;GACZ,UAAU;;EAEZ,UAAU;GACR,IAAI,CAAC,WAAW;GAChB,YAAY;GACZ,IAAI,gBAAgB,WAAoB,QAAQ;GAChD,IAAI,eAAe,eAAe,UAAU,OAAO;GACnD,IAAI,eAAe,eAAe,UAAU,OAAO;;EAEtD"}
1
+ {"version":3,"file":"index.cjs","names":["tracker: Tracker","options: NetworkMonitorOptions","url: string","data: ApiEventData","EventType","input: RequestInfo | URL","init?: RequestInit","method: string"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @gctrack/network —— 接口监控\n *\n * 劫持 fetch 与 XMLHttpRequest,自动产出 api_performance / api_error 事件。\n * flyio 底层走 XHR,会被自动覆盖;启用本包后业务层 request 封装无需重复埋点。\n */\nimport type { Tracker } from '@gctrack/core'\nimport { EventType, type ApiEventData } from '@gctrack/protocol'\n\nexport interface NetworkMonitorOptions {\n /** 忽略的 URL(字符串包含匹配或正则);上报地址自身始终被忽略以防循环 */\n ignoreUrls?: Array<string | RegExp>\n /** 慢接口阈值(ms),超过仅用于 data.slow 标记,不影响事件类型 */\n slowThreshold?: number\n}\n\nexport interface NetworkMonitor {\n start: () => void\n destroy: () => void\n}\n\nconst ORIGINAL_FETCH = typeof fetch !== 'undefined' ? fetch.bind(globalThis) : undefined\nconst ORIGINAL_OPEN =\n typeof XMLHttpRequest !== 'undefined' ? XMLHttpRequest.prototype.open : undefined\nconst ORIGINAL_SEND =\n typeof XMLHttpRequest !== 'undefined' ? XMLHttpRequest.prototype.send : undefined\n\nexport function createNetworkMonitor(\n tracker: Tracker,\n options: NetworkMonitorOptions = {},\n): NetworkMonitor {\n const { ignoreUrls = [], slowThreshold = 3000 } = options\n let installed = false\n\n const isIgnored = (url: string): boolean => {\n // 注意:必须以 tracker 为调用者保留 this 绑定,不能把 getConfig 摘出来裸调用\n const trackerCfg =\n typeof (tracker as any).getConfig === 'function' ? tracker.getConfig() : undefined\n const reportUrl = trackerCfg && trackerCfg.reportUrl\n if (reportUrl && url.includes(reportUrl)) return true\n return ignoreUrls.some((p) =>\n typeof p === 'string' ? url.includes(p) : p.test(url),\n )\n }\n\n const report = (data: ApiEventData): void => {\n const isError = data.status === 0 || data.status >= 400\n tracker.track(isError ? EventType.ApiError : EventType.ApiPerformance, {\n ...data,\n slow: data.duration >= slowThreshold,\n })\n }\n\n const patchFetch = (): void => {\n if (typeof fetch === 'undefined' || !ORIGINAL_FETCH) return\n const patched = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url\n const method = ((init && init.method) || 'GET').toUpperCase()\n const start = Date.now()\n try {\n const res = await ORIGINAL_FETCH(input as RequestInfo, init)\n if (!isIgnored(url)) {\n report({ url, method, status: res.status, duration: Date.now() - start })\n }\n return res\n } catch (err) {\n if (!isIgnored(url)) {\n report({\n url,\n method,\n status: 0,\n duration: Date.now() - start,\n reason: ((err as Error) && (err as Error).message) || 'fetch_error',\n })\n }\n throw err\n }\n }\n ;(globalThis as any).fetch = patched\n }\n\n const patchXhr = (): void => {\n if (typeof XMLHttpRequest === 'undefined' || !ORIGINAL_OPEN || !ORIGINAL_SEND) return\n XMLHttpRequest.prototype.open = function (\n this: XMLHttpRequest & Record<string, any>,\n method: string,\n url: string,\n ) {\n this.__gctrack_method = (method || 'GET').toUpperCase()\n this.__gctrack_url = url\n return ORIGINAL_OPEN.apply(this, arguments as any)\n }\n XMLHttpRequest.prototype.send = function (\n this: XMLHttpRequest & Record<string, any>,\n ) {\n this.__gctrack_start = Date.now()\n this.addEventListener('loadend', () => {\n const url = this.__gctrack_url\n if (!url || isIgnored(url)) return\n report({\n url,\n method: this.__gctrack_method || 'GET',\n status: this.status,\n duration: Date.now() - (this.__gctrack_start || Date.now()),\n })\n })\n return ORIGINAL_SEND.apply(this, arguments as any)\n }\n }\n\n return {\n start() {\n if (installed) return\n installed = true\n patchFetch()\n patchXhr()\n },\n destroy() {\n if (!installed) return\n installed = false\n if (ORIGINAL_FETCH) (globalThis as any).fetch = ORIGINAL_FETCH\n if (ORIGINAL_OPEN) XMLHttpRequest.prototype.open = ORIGINAL_OPEN\n if (ORIGINAL_SEND) XMLHttpRequest.prototype.send = ORIGINAL_SEND\n },\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA,MAAM,wBAAwB,UAAU,cAAc,MAAM,KAAK,WAAW;AAC5E,MAAM,uBACG,mBAAmB,cAAc,eAAe,UAAU;AACnE,MAAM,uBACG,mBAAmB,cAAc,eAAe,UAAU;AAEnE,SAAgB,qBACdA,SACAC,UAAiC,CAAE,GACnB;CAChB,MAAM,EAAE,aAAa,CAAE,GAAE,gBAAgB,KAAM,GAAG;CAClD,IAAI,YAAY;CAEhB,MAAM,YAAY,CAACC,QAAyB;EAE1C,MAAM,oBACI,QAAgB,cAAc,aAAa,QAAQ,WAAW;EACxE,MAAM,YAAY,cAAc,WAAW;AAC3C,MAAI,aAAa,IAAI,SAAS,UAAU,CAAE,QAAO;AACjD,SAAO,WAAW,KAAK,CAAC,aACf,MAAM,WAAW,IAAI,SAAS,EAAE,GAAG,EAAE,KAAK,IAAI,CACtD;CACF;CAED,MAAM,SAAS,CAACC,SAA6B;EAC3C,MAAM,UAAU,KAAK,WAAW,KAAK,KAAK,UAAU;AACpD,UAAQ,MAAM,UAAUC,6BAAU,WAAWA,6BAAU,gBAAgB;GACrE,GAAG;GACH,MAAM,KAAK,YAAY;EACxB,EAAC;CACH;CAED,MAAM,aAAa,MAAY;AAC7B,aAAW,UAAU,gBAAgB,eAAgB;EACrD,MAAM,UAAU,OACdC,OACAC,SACsB;GACtB,MAAM,aACG,UAAU,WACb,QACA,iBAAiB,MACf,MAAM,OACN,MAAM;GACd,MAAM,SAAS,CAAE,QAAQ,KAAK,UAAW,OAAO,aAAa;GAC7D,MAAM,QAAQ,KAAK,KAAK;AACxB,OAAI;IACF,MAAM,MAAM,MAAM,eAAe,OAAsB,KAAK;AAC5D,SAAK,UAAU,IAAI,CACjB,QAAO;KAAE;KAAK;KAAQ,QAAQ,IAAI;KAAQ,UAAU,KAAK,KAAK,GAAG;IAAO,EAAC;AAE3E,WAAO;GACR,SAAQ,KAAK;AACZ,SAAK,UAAU,IAAI,CACjB,QAAO;KACL;KACA;KACA,QAAQ;KACR,UAAU,KAAK,KAAK,GAAG;KACvB,QAAU,OAAkB,IAAc,WAAY;IACvD,EAAC;AAEJ,UAAM;GACP;EACF;AACA,EAAC,WAAmB,QAAQ;CAC9B;CAED,MAAM,WAAW,MAAY;AAC3B,aAAW,mBAAmB,gBAAgB,kBAAkB,cAAe;AAC/E,iBAAe,UAAU,OAAO,SAE9BC,QACAL,KACA;AACA,QAAK,mBAAmB,CAAC,UAAU,OAAO,aAAa;AACvD,QAAK,gBAAgB;AACrB,UAAO,cAAc,MAAM,MAAM,UAAiB;EACnD;AACD,iBAAe,UAAU,OAAO,WAE9B;AACA,QAAK,kBAAkB,KAAK,KAAK;AACjC,QAAK,iBAAiB,WAAW,MAAM;IACrC,MAAM,MAAM,KAAK;AACjB,SAAK,OAAO,UAAU,IAAI,CAAE;AAC5B,WAAO;KACL;KACA,QAAQ,KAAK,oBAAoB;KACjC,QAAQ,KAAK;KACb,UAAU,KAAK,KAAK,IAAI,KAAK,mBAAmB,KAAK,KAAK;IAC3D,EAAC;GACH,EAAC;AACF,UAAO,cAAc,MAAM,MAAM,UAAiB;EACnD;CACF;AAED,QAAO;EACL,QAAQ;AACN,OAAI,UAAW;AACf,eAAY;AACZ,eAAY;AACZ,aAAU;EACX;EACD,UAAU;AACR,QAAK,UAAW;AAChB,eAAY;AACZ,OAAI,eAAgB,CAAC,WAAmB,QAAQ;AAChD,OAAI,cAAe,gBAAe,UAAU,OAAO;AACnD,OAAI,cAAe,gBAAe,UAAU,OAAO;EACpD;CACF;AACF"}
package/dist/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { EventType } from "@gctrack/protocol";
2
+
2
3
  //#region src/index.ts
3
4
  const ORIGINAL_FETCH = typeof fetch !== "undefined" ? fetch.bind(globalThis) : void 0;
4
5
  const ORIGINAL_OPEN = typeof XMLHttpRequest !== "undefined" ? XMLHttpRequest.prototype.open : void 0;
@@ -85,7 +86,7 @@ function createNetworkMonitor(tracker, options = {}) {
85
86
  }
86
87
  };
87
88
  }
89
+
88
90
  //#endregion
89
91
  export { createNetworkMonitor };
90
-
91
92
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @gctrack/network —— 接口监控\n *\n * 劫持 fetch 与 XMLHttpRequest,自动产出 api_performance / api_error 事件。\n * flyio 底层走 XHR,会被自动覆盖;启用本包后业务层 request 封装无需重复埋点。\n */\nimport type { Tracker } from '@gctrack/core'\nimport { EventType, type ApiEventData } from '@gctrack/protocol'\n\nexport interface NetworkMonitorOptions {\n /** 忽略的 URL(字符串包含匹配或正则);上报地址自身始终被忽略以防循环 */\n ignoreUrls?: Array<string | RegExp>\n /** 慢接口阈值(ms),超过仅用于 data.slow 标记,不影响事件类型 */\n slowThreshold?: number\n}\n\nexport interface NetworkMonitor {\n start: () => void\n destroy: () => void\n}\n\nconst ORIGINAL_FETCH = typeof fetch !== 'undefined' ? fetch.bind(globalThis) : undefined\nconst ORIGINAL_OPEN =\n typeof XMLHttpRequest !== 'undefined' ? XMLHttpRequest.prototype.open : undefined\nconst ORIGINAL_SEND =\n typeof XMLHttpRequest !== 'undefined' ? XMLHttpRequest.prototype.send : undefined\n\nexport function createNetworkMonitor(\n tracker: Tracker,\n options: NetworkMonitorOptions = {},\n): NetworkMonitor {\n const { ignoreUrls = [], slowThreshold = 3000 } = options\n let installed = false\n\n const isIgnored = (url: string): boolean => {\n // 注意:必须以 tracker 为调用者保留 this 绑定,不能把 getConfig 摘出来裸调用\n const trackerCfg =\n typeof (tracker as any).getConfig === 'function' ? tracker.getConfig() : undefined\n const reportUrl = trackerCfg && trackerCfg.reportUrl\n if (reportUrl && url.includes(reportUrl)) return true\n return ignoreUrls.some((p) =>\n typeof p === 'string' ? url.includes(p) : p.test(url),\n )\n }\n\n const report = (data: ApiEventData): void => {\n const isError = data.status === 0 || data.status >= 400\n tracker.track(isError ? EventType.ApiError : EventType.ApiPerformance, {\n ...data,\n slow: data.duration >= slowThreshold,\n })\n }\n\n const patchFetch = (): void => {\n if (typeof fetch === 'undefined' || !ORIGINAL_FETCH) return\n const patched = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url\n const method = ((init && init.method) || 'GET').toUpperCase()\n const start = Date.now()\n try {\n const res = await ORIGINAL_FETCH(input as RequestInfo, init)\n if (!isIgnored(url)) {\n report({ url, method, status: res.status, duration: Date.now() - start })\n }\n return res\n } catch (err) {\n if (!isIgnored(url)) {\n report({\n url,\n method,\n status: 0,\n duration: Date.now() - start,\n reason: ((err as Error) && (err as Error).message) || 'fetch_error',\n })\n }\n throw err\n }\n }\n ;(globalThis as any).fetch = patched\n }\n\n const patchXhr = (): void => {\n if (typeof XMLHttpRequest === 'undefined' || !ORIGINAL_OPEN || !ORIGINAL_SEND) return\n XMLHttpRequest.prototype.open = function (\n this: XMLHttpRequest & Record<string, any>,\n method: string,\n url: string,\n ) {\n this.__gctrack_method = (method || 'GET').toUpperCase()\n this.__gctrack_url = url\n return ORIGINAL_OPEN.apply(this, arguments as any)\n }\n XMLHttpRequest.prototype.send = function (\n this: XMLHttpRequest & Record<string, any>,\n ) {\n this.__gctrack_start = Date.now()\n this.addEventListener('loadend', () => {\n const url = this.__gctrack_url\n if (!url || isIgnored(url)) return\n report({\n url,\n method: this.__gctrack_method || 'GET',\n status: this.status,\n duration: Date.now() - (this.__gctrack_start || Date.now()),\n })\n })\n return ORIGINAL_SEND.apply(this, arguments as any)\n }\n }\n\n return {\n start() {\n if (installed) return\n installed = true\n patchFetch()\n patchXhr()\n },\n destroy() {\n if (!installed) return\n installed = false\n if (ORIGINAL_FETCH) (globalThis as any).fetch = ORIGINAL_FETCH\n if (ORIGINAL_OPEN) XMLHttpRequest.prototype.open = ORIGINAL_OPEN\n if (ORIGINAL_SEND) XMLHttpRequest.prototype.send = ORIGINAL_SEND\n },\n }\n}\n"],"mappings":";;AAqBA,MAAM,iBAAiB,OAAO,UAAU,cAAc,MAAM,KAAK,WAAW,GAAG,KAAA;AAC/E,MAAM,gBACJ,OAAO,mBAAmB,cAAc,eAAe,UAAU,OAAO,KAAA;AAC1E,MAAM,gBACJ,OAAO,mBAAmB,cAAc,eAAe,UAAU,OAAO,KAAA;AAE1E,SAAgB,qBACd,SACA,UAAiC,EAAE,EACnB;CAChB,MAAM,EAAE,aAAa,EAAE,EAAE,gBAAgB,QAAS;CAClD,IAAI,YAAY;CAEhB,MAAM,aAAa,QAAyB;EAE1C,MAAM,aACJ,OAAQ,QAAgB,cAAc,aAAa,QAAQ,WAAW,GAAG,KAAA;EAC3E,MAAM,YAAY,cAAc,WAAW;EAC3C,IAAI,aAAa,IAAI,SAAS,UAAU,EAAE,OAAO;EACjD,OAAO,WAAW,MAAM,MACtB,OAAO,MAAM,WAAW,IAAI,SAAS,EAAE,GAAG,EAAE,KAAK,IAAI,CACtD;;CAGH,MAAM,UAAU,SAA6B;EAC3C,MAAM,UAAU,KAAK,WAAW,KAAK,KAAK,UAAU;EACpD,QAAQ,MAAM,UAAU,UAAU,WAAW,UAAU,gBAAgB;GACrE,GAAG;GACH,MAAM,KAAK,YAAY;GACxB,CAAC;;CAGJ,MAAM,mBAAyB;EAC7B,IAAI,OAAO,UAAU,eAAe,CAAC,gBAAgB;EACrD,MAAM,UAAU,OACd,OACA,SACsB;GACtB,MAAM,MACJ,OAAO,UAAU,WACb,QACA,iBAAiB,MACf,MAAM,OACN,MAAM;GACd,MAAM,UAAW,QAAQ,KAAK,UAAW,OAAO,aAAa;GAC7D,MAAM,QAAQ,KAAK,KAAK;GACxB,IAAI;IACF,MAAM,MAAM,MAAM,eAAe,OAAsB,KAAK;IAC5D,IAAI,CAAC,UAAU,IAAI,EACjB,OAAO;KAAE;KAAK;KAAQ,QAAQ,IAAI;KAAQ,UAAU,KAAK,KAAK,GAAG;KAAO,CAAC;IAE3E,OAAO;YACA,KAAK;IACZ,IAAI,CAAC,UAAU,IAAI,EACjB,OAAO;KACL;KACA;KACA,QAAQ;KACR,UAAU,KAAK,KAAK,GAAG;KACvB,QAAU,OAAkB,IAAc,WAAY;KACvD,CAAC;IAEJ,MAAM;;;EAGT,WAAoB,QAAQ;;CAG/B,MAAM,iBAAuB;EAC3B,IAAI,OAAO,mBAAmB,eAAe,CAAC,iBAAiB,CAAC,eAAe;EAC/E,eAAe,UAAU,OAAO,SAE9B,QACA,KACA;GACA,KAAK,oBAAoB,UAAU,OAAO,aAAa;GACvD,KAAK,gBAAgB;GACrB,OAAO,cAAc,MAAM,MAAM,UAAiB;;EAEpD,eAAe,UAAU,OAAO,WAE9B;GACA,KAAK,kBAAkB,KAAK,KAAK;GACjC,KAAK,iBAAiB,iBAAiB;IACrC,MAAM,MAAM,KAAK;IACjB,IAAI,CAAC,OAAO,UAAU,IAAI,EAAE;IAC5B,OAAO;KACL;KACA,QAAQ,KAAK,oBAAoB;KACjC,QAAQ,KAAK;KACb,UAAU,KAAK,KAAK,IAAI,KAAK,mBAAmB,KAAK,KAAK;KAC3D,CAAC;KACF;GACF,OAAO,cAAc,MAAM,MAAM,UAAiB;;;CAItD,OAAO;EACL,QAAQ;GACN,IAAI,WAAW;GACf,YAAY;GACZ,YAAY;GACZ,UAAU;;EAEZ,UAAU;GACR,IAAI,CAAC,WAAW;GAChB,YAAY;GACZ,IAAI,gBAAgB,WAAoB,QAAQ;GAChD,IAAI,eAAe,eAAe,UAAU,OAAO;GACnD,IAAI,eAAe,eAAe,UAAU,OAAO;;EAEtD"}
1
+ {"version":3,"file":"index.js","names":["tracker: Tracker","options: NetworkMonitorOptions","url: string","data: ApiEventData","input: RequestInfo | URL","init?: RequestInit","method: string"],"sources":["../src/index.ts"],"sourcesContent":["/**\n * @gctrack/network —— 接口监控\n *\n * 劫持 fetch 与 XMLHttpRequest,自动产出 api_performance / api_error 事件。\n * flyio 底层走 XHR,会被自动覆盖;启用本包后业务层 request 封装无需重复埋点。\n */\nimport type { Tracker } from '@gctrack/core'\nimport { EventType, type ApiEventData } from '@gctrack/protocol'\n\nexport interface NetworkMonitorOptions {\n /** 忽略的 URL(字符串包含匹配或正则);上报地址自身始终被忽略以防循环 */\n ignoreUrls?: Array<string | RegExp>\n /** 慢接口阈值(ms),超过仅用于 data.slow 标记,不影响事件类型 */\n slowThreshold?: number\n}\n\nexport interface NetworkMonitor {\n start: () => void\n destroy: () => void\n}\n\nconst ORIGINAL_FETCH = typeof fetch !== 'undefined' ? fetch.bind(globalThis) : undefined\nconst ORIGINAL_OPEN =\n typeof XMLHttpRequest !== 'undefined' ? XMLHttpRequest.prototype.open : undefined\nconst ORIGINAL_SEND =\n typeof XMLHttpRequest !== 'undefined' ? XMLHttpRequest.prototype.send : undefined\n\nexport function createNetworkMonitor(\n tracker: Tracker,\n options: NetworkMonitorOptions = {},\n): NetworkMonitor {\n const { ignoreUrls = [], slowThreshold = 3000 } = options\n let installed = false\n\n const isIgnored = (url: string): boolean => {\n // 注意:必须以 tracker 为调用者保留 this 绑定,不能把 getConfig 摘出来裸调用\n const trackerCfg =\n typeof (tracker as any).getConfig === 'function' ? tracker.getConfig() : undefined\n const reportUrl = trackerCfg && trackerCfg.reportUrl\n if (reportUrl && url.includes(reportUrl)) return true\n return ignoreUrls.some((p) =>\n typeof p === 'string' ? url.includes(p) : p.test(url),\n )\n }\n\n const report = (data: ApiEventData): void => {\n const isError = data.status === 0 || data.status >= 400\n tracker.track(isError ? EventType.ApiError : EventType.ApiPerformance, {\n ...data,\n slow: data.duration >= slowThreshold,\n })\n }\n\n const patchFetch = (): void => {\n if (typeof fetch === 'undefined' || !ORIGINAL_FETCH) return\n const patched = async (\n input: RequestInfo | URL,\n init?: RequestInit,\n ): Promise<Response> => {\n const url =\n typeof input === 'string'\n ? input\n : input instanceof URL\n ? input.href\n : input.url\n const method = ((init && init.method) || 'GET').toUpperCase()\n const start = Date.now()\n try {\n const res = await ORIGINAL_FETCH(input as RequestInfo, init)\n if (!isIgnored(url)) {\n report({ url, method, status: res.status, duration: Date.now() - start })\n }\n return res\n } catch (err) {\n if (!isIgnored(url)) {\n report({\n url,\n method,\n status: 0,\n duration: Date.now() - start,\n reason: ((err as Error) && (err as Error).message) || 'fetch_error',\n })\n }\n throw err\n }\n }\n ;(globalThis as any).fetch = patched\n }\n\n const patchXhr = (): void => {\n if (typeof XMLHttpRequest === 'undefined' || !ORIGINAL_OPEN || !ORIGINAL_SEND) return\n XMLHttpRequest.prototype.open = function (\n this: XMLHttpRequest & Record<string, any>,\n method: string,\n url: string,\n ) {\n this.__gctrack_method = (method || 'GET').toUpperCase()\n this.__gctrack_url = url\n return ORIGINAL_OPEN.apply(this, arguments as any)\n }\n XMLHttpRequest.prototype.send = function (\n this: XMLHttpRequest & Record<string, any>,\n ) {\n this.__gctrack_start = Date.now()\n this.addEventListener('loadend', () => {\n const url = this.__gctrack_url\n if (!url || isIgnored(url)) return\n report({\n url,\n method: this.__gctrack_method || 'GET',\n status: this.status,\n duration: Date.now() - (this.__gctrack_start || Date.now()),\n })\n })\n return ORIGINAL_SEND.apply(this, arguments as any)\n }\n }\n\n return {\n start() {\n if (installed) return\n installed = true\n patchFetch()\n patchXhr()\n },\n destroy() {\n if (!installed) return\n installed = false\n if (ORIGINAL_FETCH) (globalThis as any).fetch = ORIGINAL_FETCH\n if (ORIGINAL_OPEN) XMLHttpRequest.prototype.open = ORIGINAL_OPEN\n if (ORIGINAL_SEND) XMLHttpRequest.prototype.send = ORIGINAL_SEND\n },\n }\n}\n"],"mappings":";;;AAqBA,MAAM,wBAAwB,UAAU,cAAc,MAAM,KAAK,WAAW;AAC5E,MAAM,uBACG,mBAAmB,cAAc,eAAe,UAAU;AACnE,MAAM,uBACG,mBAAmB,cAAc,eAAe,UAAU;AAEnE,SAAgB,qBACdA,SACAC,UAAiC,CAAE,GACnB;CAChB,MAAM,EAAE,aAAa,CAAE,GAAE,gBAAgB,KAAM,GAAG;CAClD,IAAI,YAAY;CAEhB,MAAM,YAAY,CAACC,QAAyB;EAE1C,MAAM,oBACI,QAAgB,cAAc,aAAa,QAAQ,WAAW;EACxE,MAAM,YAAY,cAAc,WAAW;AAC3C,MAAI,aAAa,IAAI,SAAS,UAAU,CAAE,QAAO;AACjD,SAAO,WAAW,KAAK,CAAC,aACf,MAAM,WAAW,IAAI,SAAS,EAAE,GAAG,EAAE,KAAK,IAAI,CACtD;CACF;CAED,MAAM,SAAS,CAACC,SAA6B;EAC3C,MAAM,UAAU,KAAK,WAAW,KAAK,KAAK,UAAU;AACpD,UAAQ,MAAM,UAAU,UAAU,WAAW,UAAU,gBAAgB;GACrE,GAAG;GACH,MAAM,KAAK,YAAY;EACxB,EAAC;CACH;CAED,MAAM,aAAa,MAAY;AAC7B,aAAW,UAAU,gBAAgB,eAAgB;EACrD,MAAM,UAAU,OACdC,OACAC,SACsB;GACtB,MAAM,aACG,UAAU,WACb,QACA,iBAAiB,MACf,MAAM,OACN,MAAM;GACd,MAAM,SAAS,CAAE,QAAQ,KAAK,UAAW,OAAO,aAAa;GAC7D,MAAM,QAAQ,KAAK,KAAK;AACxB,OAAI;IACF,MAAM,MAAM,MAAM,eAAe,OAAsB,KAAK;AAC5D,SAAK,UAAU,IAAI,CACjB,QAAO;KAAE;KAAK;KAAQ,QAAQ,IAAI;KAAQ,UAAU,KAAK,KAAK,GAAG;IAAO,EAAC;AAE3E,WAAO;GACR,SAAQ,KAAK;AACZ,SAAK,UAAU,IAAI,CACjB,QAAO;KACL;KACA;KACA,QAAQ;KACR,UAAU,KAAK,KAAK,GAAG;KACvB,QAAU,OAAkB,IAAc,WAAY;IACvD,EAAC;AAEJ,UAAM;GACP;EACF;AACA,EAAC,WAAmB,QAAQ;CAC9B;CAED,MAAM,WAAW,MAAY;AAC3B,aAAW,mBAAmB,gBAAgB,kBAAkB,cAAe;AAC/E,iBAAe,UAAU,OAAO,SAE9BC,QACAJ,KACA;AACA,QAAK,mBAAmB,CAAC,UAAU,OAAO,aAAa;AACvD,QAAK,gBAAgB;AACrB,UAAO,cAAc,MAAM,MAAM,UAAiB;EACnD;AACD,iBAAe,UAAU,OAAO,WAE9B;AACA,QAAK,kBAAkB,KAAK,KAAK;AACjC,QAAK,iBAAiB,WAAW,MAAM;IACrC,MAAM,MAAM,KAAK;AACjB,SAAK,OAAO,UAAU,IAAI,CAAE;AAC5B,WAAO;KACL;KACA,QAAQ,KAAK,oBAAoB;KACjC,QAAQ,KAAK;KACb,UAAU,KAAK,KAAK,IAAI,KAAK,mBAAmB,KAAK,KAAK;IAC3D,EAAC;GACH,EAAC;AACF,UAAO,cAAc,MAAM,MAAM,UAAiB;EACnD;CACF;AAED,QAAO;EACL,QAAQ;AACN,OAAI,UAAW;AACf,eAAY;AACZ,eAAY;AACZ,aAAU;EACX;EACD,UAAU;AACR,QAAK,UAAW;AAChB,eAAY;AACZ,OAAI,eAAgB,CAAC,WAAmB,QAAQ;AAChD,OAAI,cAAe,gBAAe,UAAU,OAAO;AACnD,OAAI,cAAe,gBAAe,UAAU,OAAO;EACpD;CACF;AACF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gctrack/network",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "GCTrack 接口监控 —— fetch / XMLHttpRequest 劫持,产出 api_performance / api_error",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -29,10 +29,10 @@
29
29
  "access": "public"
30
30
  },
31
31
  "dependencies": {
32
- "@gctrack/protocol": "0.1.2"
32
+ "@gctrack/protocol": "0.2.0"
33
33
  },
34
34
  "peerDependencies": {
35
- "@gctrack/core": "0.1.2"
35
+ "@gctrack/core": "0.2.0"
36
36
  },
37
37
  "scripts": {
38
38
  "build": "tsdown",