web-tracing-core 2.1.0 → 2.1.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/README.md → README.md} +8 -0
- package/{dist/index.cjs → index.cjs} +24 -5
- package/{dist/index.iife.js → index.iife.js} +24 -5
- package/{dist/index.iife.min.js → index.iife.min.js} +9 -9
- package/{dist/index.mjs → index.mjs} +24 -5
- package/package.json +9 -9
- package/__test__/css/performance.css +0 -3
- package/__test__/err-batch.spec.ts +0 -47
- package/__test__/err.spec.ts +0 -82
- package/__test__/event.spec.ts +0 -62
- package/__test__/html/performance.html +0 -57
- package/__test__/html/recordscreen.html +0 -39
- package/__test__/http.spec.ts +0 -143
- package/__test__/img/performance.png +0 -0
- package/__test__/js/performance.js +0 -3
- package/__test__/performance.spec.ts +0 -112
- package/__test__/recordscreen.spec.ts +0 -50
- package/__test__/utils/index.ts +0 -99
- package/__test__/utils/pollify.ts +0 -14
- package/__test__/utils.spec.ts +0 -18
- package/dist/package.json +0 -49
- package/index.ts +0 -75
- package/src/common/config.ts +0 -13
- package/src/common/constant.ts +0 -57
- package/src/common/index.ts +0 -2
- package/src/lib/base.ts +0 -129
- package/src/lib/err-batch.ts +0 -134
- package/src/lib/err.ts +0 -323
- package/src/lib/event-dwell.ts +0 -63
- package/src/lib/event.ts +0 -252
- package/src/lib/eventBus.ts +0 -97
- package/src/lib/exportMethods.ts +0 -208
- package/src/lib/http.ts +0 -197
- package/src/lib/intersectionObserver.ts +0 -164
- package/src/lib/line-status.ts +0 -45
- package/src/lib/options.ts +0 -325
- package/src/lib/performance.ts +0 -302
- package/src/lib/pv.ts +0 -199
- package/src/lib/recordscreen.ts +0 -169
- package/src/lib/replace.ts +0 -371
- package/src/lib/sendData.ts +0 -264
- package/src/observer/computed.ts +0 -52
- package/src/observer/config.ts +0 -1
- package/src/observer/dep.ts +0 -21
- package/src/observer/index.ts +0 -91
- package/src/observer/ref.ts +0 -80
- package/src/observer/types.ts +0 -22
- package/src/observer/watch.ts +0 -19
- package/src/observer/watcher.ts +0 -88
- package/src/types/index.ts +0 -126
- package/src/utils/debug.ts +0 -17
- package/src/utils/element.ts +0 -47
- package/src/utils/fingerprintjs.ts +0 -2132
- package/src/utils/getIps.ts +0 -127
- package/src/utils/global.ts +0 -49
- package/src/utils/index.ts +0 -551
- package/src/utils/is.ts +0 -78
- package/src/utils/localStorage.ts +0 -70
- package/src/utils/session.ts +0 -27
- /package/{dist/LICENSE → LICENSE} +0 -0
- /package/{dist/index.d.ts → index.d.ts} +0 -0
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import fs from 'fs'
|
|
2
|
-
import path from 'path'
|
|
3
|
-
import http from 'http'
|
|
4
|
-
|
|
5
|
-
import { getServerURL, startServer, launchPuppeteer, getHtml } from './utils'
|
|
6
|
-
import { Browser, Page } from 'puppeteer'
|
|
7
|
-
|
|
8
|
-
describe('err', () => {
|
|
9
|
-
vi.setConfig({ testTimeout: 30_000, hookTimeout: 30_000 })
|
|
10
|
-
|
|
11
|
-
let code: string
|
|
12
|
-
let serverURL: string
|
|
13
|
-
let server: http.Server
|
|
14
|
-
let browser: Browser
|
|
15
|
-
|
|
16
|
-
beforeAll(async () => {
|
|
17
|
-
server = await startServer(3031)
|
|
18
|
-
serverURL = getServerURL(server)
|
|
19
|
-
browser = await launchPuppeteer()
|
|
20
|
-
|
|
21
|
-
const bundlePath = path.resolve(__dirname, '../dist/index.iife.js')
|
|
22
|
-
code = fs.readFileSync(bundlePath, 'utf8')
|
|
23
|
-
})
|
|
24
|
-
|
|
25
|
-
afterAll(async () => {
|
|
26
|
-
browser && (await browser.close())
|
|
27
|
-
server && server.close()
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
async function loadTestPage() {
|
|
31
|
-
const page: Page = await browser.newPage()
|
|
32
|
-
const htmlName = 'recordscreen.html'
|
|
33
|
-
await page.goto(`${serverURL}/${htmlName}`)
|
|
34
|
-
const html = getHtml(`${htmlName}`, code)
|
|
35
|
-
await page.setContent(html)
|
|
36
|
-
await page.waitForFunction(() => {
|
|
37
|
-
return document.readyState === 'complete'
|
|
38
|
-
})
|
|
39
|
-
return page
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
it('error recordscreen should be captured correctly', async () => {
|
|
43
|
-
const page = await loadTestPage()
|
|
44
|
-
await page.click('.code-error-button')
|
|
45
|
-
const webTracingData = await page.evaluate(`window.__WebTracingData__`)
|
|
46
|
-
expect(
|
|
47
|
-
(webTracingData as any).eventInfo[0].recordscreen
|
|
48
|
-
).not.toBeUndefined()
|
|
49
|
-
})
|
|
50
|
-
})
|
package/__test__/utils/index.ts
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import path from 'path'
|
|
2
|
-
import http from 'http'
|
|
3
|
-
import url from 'url'
|
|
4
|
-
import fs from 'fs'
|
|
5
|
-
import puppeteer from 'puppeteer'
|
|
6
|
-
|
|
7
|
-
interface IMimeType {
|
|
8
|
-
[key: string]: string
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
export function startServer(defaultPort = 3030) {
|
|
12
|
-
return new Promise<http.Server>((resolve, reject) => {
|
|
13
|
-
const mimeType: IMimeType = {
|
|
14
|
-
'.html': 'text/html',
|
|
15
|
-
'.js': 'text/javascript',
|
|
16
|
-
'.css': 'text/css',
|
|
17
|
-
'.png': 'image/png'
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const s = http.createServer((req, res) => {
|
|
21
|
-
const parsedUrl = url.parse(req.url!)
|
|
22
|
-
const sanitizePath = path
|
|
23
|
-
.normalize(parsedUrl.pathname!)
|
|
24
|
-
.replace(/^(\.\.[/\\])+/, '')
|
|
25
|
-
const pathname = path.join(__dirname, '../', sanitizePath)
|
|
26
|
-
|
|
27
|
-
try {
|
|
28
|
-
const data = fs.readFileSync(pathname)
|
|
29
|
-
const ext = path.parse(pathname).ext
|
|
30
|
-
res.setHeader('Content-type', mimeType[ext] || 'text/plain')
|
|
31
|
-
res.setHeader('Access-Control-Allow-Origin', '*')
|
|
32
|
-
res.setHeader('Access-Control-Allow-Methods', 'GET')
|
|
33
|
-
res.setHeader('Access-Control-Allow-Headers', 'Content-type')
|
|
34
|
-
setTimeout(() => {
|
|
35
|
-
res.end(data)
|
|
36
|
-
}, 100)
|
|
37
|
-
} catch (error) {
|
|
38
|
-
res.end()
|
|
39
|
-
}
|
|
40
|
-
})
|
|
41
|
-
s.listen(defaultPort)
|
|
42
|
-
.on('listening', () => {
|
|
43
|
-
resolve(s)
|
|
44
|
-
})
|
|
45
|
-
.on('error', e => {
|
|
46
|
-
reject(e)
|
|
47
|
-
})
|
|
48
|
-
})
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function getServerURL(server: http.Server): string {
|
|
52
|
-
const address = server.address()
|
|
53
|
-
if (address && typeof address !== 'string') {
|
|
54
|
-
return `http://localhost:${address.port}`
|
|
55
|
-
} else {
|
|
56
|
-
return `${address}`
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
export function replaceLast(str: string, find: string, replace: string) {
|
|
61
|
-
const index = str.lastIndexOf(find)
|
|
62
|
-
if (index === -1) {
|
|
63
|
-
return str
|
|
64
|
-
}
|
|
65
|
-
return str.substring(0, index) + replace + str.substring(index + find.length)
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
export async function launchPuppeteer(
|
|
69
|
-
options?: Parameters<(typeof puppeteer)['launch']>[0]
|
|
70
|
-
) {
|
|
71
|
-
return await puppeteer.launch({
|
|
72
|
-
headless: true,
|
|
73
|
-
defaultViewport: {
|
|
74
|
-
width: 1920,
|
|
75
|
-
height: 1080
|
|
76
|
-
},
|
|
77
|
-
args: ['--no-sandbox'],
|
|
78
|
-
...options
|
|
79
|
-
})
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export function getHtml(fileName: string, code: string) {
|
|
83
|
-
const filePath = path.resolve(__dirname, `../html/${fileName}`)
|
|
84
|
-
const html = fs.readFileSync(filePath, 'utf8')
|
|
85
|
-
return replaceLast(
|
|
86
|
-
html,
|
|
87
|
-
'</body>',
|
|
88
|
-
`
|
|
89
|
-
<script>
|
|
90
|
-
${code}
|
|
91
|
-
</script>
|
|
92
|
-
</body>
|
|
93
|
-
`
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
export function delay(timeout: number) {
|
|
98
|
-
return new Promise(resolve => setTimeout(resolve, timeout))
|
|
99
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
export type PromiseRejectionEventInit = {
|
|
2
|
-
promise: Promise<any>
|
|
3
|
-
reason: any
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
export class PromiseRejectionEvent extends Event {
|
|
7
|
-
public readonly reason: any
|
|
8
|
-
public readonly promise: Promise<any>
|
|
9
|
-
constructor(type: string, eventInitDict: PromiseRejectionEventInit) {
|
|
10
|
-
super(type)
|
|
11
|
-
this.promise = eventInitDict.promise
|
|
12
|
-
this.reason = eventInitDict.reason
|
|
13
|
-
}
|
|
14
|
-
}
|
package/__test__/utils.spec.ts
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { getNodeXPath } from '../src/utils/element'
|
|
2
|
-
|
|
3
|
-
describe('utils', () => {
|
|
4
|
-
it('getNodeXPath should work', () => {
|
|
5
|
-
const element = document.createElement('div')
|
|
6
|
-
element.innerHTML = `
|
|
7
|
-
<div id="wrapper">
|
|
8
|
-
<div></div>
|
|
9
|
-
<div></div>
|
|
10
|
-
<div>
|
|
11
|
-
<div class="target"></div>
|
|
12
|
-
</div>
|
|
13
|
-
</div>
|
|
14
|
-
`
|
|
15
|
-
const target = element.querySelector('.target')!
|
|
16
|
-
expect(getNodeXPath(target)).toBe('#wrapper>div>div')
|
|
17
|
-
})
|
|
18
|
-
})
|
package/dist/package.json
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "web-tracing-core",
|
|
3
|
-
"version": "2.1.0",
|
|
4
|
-
"description": "基于 JS 跨平台插件,为前端项目提供【 埋点、行为、性能、异常、请求、资源、路由、曝光、录屏 】监控手段",
|
|
5
|
-
"main": "./index.cjs",
|
|
6
|
-
"module": "./index.mjs",
|
|
7
|
-
"jsdelivr": "./index.iife.min.js",
|
|
8
|
-
"types": "./index.d.ts",
|
|
9
|
-
"sideEffects": false,
|
|
10
|
-
"exports": {
|
|
11
|
-
".": {
|
|
12
|
-
"import": "./index.mjs",
|
|
13
|
-
"require": "./index.cjs",
|
|
14
|
-
"types": "./index.d.ts"
|
|
15
|
-
},
|
|
16
|
-
"./*": "./*"
|
|
17
|
-
},
|
|
18
|
-
"license": "MIT",
|
|
19
|
-
"repository": {
|
|
20
|
-
"type": "git",
|
|
21
|
-
"url": "git+https://github.com/M-cheng-web/web-tracing.git",
|
|
22
|
-
"directory": "packages/core"
|
|
23
|
-
},
|
|
24
|
-
"author": "M-cheng-web <https://github.com/M-cheng-web>",
|
|
25
|
-
"keywords": [
|
|
26
|
-
"埋点",
|
|
27
|
-
"性能",
|
|
28
|
-
"异常",
|
|
29
|
-
"性能采集",
|
|
30
|
-
"异常采集",
|
|
31
|
-
"前端埋点",
|
|
32
|
-
"前端性能采集"
|
|
33
|
-
],
|
|
34
|
-
"dependencies": {
|
|
35
|
-
"ua-parser-js": "2.0.0-alpha.1",
|
|
36
|
-
"@types/pako": "^2.0.0",
|
|
37
|
-
"pako": "^2.1.0",
|
|
38
|
-
"js-base64": "^3.7.5",
|
|
39
|
-
"rrweb": "2.0.0-alpha.5"
|
|
40
|
-
},
|
|
41
|
-
"devDependencies": {
|
|
42
|
-
"@types/ua-parser-js": "^0.7.36"
|
|
43
|
-
},
|
|
44
|
-
"bugs": {
|
|
45
|
-
"url": "https://github.com/M-cheng-web/web-tracing/issues"
|
|
46
|
-
},
|
|
47
|
-
"homepage": "https://github.com/M-cheng-web/web-tracing#readme",
|
|
48
|
-
"unpkg": "./index.iife.min.js"
|
|
49
|
-
}
|
package/index.ts
DELETED
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import type { InitOptions } from './src/types'
|
|
2
|
-
import { initReplace, destroyReplace } from './src/lib/replace'
|
|
3
|
-
import { initOptions, options as _options } from './src/lib/options'
|
|
4
|
-
import { initBase } from './src/lib/base'
|
|
5
|
-
import { initSendData, sendData } from './src/lib/sendData'
|
|
6
|
-
import { initLineStatus } from './src/lib/line-status'
|
|
7
|
-
import { initError, parseError, destroyError } from './src/lib/err'
|
|
8
|
-
import { initEvent, destroyEvent } from './src/lib/event'
|
|
9
|
-
import { initHttp, destroyHttp } from './src/lib/http'
|
|
10
|
-
import { initPerformance, destroyPerformance } from './src/lib/performance'
|
|
11
|
-
import { initPv, destroyPv } from './src/lib/pv'
|
|
12
|
-
import {
|
|
13
|
-
initIntersection,
|
|
14
|
-
destroyIntersection
|
|
15
|
-
} from './src/lib/intersectionObserver'
|
|
16
|
-
import { _global } from './src/utils/global'
|
|
17
|
-
import { SENDID } from './src/common'
|
|
18
|
-
import { logError } from './src/utils/debug'
|
|
19
|
-
import { initRecordScreen, destroyRecordScreen } from './src/lib/recordscreen'
|
|
20
|
-
import * as exportMethods from './src/lib/exportMethods'
|
|
21
|
-
import './src/observer/index'
|
|
22
|
-
|
|
23
|
-
function init(options: InitOptions): void {
|
|
24
|
-
if (_global.__webTracingInit__) return
|
|
25
|
-
if (!initOptions(options)) return
|
|
26
|
-
|
|
27
|
-
// 注册全局
|
|
28
|
-
initReplace()
|
|
29
|
-
initBase()
|
|
30
|
-
initSendData()
|
|
31
|
-
initLineStatus()
|
|
32
|
-
|
|
33
|
-
// 注册各个业务
|
|
34
|
-
initError()
|
|
35
|
-
initEvent()
|
|
36
|
-
initHttp()
|
|
37
|
-
initPerformance()
|
|
38
|
-
initPv()
|
|
39
|
-
initIntersection()
|
|
40
|
-
|
|
41
|
-
if (_options.value.recordScreen) initRecordScreen()
|
|
42
|
-
|
|
43
|
-
_global.__webTracingInit__ = true
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* 销毁SDK添加的事件监听器,不会影响用户手动添加的监听器
|
|
48
|
-
*/
|
|
49
|
-
function destroyTracing(): void {
|
|
50
|
-
destroyEvent()
|
|
51
|
-
destroyError()
|
|
52
|
-
destroyHttp()
|
|
53
|
-
destroyPerformance()
|
|
54
|
-
destroyIntersection()
|
|
55
|
-
destroyRecordScreen()
|
|
56
|
-
destroyPv()
|
|
57
|
-
destroyReplace()
|
|
58
|
-
if (sendData) sendData.destroy()
|
|
59
|
-
|
|
60
|
-
// 重置全局状态,确保重新初始化时能正常工作
|
|
61
|
-
_global.__webTracingInit__ = false
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export {
|
|
65
|
-
init,
|
|
66
|
-
destroyTracing,
|
|
67
|
-
InitOptions,
|
|
68
|
-
logError,
|
|
69
|
-
parseError,
|
|
70
|
-
SENDID,
|
|
71
|
-
exportMethods,
|
|
72
|
-
_options as options
|
|
73
|
-
}
|
|
74
|
-
export * from './src/lib/exportMethods'
|
|
75
|
-
export default { init, destroyTracing, ...exportMethods, options: _options }
|
package/src/common/config.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { name, version } from '../../package.json'
|
|
2
|
-
|
|
3
|
-
export const DEVICE_KEY = '_webtracing_device_id' // 设备ID Key - 私有属性
|
|
4
|
-
|
|
5
|
-
export const SESSION_KEY = '_webtracing_session_id' // 会话ID Key(一个站点只允许运行一个埋点程序) - 私有属性
|
|
6
|
-
|
|
7
|
-
export const SURVIVIE_MILLI_SECONDS = 1800000 // 会话 session存活时长(30minutes) - 私有属性
|
|
8
|
-
|
|
9
|
-
export const SDK_LOCAL_KEY = '_webtracing_localization_key' // 事件本地化的key
|
|
10
|
-
|
|
11
|
-
export const SDK_VERSION = version
|
|
12
|
-
|
|
13
|
-
export const SDK_NAME = name
|
package/src/common/constant.ts
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 事件类型
|
|
3
|
-
*/
|
|
4
|
-
export enum EVENTTYPES {
|
|
5
|
-
ERROR = 'error',
|
|
6
|
-
CONSOLEERROR = 'consoleError',
|
|
7
|
-
UNHANDLEDREJECTION = 'unhandledrejection',
|
|
8
|
-
CLICK = 'click',
|
|
9
|
-
LOAD = 'load',
|
|
10
|
-
BEFOREUNLOAD = 'beforeunload',
|
|
11
|
-
FETCH = 'fetch',
|
|
12
|
-
XHROPEN = 'xhr-open',
|
|
13
|
-
XHRSEND = 'xhr-send',
|
|
14
|
-
HASHCHANGE = 'hashchange',
|
|
15
|
-
HISTORYPUSHSTATE = 'history-pushState',
|
|
16
|
-
HISTORYREPLACESTATE = 'history-replaceState',
|
|
17
|
-
POPSTATE = 'popstate',
|
|
18
|
-
READYSTATECHANGE = 'readystatechange',
|
|
19
|
-
ONLINE = 'online',
|
|
20
|
-
OFFLINE = 'offline'
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* 触发的事件是什么类型 - eventType
|
|
25
|
-
*/
|
|
26
|
-
export enum SEDNEVENTTYPES {
|
|
27
|
-
PV = 'pv', // 路由跳转
|
|
28
|
-
PVDURATION = 'pv-duration', // 页面停留事件
|
|
29
|
-
ERROR = 'error', // 错误
|
|
30
|
-
PERFORMANCE = 'performance', // 资源
|
|
31
|
-
CLICK = 'click', // 点击
|
|
32
|
-
DWELL = 'dwell', // 页面卸载
|
|
33
|
-
CUSTOM = 'custom', // 手动触发事件
|
|
34
|
-
INTERSECTION = 'intersection' // 曝光采集
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* 触发的事件id - eventID
|
|
39
|
-
*/
|
|
40
|
-
export enum SENDID {
|
|
41
|
-
PAGE = 'page', // 页面
|
|
42
|
-
RESOURCE = 'resource', // 资源
|
|
43
|
-
SERVER = 'server', // 请求
|
|
44
|
-
CODE = 'code', // code
|
|
45
|
-
REJECT = 'reject', // reject
|
|
46
|
-
CONSOLEERROR = 'console.error' // console.error
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* 网页的几种加载方式
|
|
51
|
-
*/
|
|
52
|
-
export const WEBPAGELOAD: Record<number, string> = {
|
|
53
|
-
0: 'navigate', // 网页通过点击链接,地址栏输入,表单提交,脚本操作等方式加载
|
|
54
|
-
1: 'reload', // 网页通过“重新加载”按钮或者location.reload()方法加载
|
|
55
|
-
2: 'back_forward', // 网页通过“前进”或“后退”按钮加载
|
|
56
|
-
255: 'reserved' // 任何其他来源的加载
|
|
57
|
-
}
|
package/src/common/index.ts
DELETED
package/src/lib/base.ts
DELETED
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
import { DEVICE_KEY, SDK_VERSION } from '../common'
|
|
2
|
-
import { _support, getGlobal, isTestEnv } from '../utils/global'
|
|
3
|
-
import { load } from '../utils/fingerprintjs'
|
|
4
|
-
import { getCookieByName, uuid } from '../utils'
|
|
5
|
-
import { getSessionId } from '../utils/session'
|
|
6
|
-
import { options } from './options'
|
|
7
|
-
import { getIPs } from '../utils/getIps'
|
|
8
|
-
import { AnyObj } from '../types'
|
|
9
|
-
import { computed } from '../observer'
|
|
10
|
-
import type { ObserverValue } from '../observer/types'
|
|
11
|
-
import { sendData } from './sendData'
|
|
12
|
-
|
|
13
|
-
interface Device {
|
|
14
|
-
clientHeight: number
|
|
15
|
-
clientWidth: number
|
|
16
|
-
colorDepth: number
|
|
17
|
-
pixelDepth: number
|
|
18
|
-
screenWidth: number
|
|
19
|
-
screenHeight: number
|
|
20
|
-
deviceId: string
|
|
21
|
-
vendor: string
|
|
22
|
-
platform: string
|
|
23
|
-
}
|
|
24
|
-
interface Base extends Device {
|
|
25
|
-
userUuid: string
|
|
26
|
-
sdkUserUuid: string
|
|
27
|
-
ext: AnyObj
|
|
28
|
-
appName: string
|
|
29
|
-
appCode: string
|
|
30
|
-
pageId: string
|
|
31
|
-
sessionId: string
|
|
32
|
-
sdkVersion: string
|
|
33
|
-
ip: string
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export class BaseInfo {
|
|
37
|
-
public base: ObserverValue<Base> | undefined
|
|
38
|
-
public pageId: string
|
|
39
|
-
private sdkUserUuid = ''
|
|
40
|
-
private device: Device | undefined
|
|
41
|
-
// 基础信息是否初始化成功
|
|
42
|
-
public _initSuccess = false
|
|
43
|
-
|
|
44
|
-
constructor() {
|
|
45
|
-
this.pageId = uuid() // 当前应用ID,在整个页面生命周期内不变,单页应用路由变化也不会改变;加载SDK时创建且只创建一次
|
|
46
|
-
|
|
47
|
-
this.initSdkUserUuid()
|
|
48
|
-
.then(() => {
|
|
49
|
-
this.initDevice()
|
|
50
|
-
this.initBase()
|
|
51
|
-
})
|
|
52
|
-
.finally(() => {
|
|
53
|
-
this._initSuccess = true
|
|
54
|
-
sendData.emit([])
|
|
55
|
-
})
|
|
56
|
-
}
|
|
57
|
-
private initDevice() {
|
|
58
|
-
const { screen } = getGlobal()
|
|
59
|
-
const { clientWidth, clientHeight } = document.documentElement
|
|
60
|
-
const { width, height, colorDepth, pixelDepth } = screen
|
|
61
|
-
let deviceId = getCookieByName(DEVICE_KEY)
|
|
62
|
-
if (!deviceId) {
|
|
63
|
-
deviceId = `t_${uuid()}`
|
|
64
|
-
document.cookie = `${DEVICE_KEY}=${deviceId};path=/;`
|
|
65
|
-
}
|
|
66
|
-
this.device = {
|
|
67
|
-
clientHeight, // 网页可见区高度
|
|
68
|
-
clientWidth, // 网页可见区宽度
|
|
69
|
-
colorDepth, // 显示屏幕调色板的比特深度
|
|
70
|
-
pixelDepth, // 显示屏幕的颜色分辨率
|
|
71
|
-
deviceId, // id
|
|
72
|
-
screenWidth: width, // 显示屏幕的宽度
|
|
73
|
-
screenHeight: height, // 显示屏幕的高度
|
|
74
|
-
vendor: navigator.vendor, // 浏览器名称
|
|
75
|
-
platform: navigator.platform // 浏览器平台的环境,不是电脑系统的x64这样的(浏览器平台的环境可能是x32)
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* 初始化 base 数据
|
|
80
|
-
*/
|
|
81
|
-
private initBase() {
|
|
82
|
-
// 与一般业务上理解的sessionId做区分,此session与业务无关,单纯就是浏览器端和后端直接的联系
|
|
83
|
-
const sessionId = getSessionId()
|
|
84
|
-
let ip = ''
|
|
85
|
-
|
|
86
|
-
this.base = computed<Base>(() => ({
|
|
87
|
-
...this.device!,
|
|
88
|
-
userUuid: options.value.userUuid,
|
|
89
|
-
sdkUserUuid: this.sdkUserUuid,
|
|
90
|
-
ext: options.value.ext,
|
|
91
|
-
appName: options.value.appName,
|
|
92
|
-
appCode: options.value.appCode,
|
|
93
|
-
pageId: this.pageId,
|
|
94
|
-
sessionId,
|
|
95
|
-
sdkVersion: SDK_VERSION,
|
|
96
|
-
ip
|
|
97
|
-
}))
|
|
98
|
-
|
|
99
|
-
!isTestEnv &&
|
|
100
|
-
getIPs().then((res: any) => {
|
|
101
|
-
this.base!.value.ip = res[0]
|
|
102
|
-
ip = res[0]
|
|
103
|
-
})
|
|
104
|
-
}
|
|
105
|
-
/**
|
|
106
|
-
* 初始化sdk中给用户的唯一标识
|
|
107
|
-
*/
|
|
108
|
-
private initSdkUserUuid() {
|
|
109
|
-
return isTestEnv
|
|
110
|
-
? Promise.resolve().then(() => {
|
|
111
|
-
this.sdkUserUuid = 'unit-test-id'
|
|
112
|
-
options.value.sdkUserUuid = 'unit-test-id'
|
|
113
|
-
})
|
|
114
|
-
: load({})
|
|
115
|
-
.then((fp: any) => fp.get())
|
|
116
|
-
.then((result: any) => {
|
|
117
|
-
const visitorId = result.visitorId
|
|
118
|
-
this.sdkUserUuid = visitorId
|
|
119
|
-
options.value.sdkUserUuid = visitorId
|
|
120
|
-
})
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
export let baseInfo: BaseInfo
|
|
125
|
-
|
|
126
|
-
export function initBase() {
|
|
127
|
-
baseInfo = new BaseInfo()
|
|
128
|
-
_support.baseInfo = baseInfo
|
|
129
|
-
}
|
package/src/lib/err-batch.ts
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
import { sendData } from './sendData'
|
|
2
|
-
import { AnyFun } from '../types'
|
|
3
|
-
import { debounce, throttle, groupArray } from '../utils'
|
|
4
|
-
|
|
5
|
-
const SETTIMEA = 2000
|
|
6
|
-
const SETTIMEB = 20000
|
|
7
|
-
const MAXLENGTHA = 5
|
|
8
|
-
const GROUPARRAYKEY = ['errMessage', 'eventId', 'requestUrl']
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* 判断是否为批量错误
|
|
12
|
-
* 判断流程:
|
|
13
|
-
* 1. 先把所有错误都放入 a栈
|
|
14
|
-
* 2. 每次发生错误后防抖 2s查 a栈是否有批量错误(批量错误: errMessage、errType相同且发生个数大于等于5)
|
|
15
|
-
* 1. 如果为批量错误则合并这些错误并加入[时间区间参数、发生个数参数]后放入 b栈
|
|
16
|
-
* 2. 不为批量错误则发送这些错误
|
|
17
|
-
* 3. 每次推入错误到b栈后延迟 20s查 b栈并发送这些错误
|
|
18
|
-
* 4. 在这个过程中,如果用户关闭了网页,会统一把 a栈、b栈内的数据发送
|
|
19
|
-
* 5. 在这个过程中,a栈每满50个错误也会强制触发a栈和b栈的错误处理(处理结果为直接发送批量错误)
|
|
20
|
-
*/
|
|
21
|
-
class BatchError {
|
|
22
|
-
cacheErrorA: any[]
|
|
23
|
-
cacheErrorB: any[]
|
|
24
|
-
throttleProxyAddCacheErrorA: AnyFun
|
|
25
|
-
throttleProxyAddCacheErrorB: AnyFun
|
|
26
|
-
constructor() {
|
|
27
|
-
this.cacheErrorA = []
|
|
28
|
-
this.cacheErrorB = []
|
|
29
|
-
this.throttleProxyAddCacheErrorA = debounce(
|
|
30
|
-
this.proxyAddCacheErrorA,
|
|
31
|
-
SETTIMEA
|
|
32
|
-
)
|
|
33
|
-
this.throttleProxyAddCacheErrorB = throttle(
|
|
34
|
-
this.proxyAddCacheErrorB,
|
|
35
|
-
SETTIMEB
|
|
36
|
-
)
|
|
37
|
-
}
|
|
38
|
-
proxyAddCacheErrorA() {
|
|
39
|
-
let len = this.cacheErrorA.length
|
|
40
|
-
if (!len) return
|
|
41
|
-
const arr = groupArray(this.cacheErrorA, ...GROUPARRAYKEY)
|
|
42
|
-
const arrA = arr.filter(item => item.length < MAXLENGTHA)
|
|
43
|
-
const arrB = arr.filter(item => item.length >= MAXLENGTHA)
|
|
44
|
-
|
|
45
|
-
if (arrA.length) {
|
|
46
|
-
sendData.emit(arrA.flat(Infinity))
|
|
47
|
-
}
|
|
48
|
-
if (arrB.length) {
|
|
49
|
-
const arrBsum: any[] = []
|
|
50
|
-
arrB.forEach(item => {
|
|
51
|
-
const sumItem = item[0]
|
|
52
|
-
sumItem.batchError = true
|
|
53
|
-
sumItem.batchErrorLength = item.length
|
|
54
|
-
sumItem.batchErrorLastHappenTime = item[item.length - 1].triggerTime
|
|
55
|
-
arrBsum.push(sumItem)
|
|
56
|
-
})
|
|
57
|
-
this.cacheErrorB.push(...arrBsum)
|
|
58
|
-
this.throttleProxyAddCacheErrorB()
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
while (len--) {
|
|
62
|
-
this.cacheErrorA.shift()
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
proxyAddCacheErrorB() {
|
|
66
|
-
let len = this.cacheErrorB.length
|
|
67
|
-
if (!len) return
|
|
68
|
-
const arr = groupArray(this.cacheErrorB, ...GROUPARRAYKEY)
|
|
69
|
-
|
|
70
|
-
while (len--) {
|
|
71
|
-
this.cacheErrorB.shift()
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
// 将区间报错合并
|
|
75
|
-
const emitList: any[] = []
|
|
76
|
-
arr.forEach((itemList: any[]) => {
|
|
77
|
-
const sumItem = itemList[0]
|
|
78
|
-
if (itemList.length > 1) {
|
|
79
|
-
sumItem.batchErrorLength = itemList.reduce(
|
|
80
|
-
(p, item) => (p += item.batchErrorLength),
|
|
81
|
-
0
|
|
82
|
-
)
|
|
83
|
-
sumItem.batchErrorLastHappenTime =
|
|
84
|
-
itemList[itemList.length - 1].triggerTime
|
|
85
|
-
}
|
|
86
|
-
emitList.push(sumItem)
|
|
87
|
-
})
|
|
88
|
-
sendData.emit(emitList)
|
|
89
|
-
}
|
|
90
|
-
/**
|
|
91
|
-
* 获取所有的错误
|
|
92
|
-
* 用户突然关闭页面时调用此方法集成错误
|
|
93
|
-
*/
|
|
94
|
-
sendAllCacheError() {
|
|
95
|
-
const errInfoList = this.cacheErrorA.concat(this.cacheErrorB)
|
|
96
|
-
const arr = groupArray(errInfoList, ...GROUPARRAYKEY)
|
|
97
|
-
const arrA = arr.filter(item => item.length < MAXLENGTHA)
|
|
98
|
-
const arrB = arr.filter(item => item.length >= MAXLENGTHA)
|
|
99
|
-
|
|
100
|
-
if (arrA.length) {
|
|
101
|
-
sendData.emit(arrA.flat(Infinity), true)
|
|
102
|
-
}
|
|
103
|
-
if (arrB.length) {
|
|
104
|
-
const arrBsum: any[] = []
|
|
105
|
-
arrB.forEach(item => {
|
|
106
|
-
const sumItem = item[0]
|
|
107
|
-
sumItem.batchError = true
|
|
108
|
-
sumItem.batchErrorLength = item.length
|
|
109
|
-
sumItem.batchErrorLastHappenTime = item[item.length - 1].triggerTime
|
|
110
|
-
arrBsum.push(sumItem)
|
|
111
|
-
})
|
|
112
|
-
sendData.emit(arrBsum, true)
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
pushCacheErrorA(errorInfo: any) {
|
|
116
|
-
this.cacheErrorA.push(errorInfo)
|
|
117
|
-
this.throttleProxyAddCacheErrorA()
|
|
118
|
-
|
|
119
|
-
// 每 50 个触发一次强制发送事件
|
|
120
|
-
if (this.cacheErrorA.length >= 50) {
|
|
121
|
-
this.proxyAddCacheErrorA()
|
|
122
|
-
this.proxyAddCacheErrorB()
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
export let batchError: BatchError
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* 初始化错误缓存
|
|
131
|
-
*/
|
|
132
|
-
export function initBatchError() {
|
|
133
|
-
batchError = new BatchError()
|
|
134
|
-
}
|