@cloudcare/browser-core 1.2.11 → 2.0.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.
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 +123 -46
  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 +99 -44
  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 +112 -43
  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
@@ -70,21 +70,20 @@ function beforeSend(observable, input, init) {
70
70
  function afterSend(observable, responsePromise, startContext) {
71
71
  var reportFetch = function reportFetch(response) {
72
72
  var context = startContext;
73
- context.state = 'complete';
74
- context.duration = (0, _tools.elapsed)(context.startClocks.timeStamp, (0, _tools.timeStampNow)());
73
+ context.state = 'resolve'; // context.duration = elapsed(context.startClocks.timeStamp, timeStampNow())
75
74
 
76
75
  if ('stack' in response || response instanceof Error) {
77
76
  context.status = 0;
78
77
  context.isAborted = response instanceof DOMException && response.code === DOMException.ABORT_ERR;
79
78
  context.error = response;
80
- observable.notify(context);
81
79
  } else if ('status' in response) {
82
80
  context.response = response;
83
81
  context.responseType = response.type;
84
82
  context.status = response.status;
85
83
  context.isAborted = false;
86
- observable.notify(context);
87
84
  }
85
+
86
+ observable.notify(context);
88
87
  };
89
88
 
90
89
  responsePromise.then(reportFetch, reportFetch);
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getChildNodes = getChildNodes;
7
+ exports.getParentNode = getParentNode;
8
+ exports.isCommentNode = isCommentNode;
9
+ exports.isElementNode = isElementNode;
10
+ exports.isNodeShadowHost = isNodeShadowHost;
11
+ exports.isNodeShadowRoot = isNodeShadowRoot;
12
+ exports.isTextNode = isTextNode;
13
+
14
+ function isTextNode(node) {
15
+ return node.nodeType === Node.TEXT_NODE;
16
+ }
17
+
18
+ function isCommentNode(node) {
19
+ return node.nodeType === Node.COMMENT_NODE;
20
+ }
21
+
22
+ function isElementNode(node) {
23
+ return node.nodeType === Node.ELEMENT_NODE;
24
+ }
25
+
26
+ function isNodeShadowHost(node) {
27
+ return isElementNode(node) && Boolean(node.shadowRoot);
28
+ }
29
+
30
+ function isNodeShadowRoot(node) {
31
+ var shadowRoot = node;
32
+ return !!shadowRoot.host && shadowRoot.nodeType === Node.DOCUMENT_FRAGMENT_NODE && isElementNode(shadowRoot.host);
33
+ }
34
+
35
+ function getChildNodes(node) {
36
+ return isNodeShadowHost(node) ? node.shadowRoot.childNodes : node.childNodes;
37
+ }
38
+ /**
39
+ * Return `host` in case if the current node is a shadow root otherwise will return the `parentNode`
40
+ */
41
+
42
+
43
+ function getParentNode(node) {
44
+ return isNodeShadowRoot(node) ? node.host : node.parentNode;
45
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PageExitReason = void 0;
7
+ exports.createPageExitObservable = createPageExitObservable;
8
+ exports.isPageExitReason = isPageExitReason;
9
+
10
+ var _observable = require("../helper/observable");
11
+
12
+ var _tools = require("../helper/tools");
13
+
14
+ var _enums = require("../helper/enums");
15
+
16
+ var PageExitReason = {
17
+ HIDDEN: 'visibility_hidden',
18
+ UNLOADING: 'before_unload',
19
+ PAGEHIDE: 'page_hide',
20
+ FROZEN: 'page_frozen'
21
+ };
22
+ exports.PageExitReason = PageExitReason;
23
+
24
+ function createPageExitObservable() {
25
+ var observable = new _observable.Observable(function () {
26
+ /**
27
+ * Only event that guarantee to fire on mobile devices when the page transitions to background state
28
+ * (e.g. when user switches to a different application, goes to homescreen, etc), or is being unloaded.
29
+ */
30
+ var visibilityChangeListener = (0, _tools.addEventListeners)(document, [_enums.DOM_EVENT.VISIBILITY_CHANGE, _enums.DOM_EVENT.FREEZE, _enums.DOM_EVENT.PAGE_HIDE], function (event) {
31
+ if (event.type === _enums.DOM_EVENT.VISIBILITY_CHANGE && document.visibilityState === 'hidden') {
32
+ /**
33
+ * Only event that guarantee to fire on mobile devices when the page transitions to background state
34
+ * (e.g. when user switches to a different application, goes to homescreen, etc), or is being unloaded.
35
+ */
36
+ observable.notify({
37
+ reason: PageExitReason.HIDDEN
38
+ });
39
+ } else if (event.type === _enums.DOM_EVENT.FREEZE) {
40
+ /**
41
+ * After transitioning in background a tab can be freezed to preserve resources. (cf: https://developer.chrome.com/blog/page-lifecycle-api)
42
+ * Allow to collect events happening between hidden and frozen state.
43
+ */
44
+ observable.notify({
45
+ reason: PageExitReason.FROZEN
46
+ });
47
+ }
48
+ }, {
49
+ capture: true
50
+ });
51
+ /**
52
+ * Safari does not support yet to send a request during:
53
+ * - a visibility change during doc unload (cf: https://bugs.webkit.org/show_bug.cgi?id=194897)
54
+ * - a page hide transition (cf: https://bugs.webkit.org/show_bug.cgi?id=188329)
55
+ */
56
+
57
+ var beforeUnloadListener = (0, _tools.addEventListener)(window, _enums.DOM_EVENT.BEFORE_UNLOAD, function () {
58
+ observable.notify({
59
+ reason: PageExitReason.UNLOADING
60
+ });
61
+ });
62
+ return function () {
63
+ visibilityChangeListener.stop();
64
+ beforeUnloadListener.stop();
65
+ };
66
+ });
67
+ return observable;
68
+ }
69
+
70
+ function isPageExitReason(reason) {
71
+ return (0, _tools.includes)((0, _tools.values)(PageExitReason), reason);
72
+ }
@@ -3,6 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
+ exports.DefaultPrivacyLevel = void 0;
6
7
  exports.buildCookieOptions = buildCookieOptions;
7
8
  exports.validateAndBuildConfiguration = validateAndBuildConfiguration;
8
9
 
@@ -16,6 +17,13 @@ var _tools = require("../helper/tools");
16
17
 
17
18
  var _transportConfiguration = require("./transportConfiguration");
18
19
 
20
+ var DefaultPrivacyLevel = {
21
+ ALLOW: 'allow',
22
+ MASK: 'mask',
23
+ MASK_USER_INPUT: 'mask-user-input'
24
+ };
25
+ exports.DefaultPrivacyLevel = DefaultPrivacyLevel;
26
+
19
27
  function validateAndBuildConfiguration(initConfiguration) {
20
28
  if (initConfiguration.sampleRate !== undefined && !(0, _tools.isPercentage)(initConfiguration.sampleRate)) {
21
29
  _display.display.error('Sample Rate should be a number between 0 and 100');
@@ -24,6 +24,12 @@ function getLogsEndPoint(url) {
24
24
  return trim(url) + '/v1/write/logging';
25
25
  }
26
26
 
27
+ function getSessionReplayEndPoint(url) {
28
+ // return 'http://localhost:3002/write_data'
29
+ if (url.lastIndexOf('/') === url.length - 1) return trim(url) + 'v1/write/rum/replay';
30
+ return trim(url) + '/v1/write/rum/replay';
31
+ }
32
+
27
33
  function computeTransportConfiguration(initConfiguration) {
28
34
  var isIntakeUrl = function isIntakeUrl(url) {
29
35
  return false;
@@ -44,6 +50,7 @@ function computeTransportConfiguration(initConfiguration) {
44
50
  return {
45
51
  datakitUrl: getDatakitUrl(initConfiguration.datakitUrl || initConfiguration.datakitOrigin),
46
52
  logsEndpoint: getLogsEndPoint(initConfiguration.datakitOrigin),
53
+ sessionReplayEndPoint: getSessionReplayEndPoint(initConfiguration.datakitOrigin),
47
54
  isIntakeUrl: isIntakeUrl,
48
55
  isServerError: isServerError
49
56
  };
package/cjs/dataMap.js CHANGED
@@ -3,12 +3,11 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.dataMap = exports.commonTags = void 0;
6
+ exports.dataMap = exports.commonTags = exports.commonFields = void 0;
7
7
 
8
8
  var _enums = require("./helper/enums");
9
9
 
10
10
  var commonTags = {
11
- action_id: 'action.id',
12
11
  sdk_name: '_dd.sdk_name',
13
12
  sdk_version: '_dd.sdk_version',
14
13
  app_id: 'application.id',
@@ -21,6 +20,7 @@ var commonTags = {
21
20
  session_id: 'session.id',
22
21
  session_type: 'session.type',
23
22
  session_sampling: 'session.is_sampling',
23
+ session_has_replay: 'session.has_replay',
24
24
  is_signin: 'user.is_signin',
25
25
  os: 'device.os',
26
26
  os_version: 'device.os_version',
@@ -40,9 +40,14 @@ var commonTags = {
40
40
  // 冗余一个字段
41
41
  view_path_group: 'view.path_group',
42
42
  view_url_query: 'view.url_query'
43
+ };
44
+ exports.commonTags = commonTags;
45
+ var commonFields = {
46
+ action_id: 'action.id',
47
+ view_in_foreground: 'view.in_foreground'
43
48
  }; // 需要用双引号将字符串类型的field value括起来, 这里有数组标示[string, path]
44
49
 
45
- exports.commonTags = commonTags;
50
+ exports.commonFields = commonFields;
46
51
  var dataMap = {
47
52
  view: {
48
53
  type: _enums.RumEventType.VIEW,
@@ -52,6 +57,7 @@ var dataMap = {
52
57
  is_active: 'view.is_active'
53
58
  },
54
59
  fields: {
60
+ session_replay_stats: '_dd.replay_stats',
55
61
  view_error_count: 'view.error.count',
56
62
  view_resource_count: 'view.resource.count',
57
63
  view_long_task_count: 'view.long_task.count',
@@ -72,7 +78,9 @@ var dataMap = {
72
78
  time_to_interactive: 'view.tti',
73
79
  dom: 'view.dom',
74
80
  dom_ready: 'view.dom_ready',
75
- time_spent: 'view.time_spent'
81
+ time_spent: 'view.time_spent',
82
+ in_foreground_periods: 'view.in_foreground_periods',
83
+ frustration_count: 'view.frustration.count'
76
84
  }
77
85
  },
78
86
  resource: {
@@ -196,8 +196,50 @@ var MethodLibrary = {
196
196
  },
197
197
  // 获取网络状态
198
198
  getNetwork: function getNetwork() {
199
- var netWork = navigator && navigator.connection && navigator.connection.effectiveType;
200
- return netWork;
199
+ var connection = window.navigator.connection || window.navigator.mozConnection || window.navigator.webkitConnection;
200
+ var result = 'unknown';
201
+ var type = connection ? connection.type || connection.effectiveType : null;
202
+
203
+ if (type && typeof type === 'string') {
204
+ switch (type) {
205
+ // possible type values
206
+ case 'bluetooth':
207
+ case 'cellular':
208
+ result = 'cellular';
209
+ break;
210
+
211
+ case 'none':
212
+ result = 'none';
213
+ break;
214
+
215
+ case 'ethernet':
216
+ case 'wifi':
217
+ case 'wimax':
218
+ result = 'wifi';
219
+ break;
220
+
221
+ case 'other':
222
+ case 'unknown':
223
+ result = 'unknown';
224
+ break;
225
+ // possible effectiveType values
226
+
227
+ case 'slow-2g':
228
+ case '2g':
229
+ case '3g':
230
+ result = 'cellular';
231
+ break;
232
+
233
+ case '4g':
234
+ result = 'wifi';
235
+ break;
236
+
237
+ default:
238
+ break;
239
+ }
240
+ }
241
+
242
+ return result;
201
243
  },
202
244
  // 获取当前语言
203
245
  getLanguage: function getLanguage() {
@@ -16,6 +16,9 @@ var DOM_EVENT = {
16
16
  TOUCH_END: 'touchend',
17
17
  TOUCH_MOVE: 'touchmove',
18
18
  VISIBILITY_CHANGE: 'visibilitychange',
19
+ PAGE_SHOW: 'pageshow',
20
+ FREEZE: 'freeze',
21
+ RESUME: 'resume',
19
22
  DOM_CONTENT_LOADED: 'DOMContentLoaded',
20
23
  POINTER_DOWN: 'pointerdown',
21
24
  POINTER_UP: 'pointerup',
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getZoneJsOriginalValue = getZoneJsOriginalValue;
7
+
8
+ /**
9
+ * Gets the original value for a DOM API that was potentially patched by Zone.js.
10
+ *
11
+ * Zone.js[1] is a library that patches a bunch of JS and DOM APIs. It usually stores the original
12
+ * value of the patched functions/constructors/methods in a hidden property prefixed by
13
+ * __zone_symbol__.
14
+ *
15
+ * In multiple occasions, we observed that Zone.js is the culprit of important issues leading to
16
+ * browser resource exhaustion (memory leak, high CPU usage). This method is used as a workaround to
17
+ * use the original DOM API instead of the one patched by Zone.js.
18
+ *
19
+ * [1]: https://github.com/angular/angular/tree/main/packages/zone.js
20
+ */
21
+ function getZoneJsOriginalValue(target, name) {
22
+ var browserWindow = window;
23
+ var original;
24
+
25
+ if (browserWindow.Zone && typeof browserWindow.Zone.__symbol__ === 'function') {
26
+ original = target[browserWindow.Zone.__symbol__(name)];
27
+ }
28
+
29
+ if (!original) {
30
+ original = target[name];
31
+ }
32
+
33
+ return original;
34
+ }
@@ -9,6 +9,8 @@ exports.instrumentSetter = instrumentSetter;
9
9
 
10
10
  var _tools = require("./tools");
11
11
 
12
+ var _getZoneJsOriginalValue = require("./getZoneJsOriginalValue");
13
+
12
14
  function instrumentMethod(object, method, instrumentationFactory) {
13
15
  var original = object[method];
14
16
  var instrumentation = instrumentationFactory(original);
@@ -64,7 +66,11 @@ function instrumentSetter(object, property, after) {
64
66
  return {
65
67
  stop: _tools.noop
66
68
  };
67
- }
69
+ } // Using the patched `setTimeout` from Zone.js triggers a rendering loop in some Angular
70
+ // component, see issue RUMF-1443
71
+
72
+
73
+ var setTimeout = (0, _getZoneJsOriginalValue.getZoneJsOriginalValue)(window, 'setTimeout');
68
74
 
69
75
  var instrumentation = function instrumentation(thisObject, value) {
70
76
  // put hooked setter into event loop to avoid of set latency
@@ -10,29 +10,25 @@ var _tools = require("./tools");
10
10
 
11
11
  var LifeCycleEventType = {
12
12
  PERFORMANCE_ENTRIES_COLLECTED: 'PERFORMANCE_ENTRIES_COLLECTED',
13
- AUTO_ACTION_CREATED: 'AUTO_ACTION_CREATED',
14
13
  AUTO_ACTION_COMPLETED: 'AUTO_ACTION_COMPLETED',
15
14
  VIEW_CREATED: 'VIEW_CREATED',
16
15
  VIEW_UPDATED: 'VIEW_UPDATED',
17
16
  VIEW_ENDED: 'VIEW_ENDED',
18
17
  SESSION_RENEWED: 'SESSION_RENEWED',
19
18
  SESSION_EXPIRED: 'SESSION_EXPIRED',
20
- DOM_MUTATED: 'DOM_MUTATED',
21
- BEFORE_UNLOAD: 'BEFORE_UNLOAD',
19
+ PAGE_EXITED: 'PAGE_EXITED',
22
20
  REQUEST_STARTED: 'REQUEST_STARTED',
23
21
  REQUEST_COMPLETED: 'REQUEST_COMPLETED',
24
22
  RAW_RUM_EVENT_COLLECTED: 'RAW_RUM_EVENT_COLLECTED',
25
23
  RUM_EVENT_COLLECTED: 'RUM_EVENT_COLLECTED',
26
24
  RAW_ERROR_COLLECTED: 'RAW_ERROR_COLLECTED',
27
- RECORD_STARTED: 'RECORD_STARTED',
28
- RECORD_STOPPED: 'RECORD_STOPPED',
29
25
  RAW_LOG_COLLECTED: 'RAW_LOG_COLLECTED',
30
26
  LOG_COLLECTED: 'LOG_COLLECTED'
31
27
  };
32
28
  exports.LifeCycleEventType = LifeCycleEventType;
33
29
 
34
30
  function LifeCycle() {
35
- this.callbacks = [];
31
+ this.callbacks = {};
36
32
  }
37
33
 
38
34
  LifeCycle.prototype = {
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.readBytesFromStream = readBytesFromStream;
7
+
8
+ var _tools = require("./tools");
9
+
10
+ /**
11
+ * Read bytes from a ReadableStream until at least `limit` bytes have been read (or until the end of
12
+ * the stream). The callback is invoked with the at most `limit` bytes, and indicates that the limit
13
+ * has been exceeded if more bytes were available.
14
+ */
15
+ function readBytesFromStream(stream, callback, options) {
16
+ var reader = stream.getReader();
17
+ var chunks = [];
18
+ var readBytesCount = 0;
19
+ readMore();
20
+
21
+ function readMore() {
22
+ reader.read().then(function (result) {
23
+ if (result.done) {
24
+ onDone();
25
+ return;
26
+ }
27
+
28
+ if (options.collectStreamBody) {
29
+ chunks.push(result.value);
30
+ }
31
+
32
+ readBytesCount += result.value.length;
33
+
34
+ if (readBytesCount > options.bytesLimit) {
35
+ onDone();
36
+ } else {
37
+ readMore();
38
+ }
39
+ }, function (error) {
40
+ callback(error);
41
+ });
42
+ }
43
+
44
+ function onDone() {
45
+ reader.cancel()["catch"]( // we don't care if cancel fails, but we still need to catch the error to avoid reporting it
46
+ // as an unhandled rejection
47
+ _tools.noop);
48
+ var bytes;
49
+ var limitExceeded;
50
+
51
+ if (options.collectStreamBody) {
52
+ var completeBuffer;
53
+
54
+ if (chunks.length === 1) {
55
+ // optimization: if the response is small enough to fit in a single buffer (provided by the browser), just
56
+ // use it directly.
57
+ completeBuffer = chunks[0];
58
+ } else {
59
+ // else, we need to copy buffers into a larger buffer to concatenate them.
60
+ completeBuffer = new Uint8Array(readBytesCount);
61
+ var offset = 0;
62
+ (0, _tools.each)(chunks, function (chunk) {
63
+ completeBuffer.set(chunk, offset);
64
+ offset += chunk.length;
65
+ });
66
+ }
67
+
68
+ bytes = completeBuffer.slice(0, options.bytesLimit);
69
+ limitExceeded = completeBuffer.length > options.bytesLimit;
70
+ }
71
+
72
+ callback(undefined, bytes, limitExceeded);
73
+ }
74
+ }