import type { ErrorReporter } from '../ErrorReporter'; import { Transport, TransportOptions, ReportItemWithContext } from '@tencent/merlin-core'; import { mapHrefToPath, mapHrefToPathWithMultiSearchKey, mapHrefToPathWithOneSearchKey } from './utils'; import type { ErrorReportItemData } from '../types'; export interface AvalonErrorTransportOptions extends TransportOptions { /** Node 接口,`fetch` 的 `url` */ url: string; /** 原始 href 到 page_uri 字段的映射,用于区分页面 * @default 去除 search 和 hash * @example https://qq.com/?a=1#haha/a => https://qq.com/ * - `(href: string) => string` 自定义映射函数 * - `string` 在缺省映射基础上,保留指定 search 字段 * - `string[]` 在缺省映射基础上,按顺序保留指定 search 字段 */ uriMapper?: ((href?: string) => string) | string | string[]; } /** 兼容对应老版上报协议的 avalon 接口错误上报 */ export class AvalonErrorTransport extends Transport { protected url = ''; protected uriMapper = mapHrefToPath; constructor(options: AvalonErrorTransportOptions) { super({ // 接口不支持批量上报,立刻上报即可 bufferSize: 0, flushInterval: 0, frequencyLimit: { max: 25, perSeconds: 900, }, ...options, }); const { url, uriMapper } = options; this.url = url; if (typeof uriMapper === 'string') { this.uriMapper = (href?: string) => mapHrefToPathWithOneSearchKey(href, uriMapper); } else if (Array.isArray(uriMapper)) { this.uriMapper = (href?: string) => mapHrefToPathWithMultiSearchKey(href, uriMapper); } else if (typeof uriMapper === 'function') { this.uriMapper = uriMapper; } } send(records: ReportItemWithContext[]) { const requestsToSend = records.map((record) => { let { stack } = record.data; const { appId, liteAppVersion } = record.context.env; if (liteAppVersion && appId) { stack = `appId:${appId},lite:${liteAppVersion}\n${stack}`; } else if (liteAppVersion) { stack = `lite:${liteAppVersion}\n${stack}`; } else if (appId) { stack = `appId:${appId}\n${stack}`; } return { stack, error_msg: record.data.message, error_type: record.data.name, page_uri: this.uriMapper(record.context.scope.href), }; }); this.reporter?.log('AvalonErrorTransport.send', requestsToSend); requestsToSend.forEach((req) => { this.reporter?.httpPost(this.url, JSON.stringify(req), { contentType: 'application/json', }); }); } }