@cloudcare/browser-core 1.2.9 → 2.0.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.
Files changed (61) hide show
  1. package/cjs/browser/fetchObservable.js +3 -4
  2. package/cjs/browser/htmlDomUtils.js +45 -0
  3. package/cjs/browser/pageExitObservable.js +72 -0
  4. package/cjs/configuration/configuration.js +8 -0
  5. package/cjs/configuration/transportConfiguration.js +7 -0
  6. package/cjs/dataMap.js +12 -4
  7. package/cjs/helper/deviceInfo.js +44 -2
  8. package/cjs/helper/enums.js +3 -0
  9. package/cjs/helper/getZoneJsOriginalValue.js +34 -0
  10. package/cjs/helper/instrumentMethod.js +7 -1
  11. package/cjs/helper/lifeCycle.js +2 -6
  12. package/cjs/helper/readBytesFromStream.js +74 -0
  13. package/cjs/helper/tools.js +124 -47
  14. package/cjs/index.js +52 -0
  15. package/cjs/session/sessionStore.js +1 -1
  16. package/cjs/transport/batch.js +7 -44
  17. package/cjs/transport/httpRequest.js +4 -2
  18. package/cjs/transport/sendWithRetryStrategy.js +8 -8
  19. package/cjs/transport/startBatchWithReplica.js +2 -2
  20. package/esm/browser/fetchObservable.js +3 -4
  21. package/esm/browser/htmlDomUtils.js +26 -0
  22. package/esm/browser/pageExitObservable.js +57 -0
  23. package/esm/configuration/configuration.js +5 -0
  24. package/esm/configuration/transportConfiguration.js +7 -0
  25. package/esm/dataMap.js +9 -2
  26. package/esm/helper/contextHistory.js +1 -1
  27. package/esm/helper/deviceInfo.js +44 -2
  28. package/esm/helper/enums.js +3 -0
  29. package/esm/helper/getZoneJsOriginalValue.js +27 -0
  30. package/esm/helper/instrumentMethod.js +6 -1
  31. package/esm/helper/lifeCycle.js +2 -6
  32. package/esm/helper/readBytesFromStream.js +67 -0
  33. package/esm/helper/tools.js +100 -45
  34. package/esm/index.js +4 -0
  35. package/esm/session/sessionStore.js +1 -1
  36. package/esm/transport/batch.js +8 -45
  37. package/esm/transport/httpRequest.js +4 -2
  38. package/esm/transport/sendWithRetryStrategy.js +8 -8
  39. package/esm/transport/startBatchWithReplica.js +2 -2
  40. package/package.json +2 -2
  41. package/src/browser/fetchObservable.js +21 -17
  42. package/src/browser/htmlDomUtils.js +35 -0
  43. package/src/browser/pageExitObservable.js +70 -0
  44. package/src/configuration/configuration.js +6 -0
  45. package/src/configuration/transportConfiguration.js +30 -6
  46. package/src/dataMap.js +9 -2
  47. package/src/helper/contextHistory.js +1 -1
  48. package/src/helper/deviceInfo.js +39 -3
  49. package/src/helper/enums.js +40 -37
  50. package/src/helper/getZoneJsOriginalValue.js +27 -0
  51. package/src/helper/instrumentMethod.js +40 -50
  52. package/src/helper/lifeCycle.js +2 -7
  53. package/src/helper/readBytesFromStream.js +69 -0
  54. package/src/helper/tools.js +114 -45
  55. package/src/index.js +4 -1
  56. package/src/session/sessionStore.js +27 -24
  57. package/src/synthetics/syntheticsWorkerValues.js +11 -7
  58. package/src/transport/batch.js +70 -81
  59. package/src/transport/httpRequest.js +25 -25
  60. package/src/transport/sendWithRetryStrategy.js +14 -9
  61. package/src/transport/startBatchWithReplica.js +11 -5
package/esm/dataMap.js CHANGED
@@ -1,6 +1,5 @@
1
1
  import { RumEventType } from './helper/enums';
2
2
  export var commonTags = {
3
- action_id: 'action.id',
4
3
  sdk_name: '_dd.sdk_name',
5
4
  sdk_version: '_dd.sdk_version',
6
5
  app_id: 'application.id',
@@ -13,6 +12,7 @@ export var commonTags = {
13
12
  session_id: 'session.id',
14
13
  session_type: 'session.type',
15
14
  session_sampling: 'session.is_sampling',
15
+ session_has_replay: 'session.has_replay',
16
16
  is_signin: 'user.is_signin',
17
17
  os: 'device.os',
18
18
  os_version: 'device.os_version',
@@ -32,6 +32,10 @@ export var commonTags = {
32
32
  // 冗余一个字段
33
33
  view_path_group: 'view.path_group',
34
34
  view_url_query: 'view.url_query'
35
+ };
36
+ export var commonFields = {
37
+ action_id: 'action.id',
38
+ view_in_foreground: 'view.in_foreground'
35
39
  }; // 需要用双引号将字符串类型的field value括起来, 这里有数组标示[string, path]
36
40
 
37
41
  export var dataMap = {
@@ -43,6 +47,7 @@ export var dataMap = {
43
47
  is_active: 'view.is_active'
44
48
  },
45
49
  fields: {
50
+ session_replay_stats: '_dd.replay_stats',
46
51
  view_error_count: 'view.error.count',
47
52
  view_resource_count: 'view.resource.count',
48
53
  view_long_task_count: 'view.long_task.count',
@@ -63,7 +68,9 @@ export var dataMap = {
63
68
  time_to_interactive: 'view.tti',
64
69
  dom: 'view.dom',
65
70
  dom_ready: 'view.dom_ready',
66
- time_spent: 'view.time_spent'
71
+ time_spent: 'view.time_spent',
72
+ in_foreground_periods: 'view.in_foreground_periods',
73
+ frustration_count: 'view.frustration.count'
67
74
  }
68
75
  },
69
76
  resource: {
@@ -1,4 +1,4 @@
1
- import { relativeNow, ONE_MINUTE, filter, map, each } from './tools';
1
+ import { relativeNow, ONE_MINUTE, filter, map } from './tools';
2
2
  var END_OF_TIMES = Infinity;
3
3
  export var CLEAR_OLD_CONTEXTS_INTERVAL = ONE_MINUTE;
4
4
  export function ContextHistory(expireDelay) {
@@ -188,8 +188,50 @@ var MethodLibrary = {
188
188
  },
189
189
  // 获取网络状态
190
190
  getNetwork: function getNetwork() {
191
- var netWork = navigator && navigator.connection && navigator.connection.effectiveType;
192
- return netWork;
191
+ var connection = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection;
192
+ var result = 'unknown';
193
+ var type = connection ? connection.type || connection.effectiveType : null;
194
+
195
+ if (type && typeof type === 'string') {
196
+ switch (type) {
197
+ // possible type values
198
+ case 'bluetooth':
199
+ case 'cellular':
200
+ result = 'cellular';
201
+ break;
202
+
203
+ case 'none':
204
+ result = 'none';
205
+ break;
206
+
207
+ case 'ethernet':
208
+ case 'wifi':
209
+ case 'wimax':
210
+ result = 'wifi';
211
+ break;
212
+
213
+ case 'other':
214
+ case 'unknown':
215
+ result = 'unknown';
216
+ break;
217
+ // possible effectiveType values
218
+
219
+ case 'slow-2g':
220
+ case '2g':
221
+ case '3g':
222
+ result = 'cellular';
223
+ break;
224
+
225
+ case '4g':
226
+ result = 'wifi';
227
+ break;
228
+
229
+ default:
230
+ break;
231
+ }
232
+ }
233
+
234
+ return result;
193
235
  },
194
236
  // 获取当前语言
195
237
  getLanguage: function getLanguage() {
@@ -10,6 +10,9 @@ export var DOM_EVENT = {
10
10
  TOUCH_END: 'touchend',
11
11
  TOUCH_MOVE: 'touchmove',
12
12
  VISIBILITY_CHANGE: 'visibilitychange',
13
+ PAGE_SHOW: 'pageshow',
14
+ FREEZE: 'freeze',
15
+ RESUME: 'resume',
13
16
  DOM_CONTENT_LOADED: 'DOMContentLoaded',
14
17
  POINTER_DOWN: 'pointerdown',
15
18
  POINTER_UP: 'pointerup',
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Gets the original value for a DOM API that was potentially patched by Zone.js.
3
+ *
4
+ * Zone.js[1] is a library that patches a bunch of JS and DOM APIs. It usually stores the original
5
+ * value of the patched functions/constructors/methods in a hidden property prefixed by
6
+ * __zone_symbol__.
7
+ *
8
+ * In multiple occasions, we observed that Zone.js is the culprit of important issues leading to
9
+ * browser resource exhaustion (memory leak, high CPU usage). This method is used as a workaround to
10
+ * use the original DOM API instead of the one patched by Zone.js.
11
+ *
12
+ * [1]: https://github.com/angular/angular/tree/main/packages/zone.js
13
+ */
14
+ export function getZoneJsOriginalValue(target, name) {
15
+ var browserWindow = window;
16
+ var original;
17
+
18
+ if (browserWindow.Zone && typeof browserWindow.Zone.__symbol__ === 'function') {
19
+ original = target[browserWindow.Zone.__symbol__(name)];
20
+ }
21
+
22
+ if (!original) {
23
+ original = target[name];
24
+ }
25
+
26
+ return original;
27
+ }
@@ -1,4 +1,5 @@
1
1
  import { noop } from './tools';
2
+ import { getZoneJsOriginalValue } from './getZoneJsOriginalValue';
2
3
  export function instrumentMethod(object, method, instrumentationFactory) {
3
4
  var original = object[method];
4
5
  var instrumentation = instrumentationFactory(original);
@@ -52,7 +53,11 @@ export function instrumentSetter(object, property, after) {
52
53
  return {
53
54
  stop: noop
54
55
  };
55
- }
56
+ } // Using the patched `setTimeout` from Zone.js triggers a rendering loop in some Angular
57
+ // component, see issue RUMF-1443
58
+
59
+
60
+ var setTimeout = getZoneJsOriginalValue(window, 'setTimeout');
56
61
 
57
62
  var instrumentation = function instrumentation(thisObject, value) {
58
63
  // put hooked setter into event loop to avoid of set latency
@@ -1,27 +1,23 @@
1
1
  import { each, filter } from './tools';
2
2
  export var LifeCycleEventType = {
3
3
  PERFORMANCE_ENTRIES_COLLECTED: 'PERFORMANCE_ENTRIES_COLLECTED',
4
- AUTO_ACTION_CREATED: 'AUTO_ACTION_CREATED',
5
4
  AUTO_ACTION_COMPLETED: 'AUTO_ACTION_COMPLETED',
6
5
  VIEW_CREATED: 'VIEW_CREATED',
7
6
  VIEW_UPDATED: 'VIEW_UPDATED',
8
7
  VIEW_ENDED: 'VIEW_ENDED',
9
8
  SESSION_RENEWED: 'SESSION_RENEWED',
10
9
  SESSION_EXPIRED: 'SESSION_EXPIRED',
11
- DOM_MUTATED: 'DOM_MUTATED',
12
- BEFORE_UNLOAD: 'BEFORE_UNLOAD',
10
+ PAGE_EXITED: 'PAGE_EXITED',
13
11
  REQUEST_STARTED: 'REQUEST_STARTED',
14
12
  REQUEST_COMPLETED: 'REQUEST_COMPLETED',
15
13
  RAW_RUM_EVENT_COLLECTED: 'RAW_RUM_EVENT_COLLECTED',
16
14
  RUM_EVENT_COLLECTED: 'RUM_EVENT_COLLECTED',
17
15
  RAW_ERROR_COLLECTED: 'RAW_ERROR_COLLECTED',
18
- RECORD_STARTED: 'RECORD_STARTED',
19
- RECORD_STOPPED: 'RECORD_STOPPED',
20
16
  RAW_LOG_COLLECTED: 'RAW_LOG_COLLECTED',
21
17
  LOG_COLLECTED: 'LOG_COLLECTED'
22
18
  };
23
19
  export function LifeCycle() {
24
- this.callbacks = [];
20
+ this.callbacks = {};
25
21
  }
26
22
  LifeCycle.prototype = {
27
23
  notify: function notify(eventType, data) {
@@ -0,0 +1,67 @@
1
+ import { noop, each } from './tools';
2
+ /**
3
+ * Read bytes from a ReadableStream until at least `limit` bytes have been read (or until the end of
4
+ * the stream). The callback is invoked with the at most `limit` bytes, and indicates that the limit
5
+ * has been exceeded if more bytes were available.
6
+ */
7
+
8
+ export function readBytesFromStream(stream, callback, options) {
9
+ var reader = stream.getReader();
10
+ var chunks = [];
11
+ var readBytesCount = 0;
12
+ readMore();
13
+
14
+ function readMore() {
15
+ reader.read().then(function (result) {
16
+ if (result.done) {
17
+ onDone();
18
+ return;
19
+ }
20
+
21
+ if (options.collectStreamBody) {
22
+ chunks.push(result.value);
23
+ }
24
+
25
+ readBytesCount += result.value.length;
26
+
27
+ if (readBytesCount > options.bytesLimit) {
28
+ onDone();
29
+ } else {
30
+ readMore();
31
+ }
32
+ }, function (error) {
33
+ callback(error);
34
+ });
35
+ }
36
+
37
+ function onDone() {
38
+ reader.cancel().catch( // we don't care if cancel fails, but we still need to catch the error to avoid reporting it
39
+ // as an unhandled rejection
40
+ noop);
41
+ var bytes;
42
+ var limitExceeded;
43
+
44
+ if (options.collectStreamBody) {
45
+ var completeBuffer;
46
+
47
+ if (chunks.length === 1) {
48
+ // optimization: if the response is small enough to fit in a single buffer (provided by the browser), just
49
+ // use it directly.
50
+ completeBuffer = chunks[0];
51
+ } else {
52
+ // else, we need to copy buffers into a larger buffer to concatenate them.
53
+ completeBuffer = new Uint8Array(readBytesCount);
54
+ var offset = 0;
55
+ each(chunks, function (chunk) {
56
+ completeBuffer.set(chunk, offset);
57
+ offset += chunk.length;
58
+ });
59
+ }
60
+
61
+ bytes = completeBuffer.slice(0, options.bytesLimit);
62
+ limitExceeded = completeBuffer.length > options.bytesLimit;
63
+ }
64
+
65
+ callback(undefined, bytes, limitExceeded);
66
+ }
67
+ }
@@ -1,3 +1,5 @@
1
+ import { DOM_EVENT } from './enums';
2
+ import { getZoneJsOriginalValue } from './getZoneJsOriginalValue';
1
3
  var ArrayProto = Array.prototype;
2
4
  var FuncProto = Function.prototype;
3
5
  var ObjProto = Object.prototype;
@@ -386,49 +388,42 @@ export var getScreenOrientation = function getScreenOrientation() {
386
388
  export var now = Date.now || function () {
387
389
  return new Date().getTime();
388
390
  };
389
- export var throttle = function throttle(func, wait, options) {
390
- var timeout, context, args, result;
391
- var previous = 0;
392
- if (!options) options = {};
393
-
394
- var later = function later() {
395
- previous = options.leading === false ? 0 : new Date().getTime();
396
- timeout = null;
397
- result = func.apply(context, args);
398
- if (!timeout) context = args = null;
399
- };
400
-
401
- var throttled = function throttled() {
402
- args = arguments;
403
- var now = new Date().getTime();
404
- if (!previous && options.leading === false) previous = now; //下次触发 func 剩余的时间
405
-
406
- var remaining = wait - (now - previous);
407
- context = this; // 如果没有剩余的时间了或者你改了系统时间
408
-
409
- if (remaining <= 0 || remaining > wait) {
410
- if (timeout) {
411
- clearTimeout(timeout);
412
- timeout = null;
391
+ export var throttle = function throttle(fn, wait, options) {
392
+ var needLeadingExecution = options && options.leading !== undefined ? options.leading : true;
393
+ var needTrailingExecution = options && options.trailing !== undefined ? options.trailing : true;
394
+ var inWaitPeriod = false;
395
+ var pendingExecutionWithParameters;
396
+ var pendingTimeoutId;
397
+ var context = this;
398
+ return {
399
+ throttled: function throttled() {
400
+ if (inWaitPeriod) {
401
+ pendingExecutionWithParameters = arguments;
402
+ return;
413
403
  }
414
404
 
415
- previous = now;
416
- result = func.apply(context, args);
417
- if (!timeout) context = args = null;
418
- } else if (!timeout && options.trailing !== false) {
419
- timeout = setTimeout(later, remaining);
420
- }
405
+ if (needLeadingExecution) {
406
+ fn.apply(context, arguments);
407
+ } else {
408
+ pendingExecutionWithParameters = arguments;
409
+ }
421
410
 
422
- return result;
423
- };
411
+ inWaitPeriod = true;
412
+ pendingTimeoutId = setTimeout(function () {
413
+ if (needTrailingExecution && pendingExecutionWithParameters) {
414
+ fn.apply(context, pendingExecutionWithParameters);
415
+ }
424
416
 
425
- throttled.cancel = function () {
426
- clearTimeout(timeout);
427
- previous = 0;
428
- timeout = null;
417
+ inWaitPeriod = false;
418
+ pendingExecutionWithParameters = undefined;
419
+ }, wait);
420
+ },
421
+ cancel: function cancel() {
422
+ clearTimeout(pendingTimeoutId);
423
+ inWaitPeriod = false;
424
+ pendingExecutionWithParameters = undefined;
425
+ }
429
426
  };
430
-
431
- return throttled;
432
427
  };
433
428
  export var hashCode = function hashCode(str) {
434
429
  if (typeof str !== 'string') {
@@ -1661,6 +1656,9 @@ export function currentDrift() {
1661
1656
  // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
1662
1657
  return Math.round(dateNow() - (getNavigationStart() + performance.now()));
1663
1658
  }
1659
+ export function addDuration(a, b) {
1660
+ return a + b;
1661
+ }
1664
1662
 
1665
1663
  function getCorrectedTimeStamp(relativeTime) {
1666
1664
  var correctedOrigin = dateNow() - performance.now(); // apply correction only for positive drift
@@ -1712,8 +1710,8 @@ export function safeTruncate(candidate, length) {
1712
1710
 
1713
1711
  return candidate.slice(0, length);
1714
1712
  }
1715
- export function addEventListener(emitter, event, listener, options) {
1716
- return addEventListeners(emitter, [event], listener, options);
1713
+ export function addEventListener(eventTarget, event, listener, options) {
1714
+ return addEventListeners(eventTarget, [event], listener, options);
1717
1715
  }
1718
1716
  /**
1719
1717
  * Add event listeners to an event emitter object (Window, Element, mock object...). This provides
@@ -1731,8 +1729,8 @@ export function addEventListener(emitter, event, listener, options) {
1731
1729
  * listened
1732
1730
  */
1733
1731
 
1734
- export function addEventListeners(emitter, events, listener, options) {
1735
- var wrapedListener = options && options.once ? function (event) {
1732
+ export function addEventListeners(eventTarget, events, listener, options) {
1733
+ var wrappedListener = options && options.once ? function (event) {
1736
1734
  stop();
1737
1735
  listener(event);
1738
1736
  } : listener;
@@ -1740,13 +1738,15 @@ export function addEventListeners(emitter, events, listener, options) {
1740
1738
  capture: options.capture,
1741
1739
  passive: options.passive
1742
1740
  } : options && options.capture;
1741
+ var add = getZoneJsOriginalValue(eventTarget, 'addEventListener');
1743
1742
  each(events, function (event) {
1744
- emitter.addEventListener(event, wrapedListener, options);
1743
+ add.call(eventTarget, event, wrappedListener, options);
1745
1744
  });
1746
1745
 
1747
1746
  var stop = function stop() {
1747
+ var remove = getZoneJsOriginalValue(eventTarget, 'removeEventListener');
1748
1748
  each(events, function (event) {
1749
- emitter.removeEventListener(event, wrapedListener, options);
1749
+ remove.call(eventTarget, event, wrappedListener, options);
1750
1750
  });
1751
1751
  };
1752
1752
 
@@ -1909,7 +1909,7 @@ export function escapeJsonValue(value) {
1909
1909
  }
1910
1910
  }
1911
1911
  export function escapeFieldValueStr(str) {
1912
- return '"' + str.replace(/[\\]*"/g, '"').replace(/"/g, '\\"').replace(/\\/g, '\\\\') + '"';
1912
+ return '"' + str.replace(/\\/g, '\\\\').replace(/[\\]*"/g, '"').replace(/"/g, '\\"') + '"';
1913
1913
  }
1914
1914
  export function escapeRowField(value) {
1915
1915
  if (typeof value === 'object' && value) {
@@ -1926,4 +1926,59 @@ export function isNullUndefinedDefaultValue(data, defaultValue) {
1926
1926
  } else {
1927
1927
  return defaultValue;
1928
1928
  }
1929
+ }
1930
+ export function runOnReadyState(expectedReadyState, callback) {
1931
+ if (document.readyState === expectedReadyState || document.readyState === 'complete') {
1932
+ callback();
1933
+ } else {
1934
+ var eventName = expectedReadyState === 'complete' ? DOM_EVENT.LOAD : DOM_EVENT.DOM_CONTENT_LOADED;
1935
+ addEventListener(window, eventName, callback, {
1936
+ once: true
1937
+ });
1938
+ }
1939
+ }
1940
+ export function requestIdleCallback(callback, opts) {
1941
+ // Use 'requestIdleCallback' when available: it will throttle the mutation processing if the
1942
+ // browser is busy rendering frames (ex: when frames are below 60fps). When not available, the
1943
+ // fallback on 'requestAnimationFrame' will still ensure the mutations are processed after any
1944
+ // browser rendering process (Layout, Recalculate Style, etc.), so we can serialize DOM nodes
1945
+ // efficiently.
1946
+ if (window.requestIdleCallback) {
1947
+ var id = window.requestIdleCallback(callback, opts);
1948
+ return function () {
1949
+ return window.cancelIdleCallback(id);
1950
+ };
1951
+ }
1952
+
1953
+ var id = window.requestAnimationFrame(callback);
1954
+ return function () {
1955
+ return window.cancelAnimationFrame(id);
1956
+ };
1957
+ }
1958
+ export function objectHasValue(object, value) {
1959
+ return some(keys(object), function (key) {
1960
+ return object[key] === value;
1961
+ });
1962
+ }
1963
+ export function startsWith(candidate, search) {
1964
+ return candidate.slice(0, search.length) === search;
1965
+ }
1966
+ export function endsWith(candidate, search) {
1967
+ return candidate.slice(-search.length) === search;
1968
+ }
1969
+ export function tryToClone(response) {
1970
+ try {
1971
+ return response.clone();
1972
+ } catch (e) {
1973
+ // clone can throw if the response has already been used by another instrumentation or is disturbed
1974
+ return;
1975
+ }
1976
+ }
1977
+ export function isHashAnAnchor(hash) {
1978
+ var correspondingId = hash.substr(1);
1979
+ return !!document.getElementById(correspondingId);
1980
+ }
1981
+ export function getPathFromHash(hash) {
1982
+ var index = hash.indexOf('?');
1983
+ return index < 0 ? hash : hash.slice(0, index);
1929
1984
  }
package/esm/index.js CHANGED
@@ -16,12 +16,16 @@ export * from './helper/observable';
16
16
  export * from './helper/tools';
17
17
  export * from './helper/urlPolyfill';
18
18
  export * from './helper/mobileUtil';
19
+ export * from './helper/getZoneJsOriginalValue';
20
+ export * from './helper/readBytesFromStream';
19
21
  export * from './tracekit';
20
22
  export * from './configuration/configuration';
21
23
  export * from './configuration/transportConfiguration';
22
24
  export * from './browser/cookie';
23
25
  export * from './browser/fetchObservable';
24
26
  export * from './browser/xhrObservable';
27
+ export * from './browser/pageExitObservable';
28
+ export * from './browser/htmlDomUtils';
25
29
  export * from './dataMap';
26
30
  export * from './init';
27
31
  export * from './session/sessionManagement';
@@ -125,7 +125,7 @@ export function startSessionStore(options, productKey, computeSessionState) {
125
125
  }
126
126
 
127
127
  return {
128
- expandOrRenewSession: throttle(expandOrRenewSession, COOKIE_ACCESS_DELAY),
128
+ expandOrRenewSession: throttle(expandOrRenewSession, COOKIE_ACCESS_DELAY).throttled,
129
129
  expandSession: expandSession,
130
130
  getSession: function getSession() {
131
131
  return sessionCache;
@@ -1,6 +1,6 @@
1
1
  import { display } from '../helper/display';
2
2
  import { addEventListener, noop, values, findByPath, escapeRowData, each, isNumber, isArray, extend, isString, toServerDuration, isBoolean, isEmptyObject, isObject, escapeJsonValue, escapeRowField } from '../helper/tools';
3
- import { commonTags, dataMap } from '../dataMap';
3
+ import { commonTags, dataMap, commonFields } from '../dataMap';
4
4
  import { DOM_EVENT, RumEventType } from '../helper/enums'; // https://en.wikipedia.org/wiki/UTF-8
5
5
  // eslint-disable-next-line no-control-regex
6
6
 
@@ -36,7 +36,8 @@ export var processedMessageByDataMap = function processedMessageByDataMap(messag
36
36
  }
37
37
  });
38
38
  var fieldsStr = [];
39
- each(value.fields, function (_value, _key) {
39
+ var fields = extend({}, commonFields, value.fields);
40
+ each(fields, function (_value, _key) {
40
41
  if (isArray(_value) && _value.length === 2) {
41
42
  var type = _value[0],
42
43
  value_path = _value[1];
@@ -123,7 +124,7 @@ export var processedMessageByDataMap = function processedMessageByDataMap(messag
123
124
  };
124
125
  };
125
126
 
126
- var batch = function batch(request, batchMessagesLimit, batchBytesLimit, messageBytesLimit, flushTimeout, beforeUnloadCallback) {
127
+ var batch = function batch(request, batchMessagesLimit, batchBytesLimit, messageBytesLimit, flushTimeout, pageExitObservable) {
127
128
  this.pushOnlyBuffer = [];
128
129
  this.upsertBuffer = {};
129
130
  this.bufferBytesCount = 0;
@@ -134,13 +135,11 @@ var batch = function batch(request, batchMessagesLimit, batchBytesLimit, message
134
135
  this.messageBytesLimit = messageBytesLimit;
135
136
  this.flushTimeout = flushTimeout;
136
137
 
137
- if (typeof beforeUnloadCallback === 'function') {
138
- this.beforeUnloadCallback = beforeUnloadCallback;
139
- } else {
140
- this.beforeUnloadCallback = noop;
141
- }
138
+ var _this = this;
142
139
 
143
- this.setupFlushOnExit();
140
+ pageExitObservable.subscribe(function () {
141
+ _this.flush(_this.request.sendOnExit);
142
+ });
144
143
  this.flushPeriodically();
145
144
  };
146
145
 
@@ -277,40 +276,4 @@ batch.prototype.flushPeriodically = function () {
277
276
  }, this.flushTimeout);
278
277
  };
279
278
 
280
- batch.prototype.setupFlushOnExit = function () {
281
- /**
282
- * With sendBeacon, requests are guaranteed to be successfully sent during document unload
283
- */
284
- // @ts-ignore this function is not always defined
285
- var _this = this;
286
-
287
- if (navigator.sendBeacon) {
288
- /**
289
- * beforeunload is called before visibilitychange
290
- * register first to be sure to be called before flush on beforeunload
291
- * caveat: unload can still be canceled by another listener
292
- */
293
- addEventListener(window, DOM_EVENT.BEFORE_UNLOAD, this.beforeUnloadCallback);
294
- /**
295
- * Only event that guarantee to fire on mobile devices when the page transitions to background state
296
- * (e.g. when user switches to a different application, goes to homescreen, etc), or is being unloaded.
297
- */
298
-
299
- addEventListener(document, DOM_EVENT.VISIBILITY_CHANGE, function () {
300
- if (document.visibilityState === 'hidden') {
301
- _this.flushOnExit();
302
- }
303
- });
304
- /**
305
- * Safari does not support yet to send a request during:
306
- * - a visibility change during doc unload (cf: https://bugs.webkit.org/show_bug.cgi?id=194897)
307
- * - a page hide transition (cf: https://bugs.webkit.org/show_bug.cgi?id=188329)
308
- */
309
-
310
- addEventListener(window, DOM_EVENT.BEFORE_UNLOAD, function () {
311
- return _this.flushOnExit();
312
- });
313
- }
314
- };
315
-
316
279
  export var Batch = batch;
@@ -65,11 +65,13 @@ export function fetchKeepAliveStrategy(endpointUrl, bytesLimit, payload, onRespo
65
65
  fetch(url, {
66
66
  method: 'POST',
67
67
  body: data,
68
- keepalive: true
68
+ keepalive: true,
69
+ mode: 'cors'
69
70
  }).then(function (response) {
70
71
  if (typeof onResponse === 'function') {
71
72
  onResponse({
72
- status: response.status
73
+ status: response.status,
74
+ type: response.type
73
75
  });
74
76
  }
75
77
  }, function () {
@@ -6,13 +6,13 @@ export var MAX_QUEUE_BYTES_COUNT = 3 * ONE_MEBI_BYTE;
6
6
  export var MAX_BACKOFF_TIME = 256 * ONE_SECOND;
7
7
  export var INITIAL_BACKOFF_TIME = ONE_SECOND;
8
8
  var TransportStatus = {
9
- UP: 'UP',
10
- FAILURE_DETECTED: 'FAILURE_DETECTED',
11
- DOWN: 'DOWN'
9
+ UP: 0,
10
+ FAILURE_DETECTED: 1,
11
+ DOWN: 2
12
12
  };
13
13
  var RetryReason = {
14
- AFTER_SUCCESS: 'AFTER_SUCCESS',
15
- AFTER_RESUME: 'AFTER_RESUME'
14
+ AFTER_SUCCESS: 0,
15
+ AFTER_RESUME: 1
16
16
  };
17
17
  export function sendWithRetryStrategy(payload, state, sendStrategy, reportError) {
18
18
  if (state.transportStatus === TransportStatus.UP && state.queuedPayloads.size() === 0 && state.bandwidthMonitor.canHandle(payload)) {
@@ -63,7 +63,7 @@ function send(payload, state, sendStrategy, responseData) {
63
63
  sendStrategy(payload, function (response) {
64
64
  state.bandwidthMonitor.remove(payload);
65
65
 
66
- if (wasRequestSuccessful(response)) {
66
+ if (!shouldRetryRequest(response)) {
67
67
  state.transportStatus = TransportStatus.UP;
68
68
  onSuccess();
69
69
  } else {
@@ -93,8 +93,8 @@ function retryQueuedPayloads(reason, state, sendStrategy, reportError) {
93
93
  }
94
94
  }
95
95
 
96
- function wasRequestSuccessful(response) {
97
- return response.status !== 0 && response.status < 500;
96
+ function shouldRetryRequest(response) {
97
+ return response.type !== 'opaque' && (response.status === 0 && !navigator.onLine || response.status === 408 || response.status === 429 || response.status >= 500);
98
98
  }
99
99
 
100
100
  export function newRetryState() {
@@ -1,10 +1,10 @@
1
1
  import { Batch } from './batch';
2
2
  import { createHttpRequest } from './httpRequest';
3
- export function startBatchWithReplica(configuration, endpointUrl, reportError) {
3
+ export function startBatchWithReplica(configuration, endpointUrl, reportError, pageExitObservable) {
4
4
  var primaryBatch = createBatch(endpointUrl);
5
5
 
6
6
  function createBatch(endpointUrl) {
7
- return new Batch(createHttpRequest(endpointUrl, configuration.batchBytesLimit, reportError), configuration.batchMessagesLimit, configuration.batchBytesLimit, configuration.messageBytesLimit, configuration.flushTimeout);
7
+ return new Batch(createHttpRequest(endpointUrl, configuration.batchBytesLimit, reportError), configuration.batchMessagesLimit, configuration.batchBytesLimit, configuration.messageBytesLimit, configuration.flushTimeout, pageExitObservable);
8
8
  }
9
9
 
10
10
  return {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cloudcare/browser-core",
3
- "version": "1.2.9",
3
+ "version": "2.0.0",
4
4
  "main": "cjs/index.js",
5
5
  "module": "esm/index.js",
6
6
  "scripts": {
@@ -20,5 +20,5 @@
20
20
  "author": "dataflux",
21
21
  "license": "MIT",
22
22
  "description": "DataFlux RUM Web 端数据指标监控",
23
- "gitHead": "9a15e3d36ff76e9bd1830516743fb8299ce6829b"
23
+ "gitHead": "bc7a044056367a5f9a0bc941462cb4e1d4d1d925"
24
24
  }