spy-client 2.1.7 → 2.1.9

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.
Files changed (80) hide show
  1. package/README.md +54 -11
  2. package/dist/spy-client-basic.esm.js +5 -2
  3. package/dist/spy-client-basic.iife.js +5 -2
  4. package/dist/spy-client-basic.iife.min.js +1 -1
  5. package/dist/spy-client-basic.js +5 -2
  6. package/dist/spy-client-basic.min.js +1 -1
  7. package/dist/spy-client-basic.mjs +5 -2
  8. package/dist/spy-client.esm.js +19 -11
  9. package/dist/spy-client.iife.js +19 -11
  10. package/dist/spy-client.iife.min.js +1 -1
  11. package/dist/spy-client.js +19 -11
  12. package/dist/spy-client.min.js +1 -1
  13. package/dist/spy-client.mjs +19 -11
  14. package/dist/spy-head.js +15 -10
  15. package/dist/spy-head.min.js +1 -1
  16. package/example/index.html +2 -0
  17. package/package.json +1 -1
  18. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/base.css +0 -224
  19. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/basicSpec.ts.html +0 -740
  20. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/block-navigation.js +0 -79
  21. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/checkSpec.ts.html +0 -479
  22. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/favicon.png +0 -0
  23. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/headSpec.ts.html +0 -695
  24. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/index.html +0 -171
  25. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/markSpec.ts.html +0 -284
  26. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/metricSpec.ts.html +0 -977
  27. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/prettify.css +0 -1
  28. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/prettify.js +0 -2
  29. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
  30. package/coverage/Chrome 92.0.4515.159 (Mac OS 10.15.7)/html/sorter.js +0 -170
  31. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/base.css +0 -224
  32. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/basicSpec.ts.html +0 -740
  33. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/block-navigation.js +0 -79
  34. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/checkSpec.ts.html +0 -479
  35. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/favicon.png +0 -0
  36. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/headSpec.ts.html +0 -695
  37. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/index.html +0 -171
  38. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/markSpec.ts.html +0 -284
  39. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/metricSpec.ts.html +0 -977
  40. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/prettify.css +0 -1
  41. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/prettify.js +0 -2
  42. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
  43. package/coverage/Chrome 95.0.4638.69 (Mac OS 10.15.7)/html/sorter.js +0 -170
  44. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/base.css +0 -224
  45. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/basicSpec.ts.html +0 -740
  46. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/block-navigation.js +0 -79
  47. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/checkSpec.ts.html +0 -479
  48. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/favicon.png +0 -0
  49. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/headSpec.ts.html +0 -695
  50. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/index.html +0 -171
  51. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/markSpec.ts.html +0 -284
  52. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/metricSpec.ts.html +0 -977
  53. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/prettify.css +0 -1
  54. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/prettify.js +0 -2
  55. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/sort-arrow-sprite.png +0 -0
  56. package/coverage/Chrome 96.0.4664.55 (Mac OS 10.15.7)/html/sorter.js +0 -170
  57. package/src/head/base.ts +0 -69
  58. package/src/head/error.ts +0 -118
  59. package/src/head/observer.ts +0 -40
  60. package/src/head/readme.md +0 -1
  61. package/src/head/whitescreen.ts +0 -105
  62. package/src/lib/data.ts +0 -14
  63. package/src/lib/huffman.ts +0 -307
  64. package/src/lib/interface.ts +0 -331
  65. package/src/lib/spyHeadInterface.ts +0 -40
  66. package/src/lib/util.ts +0 -101
  67. package/src/module/fid.ts +0 -56
  68. package/src/module/layoutShift.ts +0 -71
  69. package/src/module/lcp.ts +0 -63
  70. package/src/module/longtask.ts +0 -193
  71. package/src/module/memory.ts +0 -43
  72. package/src/module/navigatorInfo.ts +0 -61
  73. package/src/module/resource.ts +0 -433
  74. package/src/module/timing.ts +0 -75
  75. package/src/module/tti.ts +0 -139
  76. package/src/spy-client-basic.ts +0 -387
  77. package/src/spy-client.ts +0 -198
  78. package/src/spy-head.ts +0 -31
  79. package/src/spy-local-cache.ts +0 -478
  80. package/src/types/globals.d.ts +0 -93
@@ -1,478 +0,0 @@
1
- import {huffmanEncode, huffmanDecode} from './lib/huffman';
2
-
3
- interface Option {
4
- defaultTrigger: boolean;
5
- compress: 'huffman' | 'lzw' | 'no';
6
- key: string;
7
- maxRecordLen: number;
8
- interval: number;
9
- onFlush?: (res: any) => void;
10
- onSave?: (res: any) => void;
11
- onAdd?: (res: any) => boolean;
12
- storage: 'indexedDB' | 'localstorage' | 'empty';
13
- }
14
-
15
- class Storage {
16
- static isSupport: () => boolean;
17
-
18
- set(key: string, value: any) {
19
-
20
- }
21
-
22
- get(key: string, cb: any) {
23
-
24
- }
25
-
26
- rm(key: string) {
27
-
28
- }
29
- }
30
-
31
- class LS extends Storage {
32
- static isSupport() {
33
- return !!window.localStorage;
34
- }
35
-
36
- set(key: string, value: any) {
37
- try {
38
- localStorage.setItem(key, value);
39
- }
40
- catch (e) {
41
- console.error(e);
42
- }
43
- return;
44
- }
45
-
46
- get(key: string, cb: any) {
47
- let res = null;
48
- try {
49
- res = localStorage.getItem(key);
50
- }
51
- catch (e) {
52
- console.error(e);
53
- }
54
- if (cb) {
55
- cb(res);
56
- }
57
- return;
58
- }
59
-
60
- rm(key: string) {
61
- try {
62
- localStorage.removeItem(key);
63
- }
64
- catch (e) {
65
- console.error(e);
66
- }
67
- return;
68
- }
69
-
70
- }
71
-
72
- class IndexedDB extends Storage {
73
- private readonly databaseName = 'spyLC';
74
- private db: IDBDatabase | null = null;
75
- private readonly setQueue: any[] = [];
76
- private readonly getQueue: any[] = [];
77
- constructor() {
78
- super();
79
-
80
- let request = window.indexedDB.open(this.databaseName);
81
-
82
- request.onupgradeneeded = event => {
83
- // @ts-ignore ts默认的EventTarget类型有问题,先ignore掉
84
- this.db = event.target && event.target.result;
85
- if (this.db && !this.db.objectStoreNames.contains(this.databaseName)) {
86
- this.db.createObjectStore(this.databaseName, {keyPath: 'key'});
87
- }
88
- this.runQueueTask();
89
- };
90
-
91
- request.onsuccess = () => {
92
- this.db = request.result;
93
- this.runQueueTask();
94
- };
95
-
96
- }
97
- static isSupport() {
98
- return !!window.indexedDB;
99
- }
100
-
101
- set(key: string, value: any) {
102
- // 因为indexDB是异步初始化的,如果set的时候未初始化,先缓存之后再执行set
103
- if (!this.db) {
104
- this.setQueue.push({
105
- key,
106
- value,
107
- });
108
- return;
109
- }
110
- this.db.transaction([this.databaseName], 'readwrite')
111
- .objectStore(this.databaseName)
112
- .add({
113
- key,
114
- value,
115
- });
116
-
117
- }
118
-
119
- get(key: string, cb: any) {
120
- // 因为indexDB是异步初始化的,如果get的时候未初始化,先缓存之后再执行get
121
- if (!this.db) {
122
- this.getQueue.push({
123
- key,
124
- cb,
125
- });
126
- return;
127
- }
128
- const transaction = this.db.transaction([this.databaseName]);
129
- const objectStore = transaction.objectStore(this.databaseName);
130
- const request = objectStore.get(key);
131
-
132
- request.onsuccess = () => {
133
- const result = request.result ? request.result : {value: ''};
134
- cb(result.value);
135
- };
136
- }
137
-
138
- private runQueueTask() {
139
- this.setQueue.forEach(ele => {
140
- this.set(ele.key, ele.value);
141
- });
142
- this.getQueue.forEach(ele => {
143
- this.get(ele.key, ele.cb);
144
- });
145
- }
146
- }
147
-
148
- function assign(...args: any[]) {
149
- const __assign = Object.assign || function __assign(t: any) {
150
- for (let s, i = 1, n = arguments.length; i < n; i++) {
151
- // eslint-disable-next-line prefer-rest-params
152
- s = arguments[i];
153
- for (const p in s) {
154
- if (Object.prototype.hasOwnProperty.call(s, p)) {
155
- t[p] = s[p];
156
- }
157
- }
158
- }
159
- return t;
160
- };
161
- return __assign.apply(this, args);
162
- };
163
-
164
- function utf8Encode(text: string) {
165
- let result = '';
166
- for (let n = 0; n < text.length; n++) {
167
- const c = text.charCodeAt(n);
168
- if (c < 128) {
169
- result += String.fromCharCode(c);
170
- }
171
- else if (c > 127 && c < 2048) {
172
- result += String.fromCharCode((c >> 6) | 192);
173
- result += String.fromCharCode((c & 63) | 128);
174
- }
175
- else {
176
- result += String.fromCharCode((c >> 12) | 224);
177
- result += String.fromCharCode(((c >> 6) & 63) | 128);
178
- result += String.fromCharCode((c & 63) | 128);
179
- }
180
- }
181
- return result;
182
- // return window.btoa(result);
183
- }
184
-
185
- function utf8Decode(text: string) {
186
- // text = window.atob(text);
187
- let result = '';
188
- let i = 0;
189
- let c1 = 0;
190
- let c2 = 0;
191
- let c3 = 0;
192
- while (i < text.length) {
193
- c1 = text.charCodeAt(i);
194
- if (c1 < 128) {
195
- result += String.fromCharCode(c1);
196
- i++;
197
- }
198
- else if (c1 > 191 && c1 < 224) {
199
- c2 = text.charCodeAt(i + 1);
200
- result += String.fromCharCode(((c1 & 31) << 6) | (c2 & 63));
201
- i += 2;
202
- }
203
- else {
204
- c2 = text.charCodeAt(i + 1);
205
- c3 = text.charCodeAt(i + 2);
206
- result += String.fromCharCode(((c1 & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
207
- i += 3;
208
- }
209
- }
210
- return result;
211
- }
212
-
213
-
214
- function lzw(text: string, deCompress = false) {
215
- if (!text) {
216
- return '';
217
- };
218
- if (!deCompress) {
219
- text = utf8Encode(text);
220
- }
221
-
222
- let dict: any = {};
223
- let out: any[] = [];
224
- let prefix = text.charAt(0);
225
- let curChar = prefix;
226
- let oldPrefix = curChar;
227
- let idx = 256;
228
- let i;
229
- let c;
230
- let d;
231
- let g = function () {
232
- out.push(prefix.length > 1 ? String.fromCharCode(dict[prefix]) : prefix);
233
- };
234
- if (deCompress) {
235
- out.push(prefix);
236
- }
237
- for (i = 1, c, d; i < text.length; i++) {
238
- c = text.charAt(i);
239
- if (deCompress) {
240
- d = text.charCodeAt(i);
241
- prefix = d < 256 ? c : dict[d] || (prefix + curChar);
242
- out.push(prefix);
243
- curChar = prefix.charAt(0);
244
- dict[idx++] = oldPrefix + curChar;
245
- oldPrefix = prefix;
246
- }
247
- else {
248
- if (dict.hasOwnProperty(prefix + c)) {
249
- prefix += c;
250
- }
251
- else {
252
- g();
253
- dict[prefix + c] = idx++;
254
- prefix = c;
255
- }
256
- }
257
- }
258
- if (!deCompress) {
259
- g();
260
- }
261
-
262
- let ret = out.join('');
263
- if (deCompress) {
264
- ret = utf8Decode(ret);
265
- }
266
-
267
- return ret;
268
- }
269
-
270
-
271
- export default class SpyLocalCache {
272
- private readonly option: Option;
273
- private storage: Storage;
274
- private timer: ReturnType<typeof setTimeout>;
275
- private tmpList: string[] = [];
276
- constructor(option: any = {}) {
277
- this.option = assign({
278
- defaultTrigger: true,
279
- compress: 'lzw', // huffman lzw no
280
- key: 'SpyLocalCache',
281
- interval: 500,
282
- maxRecordLen: 30,
283
- onFlush: () => {},
284
- onSave: () => {},
285
- onAdd: () => {
286
- return true;
287
- },
288
- storage: IndexedDB.isSupport()
289
- ? 'indexedDB'
290
- : LS.isSupport()
291
- ? 'localstorage'
292
- : 'empty',
293
- }, option);
294
-
295
- this.load = this.load.bind(this);
296
-
297
- this.init();
298
- }
299
-
300
- init() {
301
- if (this.option.storage === 'indexedDB') {
302
- this.storage = new IndexedDB();
303
- }
304
- else if (this.option.storage === 'localstorage') {
305
- this.storage = new LS();
306
- }
307
- else {
308
- this.storage = new Storage();
309
- }
310
-
311
- if (document.readyState === 'complete') {
312
- this.load();
313
- }
314
- else {
315
- window.addEventListener('load', this.load);
316
- }
317
- }
318
-
319
- load() {
320
- if (location.search.indexOf('_FlushLogLocalCache=1') > -1 && this.option.defaultTrigger) {
321
- this.flushLog();
322
- }
323
- }
324
-
325
- addLog(info: any) {
326
- if (this.option.onAdd) {
327
- if (!this.option.onAdd(info)) {
328
- return;
329
- }
330
- }
331
-
332
- info = JSON.stringify(info);
333
-
334
- this.tmpList.push(info as string);
335
-
336
- // 控制写日志频率
337
- if (this.timer) {
338
- clearTimeout(this.timer);
339
- }
340
- this.timer = setTimeout(() => {
341
- this.save();
342
- }, this.option.interval);
343
- }
344
-
345
- getData(cb: any) {
346
- try {
347
- this.storage.get(this.option.key, (encodeStr: string) => {
348
- if (encodeStr) {
349
- this.storage.get(this.option.key + 'Codes', (codes: any) => {
350
- let res: any[] = [];
351
- try {
352
- if (codes) {
353
- codes = JSON.parse(codes);
354
- }
355
- const str = this.unzip(encodeStr, codes);
356
- res = str.split('\n');
357
- }
358
- catch (e) {
359
- console.error(e);
360
- }
361
- cb(res);
362
- });
363
- }
364
- else {
365
- cb([]);
366
- }
367
- });
368
-
369
- }
370
- catch (e) {
371
- console.error(e);
372
- cb([]);
373
- }
374
- }
375
-
376
- save() {
377
- const st = Date.now();
378
- this.getData((list: any[]) => {
379
- // 只保留最近的maxRecordLen条日志
380
- const reserveLen = this.option.maxRecordLen - 1;
381
- const originList = list.length > reserveLen ? list.slice(list.length - reserveLen, list.length) : list;
382
- let newList = originList.concat(this.tmpList);
383
- let content = newList.join('\n');
384
- let error: Error | null = null;
385
- let len = 0;
386
- try {
387
- let data = this.zip(content);
388
- let codesStr = '';
389
- if (data.codes) {
390
- codesStr = JSON.stringify(data.codes);
391
- this.storage.set(this.option.key + 'Codes', codesStr);
392
- }
393
- else {
394
- this.storage.rm(this.option.key + 'Codes');
395
- }
396
-
397
- this.storage.set(this.option.key, data.result);
398
- len = data.result.length;
399
- }
400
- catch (e) {
401
- error = e;
402
- console.error(e);
403
- }
404
-
405
- this.tmpList = [];
406
-
407
- this.option.onSave && this.option.onSave({
408
- cost: Date.now() - st,
409
- length: len / 1024,
410
- list: newList,
411
- error: error,
412
- });
413
- });
414
- }
415
-
416
- flushLog() {
417
- this.getData((list: any[]) => {
418
-
419
- // 先解析来自存储的数据,若失败,说明格式有问题,清空存储
420
- try {
421
- for (let index = 0; index < list.length; index++) {
422
- list[index] = JSON.parse(list[index]);
423
- }
424
- }
425
- catch (e) {
426
- list = [];
427
- this.storage.rm(this.option.key);
428
- console.error(e);
429
- }
430
- // 未落盘的数据也加上
431
- for (let index = 0; index < this.tmpList.length; index++) {
432
- list.push(JSON.parse(this.tmpList[index]));
433
- }
434
- this.option.onFlush && this.option.onFlush(list);
435
- });
436
- }
437
-
438
- zip(str: string) {
439
- if (this.option.compress === 'lzw') {
440
- return {
441
- codes: null,
442
- result: lzw(str),
443
- };
444
- }
445
- else if (this.option.compress === 'huffman') {
446
- return huffmanEncode(str);
447
- }
448
- return {
449
- codes: null,
450
- result: str,
451
- };
452
- }
453
-
454
- unzip(str: string, codes?: any) {
455
- if (this.option.compress === 'lzw') {
456
- return lzw(str, true);
457
- }
458
- else if (this.option.compress === 'huffman') {
459
- return huffmanDecode(codes, str);
460
- }
461
- return str;
462
- }
463
- }
464
-
465
- // For test
466
- // let content = JSON.stringify({
467
- // type: 3,
468
- // fm: 'disp',
469
- // data: [{"base":{"size":{"doc":{"w":360,"h":4875},"wind":{"w":360,"h":640},"scr":{"w":360,"h":640}},"vsb":"visible","num":16},"t":1629773746698,"path":"/s"}],
470
- // qid: 10991431029479106376,
471
- // did: '8dd09c47c7bc90c9fd7274f0ad2c581e',
472
- // q: '刘德华',
473
- // t: 1629773746698,
474
- // });
475
- // const compressText = lzw(content);
476
- // const deCompressText = lzw(compressText, true);
477
- // console.log('compressText', compressText, compressText.length);
478
- // console.log('deCompressText', deCompressText, deCompressText.length);
@@ -1,93 +0,0 @@
1
- /**
2
- * @file 全局声明
3
- * @author kaivean
4
- */
5
-
6
- interface Window {
7
- __spyHead: any;
8
- __spyclientConf: any;
9
- PerformanceObserver: any;
10
- requestIdleCallback?: (callback: () => void, options?: any) => void;
11
- }
12
-
13
- interface Event {
14
- // MSMediaKeyMessageEvent 继承 Event,并且有message属性 且是 Uint8Array,会有冲突。这里设置为any
15
- message?: any;
16
- lineno?: number;
17
- line?: number;
18
- colno?: number;
19
- column?: number;
20
- error?: any;
21
- filename: any;
22
- sourceURL: any;
23
- errorCharacter?: number;
24
- }
25
-
26
- interface Connection {
27
- downlink?: number;
28
- effectiveType?: '2g' | '3g' | '4g' | 'slow-2g';
29
- onchange?: () => void;
30
- rtt?: number;
31
- saveData?: boolean;
32
- }
33
-
34
- interface Navigator {
35
- deviceMemory: number;
36
- hardwareConcurrency: number;
37
- connection: Connection;
38
- }
39
-
40
- interface MemoryInfo {
41
- totalJSHeapSize: number;
42
- usedJSHeapSize: number;
43
- jsHeapSizeLimit: number;
44
- }
45
-
46
- interface Performance {
47
- memory?: MemoryInfo;
48
- }
49
-
50
- interface PerformanceTiming {
51
- domFirstPaint?: number;
52
- domFirstScreenPaint?: number;
53
- }
54
-
55
- type PerformanceObserverType =
56
- | 'first-input'
57
- | 'largest-contentful-paint'
58
- | 'layout-shift'
59
- | 'longtask'
60
- | 'measure'
61
- | 'navigation'
62
- | 'paint'
63
- | 'resource';
64
-
65
-
66
- type PerformanceEntryInitiatorType =
67
- | 'beacon'
68
- | 'css'
69
- | 'fetch'
70
- | 'img'
71
- | 'other'
72
- | 'script'
73
- | 'xmlhttprequest';
74
-
75
-
76
- interface PerformanceEntry {
77
- decodedBodySize?: number;
78
- // duration: number;
79
- // entryType: PerformanceObserverType;
80
- initiatorType?: PerformanceEntryInitiatorType;
81
- loadTime: number;
82
- // name: string;
83
- renderTime: number;
84
- // startTime: number;
85
- // hadRecentInput?: boolean;
86
- value?: number;
87
- hadRecentInput: boolean;
88
- attribution: Array<{containerSrc: string}>;
89
- }
90
-
91
- interface PerformanceObserver {
92
- takeRecords: () => PerformanceEntryList;
93
- }