@newrelic/browser-agent 1.262.0 → 1.264.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 (259) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +2 -2
  3. package/dist/cjs/cdn/experimental.js +3 -7
  4. package/dist/cjs/cdn/pro.js +2 -2
  5. package/dist/cjs/cdn/spa.js +2 -2
  6. package/dist/cjs/common/aggregate/aggregator.js +3 -3
  7. package/dist/cjs/common/config/state/configurable.js +4 -4
  8. package/dist/cjs/common/config/state/init.js +11 -6
  9. package/dist/cjs/common/constants/env.cdn.js +1 -1
  10. package/dist/cjs/common/constants/env.npm.js +1 -1
  11. package/dist/cjs/common/constants/runtime.js +1 -3
  12. package/dist/cjs/common/context/shared-context.js +2 -2
  13. package/dist/cjs/common/drain/drain.js +5 -5
  14. package/dist/cjs/common/harvest/harvest.js +3 -3
  15. package/dist/cjs/common/serialize/bel-serializer.js +2 -2
  16. package/dist/cjs/common/session/session-entity.js +3 -3
  17. package/dist/cjs/common/timing/time-keeper.js +13 -2
  18. package/dist/cjs/common/url/encode.js +3 -5
  19. package/dist/cjs/common/util/console.js +3 -4
  20. package/dist/cjs/common/util/obfuscate.js +3 -3
  21. package/dist/cjs/common/util/submit-data.js +0 -1
  22. package/dist/cjs/common/vitals/vital-metric.js +1 -1
  23. package/dist/cjs/common/wrap/wrap-logger.js +1 -2
  24. package/dist/cjs/common/wrap/wrap-xhr.js +1 -1
  25. package/dist/cjs/features/ajax/aggregate/index.js +1 -1
  26. package/dist/cjs/features/ajax/instrument/index.js +1 -1
  27. package/dist/cjs/features/generic_events/aggregate/index.js +137 -0
  28. package/dist/cjs/features/generic_events/constants.js +8 -0
  29. package/dist/cjs/features/generic_events/index.js +12 -0
  30. package/dist/cjs/features/generic_events/instrument/index.js +27 -0
  31. package/dist/cjs/features/jserrors/aggregate/index.js +13 -12
  32. package/dist/cjs/features/jserrors/instrument/index.js +1 -1
  33. package/dist/cjs/features/logging/aggregate/index.js +6 -6
  34. package/dist/cjs/features/logging/constants.js +2 -5
  35. package/dist/cjs/features/logging/instrument/index.js +1 -1
  36. package/dist/cjs/features/metrics/aggregate/index.js +17 -1
  37. package/dist/cjs/features/metrics/instrument/index.js +1 -1
  38. package/dist/cjs/features/page_action/instrument/index.js +6 -6
  39. package/dist/cjs/features/page_view_event/aggregate/index.js +21 -5
  40. package/dist/cjs/features/page_view_event/aggregate/initialized-features.js +1 -1
  41. package/dist/cjs/features/page_view_event/instrument/index.js +1 -1
  42. package/dist/cjs/features/page_view_timing/aggregate/index.js +3 -3
  43. package/dist/cjs/features/page_view_timing/instrument/index.js +1 -1
  44. package/dist/cjs/features/session_replay/aggregate/index.js +3 -3
  45. package/dist/cjs/features/session_replay/instrument/index.js +1 -1
  46. package/dist/cjs/features/session_replay/shared/recorder.js +1 -1
  47. package/dist/cjs/features/session_replay/shared/stylesheet-evaluator.js +1 -1
  48. package/dist/cjs/features/session_trace/aggregate/index.js +1 -1
  49. package/dist/cjs/features/session_trace/aggregate/trace/storage.js +2 -2
  50. package/dist/cjs/features/session_trace/instrument/index.js +1 -1
  51. package/dist/cjs/features/soft_navigations/aggregate/bel-node.js +1 -1
  52. package/dist/cjs/features/soft_navigations/aggregate/index.js +1 -1
  53. package/dist/cjs/features/soft_navigations/aggregate/interaction.js +5 -5
  54. package/dist/cjs/features/soft_navigations/instrument/index.js +1 -1
  55. package/dist/cjs/features/spa/aggregate/index.js +3 -4
  56. package/dist/cjs/features/spa/aggregate/interaction.js +2 -2
  57. package/dist/cjs/features/spa/aggregate/serializer.js +1 -2
  58. package/dist/cjs/features/spa/instrument/index.js +1 -1
  59. package/dist/cjs/features/utils/aggregate-base.js +6 -3
  60. package/dist/cjs/features/utils/instrument-base.js +2 -2
  61. package/dist/cjs/features/utils/lazy-feature-loader.js +2 -2
  62. package/dist/cjs/index.js +21 -0
  63. package/dist/cjs/loaders/agent-base.js +1 -5
  64. package/dist/cjs/loaders/agent.js +3 -4
  65. package/dist/cjs/loaders/api/api.js +10 -8
  66. package/dist/cjs/loaders/api/apiAsync.js +1 -1
  67. package/dist/cjs/loaders/browser-agent.js +4 -3
  68. package/dist/cjs/loaders/configure/configure.js +4 -3
  69. package/dist/cjs/loaders/features/features.js +8 -4
  70. package/dist/cjs/loaders/micro-agent.js +6 -6
  71. package/dist/esm/cdn/experimental.js +2 -5
  72. package/dist/esm/cdn/pro.js +2 -2
  73. package/dist/esm/cdn/spa.js +2 -2
  74. package/dist/esm/common/aggregate/aggregator.js +3 -3
  75. package/dist/esm/common/config/state/configurable.js +4 -4
  76. package/dist/esm/common/config/state/init.js +11 -6
  77. package/dist/esm/common/constants/env.cdn.js +1 -1
  78. package/dist/esm/common/constants/env.npm.js +1 -1
  79. package/dist/esm/common/constants/runtime.js +0 -2
  80. package/dist/esm/common/context/shared-context.js +2 -2
  81. package/dist/esm/common/drain/drain.js +5 -5
  82. package/dist/esm/common/harvest/harvest.js +4 -4
  83. package/dist/esm/common/serialize/bel-serializer.js +2 -2
  84. package/dist/esm/common/session/session-entity.js +4 -4
  85. package/dist/esm/common/timing/time-keeper.js +12 -2
  86. package/dist/esm/common/url/encode.js +3 -5
  87. package/dist/esm/common/util/console.js +3 -4
  88. package/dist/esm/common/util/obfuscate.js +3 -3
  89. package/dist/esm/common/util/submit-data.js +0 -1
  90. package/dist/esm/common/vitals/vital-metric.js +1 -1
  91. package/dist/esm/common/wrap/wrap-logger.js +1 -2
  92. package/dist/esm/common/wrap/wrap-xhr.js +1 -1
  93. package/dist/esm/features/ajax/aggregate/index.js +1 -1
  94. package/dist/esm/features/ajax/instrument/index.js +1 -1
  95. package/dist/esm/features/generic_events/aggregate/index.js +129 -0
  96. package/dist/esm/features/generic_events/constants.js +2 -0
  97. package/dist/esm/features/generic_events/index.js +1 -0
  98. package/dist/esm/features/generic_events/instrument/index.js +20 -0
  99. package/dist/esm/features/jserrors/aggregate/index.js +13 -12
  100. package/dist/esm/features/jserrors/instrument/index.js +1 -1
  101. package/dist/esm/features/logging/aggregate/index.js +7 -7
  102. package/dist/esm/features/logging/constants.js +1 -4
  103. package/dist/esm/features/logging/instrument/index.js +1 -1
  104. package/dist/esm/features/metrics/aggregate/index.js +17 -1
  105. package/dist/esm/features/metrics/instrument/index.js +1 -1
  106. package/dist/esm/features/page_action/instrument/index.js +7 -6
  107. package/dist/esm/features/page_view_event/aggregate/index.js +22 -6
  108. package/dist/esm/features/page_view_event/aggregate/initialized-features.js +1 -1
  109. package/dist/esm/features/page_view_event/instrument/index.js +1 -1
  110. package/dist/esm/features/page_view_timing/aggregate/index.js +3 -3
  111. package/dist/esm/features/page_view_timing/instrument/index.js +1 -1
  112. package/dist/esm/features/session_replay/aggregate/index.js +3 -3
  113. package/dist/esm/features/session_replay/instrument/index.js +1 -1
  114. package/dist/esm/features/session_replay/shared/recorder.js +1 -1
  115. package/dist/esm/features/session_replay/shared/stylesheet-evaluator.js +1 -1
  116. package/dist/esm/features/session_trace/aggregate/index.js +1 -1
  117. package/dist/esm/features/session_trace/aggregate/trace/storage.js +2 -2
  118. package/dist/esm/features/session_trace/instrument/index.js +1 -1
  119. package/dist/esm/features/soft_navigations/aggregate/bel-node.js +1 -1
  120. package/dist/esm/features/soft_navigations/aggregate/index.js +1 -1
  121. package/dist/esm/features/soft_navigations/aggregate/interaction.js +5 -5
  122. package/dist/esm/features/soft_navigations/instrument/index.js +1 -1
  123. package/dist/esm/features/spa/aggregate/index.js +3 -4
  124. package/dist/esm/features/spa/aggregate/interaction.js +2 -2
  125. package/dist/esm/features/spa/aggregate/serializer.js +1 -2
  126. package/dist/esm/features/spa/instrument/index.js +1 -1
  127. package/dist/esm/features/utils/aggregate-base.js +7 -4
  128. package/dist/esm/features/utils/instrument-base.js +2 -2
  129. package/dist/esm/features/utils/lazy-feature-loader.js +2 -2
  130. package/dist/esm/index.js +3 -0
  131. package/dist/esm/loaders/agent-base.js +1 -5
  132. package/dist/esm/loaders/agent.js +3 -4
  133. package/dist/esm/loaders/api/api.js +10 -8
  134. package/dist/esm/loaders/api/apiAsync.js +1 -1
  135. package/dist/esm/loaders/browser-agent.js +3 -2
  136. package/dist/esm/loaders/configure/configure.js +4 -3
  137. package/dist/esm/loaders/features/features.js +8 -4
  138. package/dist/esm/loaders/micro-agent.js +6 -6
  139. package/dist/types/common/aggregate/aggregator.d.ts.map +1 -1
  140. package/dist/types/common/config/state/init.d.ts.map +1 -1
  141. package/dist/types/common/constants/runtime.d.ts +0 -1
  142. package/dist/types/common/constants/runtime.d.ts.map +1 -1
  143. package/dist/types/common/drain/drain.d.ts.map +1 -1
  144. package/dist/types/common/serialize/bel-serializer.d.ts.map +1 -1
  145. package/dist/types/common/timing/time-keeper.d.ts +2 -1
  146. package/dist/types/common/timing/time-keeper.d.ts.map +1 -1
  147. package/dist/types/common/url/encode.d.ts.map +1 -1
  148. package/dist/types/common/util/console.d.ts +1 -1
  149. package/dist/types/common/util/console.d.ts.map +1 -1
  150. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  151. package/dist/types/common/wrap/wrap-logger.d.ts.map +1 -1
  152. package/dist/types/features/{page_action → generic_events}/aggregate/index.d.ts +7 -5
  153. package/dist/types/features/generic_events/aggregate/index.d.ts.map +1 -0
  154. package/dist/types/features/generic_events/constants.d.ts +2 -0
  155. package/dist/types/features/generic_events/constants.d.ts.map +1 -0
  156. package/dist/types/features/generic_events/index.d.ts +2 -0
  157. package/dist/types/features/generic_events/index.d.ts.map +1 -0
  158. package/dist/types/features/generic_events/instrument/index.d.ts +6 -0
  159. package/dist/types/features/generic_events/instrument/index.d.ts.map +1 -0
  160. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  161. package/dist/types/features/logging/constants.d.ts +0 -3
  162. package/dist/types/features/logging/constants.d.ts.map +1 -1
  163. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  164. package/dist/types/features/page_action/instrument/index.d.ts +5 -4
  165. package/dist/types/features/page_action/instrument/index.d.ts.map +1 -1
  166. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  167. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  168. package/dist/types/features/session_replay/shared/recorder.d.ts.map +1 -1
  169. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  170. package/dist/types/features/spa/aggregate/interaction.d.ts.map +1 -1
  171. package/dist/types/features/spa/aggregate/serializer.d.ts.map +1 -1
  172. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
  173. package/dist/types/index.d.ts +3 -0
  174. package/dist/types/loaders/agent-base.d.ts +0 -1
  175. package/dist/types/loaders/agent-base.d.ts.map +1 -1
  176. package/dist/types/loaders/agent.d.ts.map +1 -1
  177. package/dist/types/loaders/api/api.d.ts.map +1 -1
  178. package/dist/types/loaders/browser-agent.d.ts.map +1 -1
  179. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  180. package/dist/types/loaders/features/features.d.ts +1 -0
  181. package/dist/types/loaders/features/features.d.ts.map +1 -1
  182. package/package.json +25 -6
  183. package/src/cdn/experimental.js +2 -4
  184. package/src/cdn/pro.js +2 -2
  185. package/src/cdn/spa.js +2 -2
  186. package/src/common/aggregate/aggregator.js +2 -3
  187. package/src/common/config/state/configurable.js +4 -4
  188. package/src/common/config/state/init.js +6 -4
  189. package/src/common/constants/runtime.js +0 -2
  190. package/src/common/context/shared-context.js +2 -2
  191. package/src/common/drain/drain.js +4 -5
  192. package/src/common/harvest/harvest.js +4 -4
  193. package/src/common/serialize/bel-serializer.js +1 -2
  194. package/src/common/session/session-entity.js +4 -4
  195. package/src/common/timing/time-keeper.js +14 -2
  196. package/src/common/url/encode.js +2 -3
  197. package/src/common/util/console.js +3 -4
  198. package/src/common/util/obfuscate.js +3 -3
  199. package/src/common/util/submit-data.js +0 -1
  200. package/src/common/wrap/wrap-logger.js +1 -2
  201. package/src/common/wrap/wrap-xhr.js +1 -1
  202. package/src/features/generic_events/aggregate/index.js +133 -0
  203. package/src/features/generic_events/constants.js +3 -0
  204. package/src/features/generic_events/index.js +1 -0
  205. package/src/features/generic_events/instrument/index.js +22 -0
  206. package/src/features/jserrors/aggregate/index.js +4 -5
  207. package/src/features/logging/aggregate/index.js +6 -6
  208. package/src/features/logging/constants.js +0 -4
  209. package/src/features/metrics/aggregate/index.js +12 -0
  210. package/src/features/page_action/instrument/index.js +6 -6
  211. package/src/features/page_view_event/aggregate/index.js +22 -5
  212. package/src/features/page_view_event/aggregate/initialized-features.js +1 -1
  213. package/src/features/page_view_timing/aggregate/index.js +1 -2
  214. package/src/features/session_replay/aggregate/index.js +1 -1
  215. package/src/features/session_replay/shared/recorder.js +1 -1
  216. package/src/features/spa/aggregate/index.js +2 -3
  217. package/src/features/spa/aggregate/interaction.js +1 -2
  218. package/src/features/spa/aggregate/serializer.js +1 -2
  219. package/src/features/utils/aggregate-base.js +7 -4
  220. package/src/features/utils/instrument-base.js +2 -2
  221. package/src/features/utils/lazy-feature-loader.js +2 -2
  222. package/src/index.js +3 -0
  223. package/src/loaders/agent-base.js +1 -5
  224. package/src/loaders/agent.js +3 -4
  225. package/src/loaders/api/api.js +10 -8
  226. package/src/loaders/api/apiAsync.js +1 -1
  227. package/src/loaders/browser-agent.js +5 -3
  228. package/src/loaders/configure/configure.js +5 -1
  229. package/src/loaders/features/features.js +8 -4
  230. package/src/loaders/micro-agent.js +6 -6
  231. package/dist/cjs/cdn/polyfills/lite.js +0 -16
  232. package/dist/cjs/cdn/polyfills/pro.js +0 -21
  233. package/dist/cjs/cdn/polyfills/spa.js +0 -22
  234. package/dist/cjs/cdn/polyfills.js +0 -24
  235. package/dist/cjs/common/util/map-own.js +0 -31
  236. package/dist/cjs/features/page_action/aggregate/index.js +0 -121
  237. package/dist/esm/cdn/polyfills/lite.js +0 -14
  238. package/dist/esm/cdn/polyfills/pro.js +0 -19
  239. package/dist/esm/cdn/polyfills/spa.js +0 -20
  240. package/dist/esm/cdn/polyfills.js +0 -27
  241. package/dist/esm/common/util/map-own.js +0 -24
  242. package/dist/esm/features/page_action/aggregate/index.js +0 -114
  243. package/dist/types/cdn/polyfills/lite.d.ts +0 -2
  244. package/dist/types/cdn/polyfills/lite.d.ts.map +0 -1
  245. package/dist/types/cdn/polyfills/pro.d.ts +0 -2
  246. package/dist/types/cdn/polyfills/pro.d.ts.map +0 -1
  247. package/dist/types/cdn/polyfills/spa.d.ts +0 -2
  248. package/dist/types/cdn/polyfills/spa.d.ts.map +0 -1
  249. package/dist/types/cdn/polyfills.d.ts +0 -2
  250. package/dist/types/cdn/polyfills.d.ts.map +0 -1
  251. package/dist/types/common/util/map-own.d.ts +0 -3
  252. package/dist/types/common/util/map-own.d.ts.map +0 -1
  253. package/dist/types/features/page_action/aggregate/index.d.ts.map +0 -1
  254. package/src/cdn/polyfills/lite.js +0 -20
  255. package/src/cdn/polyfills/pro.js +0 -30
  256. package/src/cdn/polyfills/spa.js +0 -32
  257. package/src/cdn/polyfills.js +0 -27
  258. package/src/common/util/map-own.js +0 -22
  259. package/src/features/page_action/aggregate/index.js +0 -114
@@ -45,6 +45,11 @@ const model = () => {
45
45
  allowed_origins: undefined
46
46
  },
47
47
  feature_flags: [],
48
+ generic_events: {
49
+ enabled: true,
50
+ harvestTimeSeconds: 30,
51
+ autoStart: true
52
+ },
48
53
  harvest: {
49
54
  tooManyRequestsDelay: 60
50
55
  },
@@ -65,9 +70,7 @@ const model = () => {
65
70
  },
66
71
  obfuscate: undefined,
67
72
  page_action: {
68
- enabled: true,
69
- harvestTimeSeconds: 30,
70
- autoStart: true
73
+ enabled: true
71
74
  },
72
75
  page_view_event: {
73
76
  enabled: true,
@@ -109,6 +112,8 @@ const model = () => {
109
112
  // serialize images for collection without public asset url -- right now this is only useful for testing as it easily generates payloads too large to be harvested
110
113
  inline_stylesheet: true,
111
114
  // serialize css for collection without public asset url
115
+ fix_stylesheets: true,
116
+ // fetch missing stylesheet resources for inlining, only works if 'inline_stylesheet' is also true
112
117
  // recording config settings
113
118
  mask_all_inputs: true,
114
119
  // this has a getter/setter to facilitate validation of the selectors
@@ -116,7 +121,7 @@ const model = () => {
116
121
  return hiddenState.mask_selector;
117
122
  },
118
123
  set mask_text_selector(val) {
119
- if (isValidSelector(val)) hiddenState.mask_selector = "".concat(val, ",").concat(nrMask);else if (val === '' || val === null) hiddenState.mask_selector = nrMask;else warn('An invalid session_replay.mask_selector was provided. \'*\' will be used.', val);
124
+ if (isValidSelector(val)) hiddenState.mask_selector = "".concat(val, ",").concat(nrMask);else if (val === '' || val === null) hiddenState.mask_selector = nrMask;else warn(5, val);
120
125
  },
121
126
  // these properties only have getters because they are enforcable constants and should error if someone tries to override them
122
127
  get block_class() {
@@ -134,7 +139,7 @@ const model = () => {
134
139
  return hiddenState.block_selector;
135
140
  },
136
141
  set block_selector(val) {
137
- if (isValidSelector(val)) hiddenState.block_selector += ",".concat(val);else if (val !== '') warn('An invalid session_replay.block_selector was provided and will not be used', val);
142
+ if (isValidSelector(val)) hiddenState.block_selector += ",".concat(val);else if (val !== '') warn(6, val);
138
143
  },
139
144
  // password: must always be present and true no matter what customer sets
140
145
  get mask_input_options() {
@@ -144,7 +149,7 @@ const model = () => {
144
149
  if (val && typeof val === 'object') hiddenState.mask_input_options = {
145
150
  ...val,
146
151
  password: true
147
- };else warn('An invalid session_replay.mask_input_option was provided and will not be used', val);
152
+ };else warn(7, val);
148
153
  }
149
154
  },
150
155
  session_trace: {
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.262.0";
9
+ export const VERSION = "1.264.0";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.262.0";
9
+ export const VERSION = "1.264.0";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -37,8 +37,6 @@ export const ffVersion = (() => {
37
37
  }
38
38
  return 0;
39
39
  })();
40
- export const isIE = Boolean(isBrowserScope && window.document.documentMode); // deprecated property that only works in IE
41
-
42
40
  export const supportsSendBeacon = !!globalScope.navigator?.sendBeacon;
43
41
 
44
42
  /**
@@ -6,7 +6,7 @@ const model = {
6
6
  export class SharedContext {
7
7
  constructor(context) {
8
8
  try {
9
- if (typeof context !== 'object') return warn('shared context requires an object as input');
9
+ if (typeof context !== 'object') return warn(8);
10
10
  this.sharedContext = {};
11
11
  Object.assign(this.sharedContext, model);
12
12
  Object.entries(context).forEach(_ref => {
@@ -14,7 +14,7 @@ export class SharedContext {
14
14
  if (Object.keys(model).includes(key)) this.sharedContext[key] = value;
15
15
  });
16
16
  } catch (err) {
17
- warn('An error occurred while setting SharedContext', err);
17
+ warn(9, err);
18
18
  }
19
19
  }
20
20
  }
@@ -4,7 +4,6 @@
4
4
  */
5
5
 
6
6
  import { ee } from '../event-emitter/contextual-ee';
7
- import { mapOwn } from '../util/map-own';
8
7
  import { registerHandler as defaultRegister } from '../event-emitter/register-handler';
9
8
  import { featurePriority } from '../../loaders/features/features';
10
9
  const registry = {};
@@ -99,7 +98,7 @@ function drainGroup(agentIdentifier, group) {
99
98
  let activateGroup = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
100
99
  const baseEE = agentIdentifier ? ee.get(agentIdentifier) : ee;
101
100
  const handlers = defaultRegister.handlers; // other storage in registerHandler
102
- if (!baseEE.backlog || !handlers) return;
101
+ if (baseEE.aborted || !baseEE.backlog || !handlers) return;
103
102
 
104
103
  // Only activated features being drained should run queued listeners on buffered events. Deactivated features only need to release memory.
105
104
  if (activateGroup) {
@@ -111,8 +110,9 @@ function drainGroup(agentIdentifier, group) {
111
110
  // eslint-disable-line no-unmodified-loop-condition
112
111
  emitEvent(bufferedEventsInGroup[i], groupHandlers);
113
112
  }
114
- mapOwn(groupHandlers, function (eventType, handlerRegistrationList) {
115
- mapOwn(handlerRegistrationList, function (i, registration) {
113
+ Object.entries(groupHandlers).forEach(_ref3 => {
114
+ let [eventType, handlerRegistrationList] = _ref3;
115
+ Object.values(handlerRegistrationList || {}).forEach(registration => {
116
116
  // registration is an array of: [targetEE, eventHandler]
117
117
  registration[0].on(eventType, registration[1]);
118
118
  });
@@ -133,7 +133,7 @@ function drainGroup(agentIdentifier, group) {
133
133
  */
134
134
  function emitEvent(evt, groupHandlers) {
135
135
  var type = evt[1];
136
- mapOwn(groupHandlers[type], function (i, registration) {
136
+ Object.values(groupHandlers[type] || {}).forEach(registration => {
137
137
  var sourceEE = evt[0];
138
138
  var ee = registration[0];
139
139
  if (ee === sourceEE) {
@@ -14,7 +14,7 @@ import { Obfuscator } from '../util/obfuscate';
14
14
  import { applyFnToProps } from '../util/traverse';
15
15
  import { SharedContext } from '../context/shared-context';
16
16
  import { VERSION } from "../constants/env.npm";
17
- import { isWorkerScope, isIE } from '../constants/runtime';
17
+ import { isWorkerScope } from '../constants/runtime';
18
18
  import { warn } from '../util/console';
19
19
  import { now } from '../timing/now';
20
20
  const warnings = {};
@@ -148,7 +148,7 @@ export class Harvest extends SharedContext {
148
148
  body = stringify(body);
149
149
  }
150
150
  /** Warn --once per endpoint-- if the agent tries to send large payloads */
151
- if (body.length > 750000 && (warnings[endpoint] = (warnings?.[endpoint] || 0) + 1) === 1) warn("The Browser Agent is attempting to send a very large payload to /".concat(endpoint, ". This is usually tied to large amounts of custom attributes. Please check your configurations."));
151
+ if (body.length > 750000 && (warnings[endpoint] = (warnings?.[endpoint] || 0) + 1) === 1) warn(28, endpoint);
152
152
  }
153
153
  if (!body || body.length === 0 || body === '{}' || body === '[]') {
154
154
  // If body is null, undefined, or an empty object or array, send an empty string instead
@@ -163,11 +163,11 @@ export class Harvest extends SharedContext {
163
163
  /* Since workers don't support sendBeacon right now, they can only use XHR method.
164
164
  Because they still do permit synch XHR, the idea is that at final harvest time (worker is closing),
165
165
  we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon.
166
- Following the removal of img-element method, IE will also use sync XHR on page dismissal to ensure final analytics are sent. */
166
+ Following the removal of img-element method. */
167
167
  let result = submitMethod({
168
168
  url: fullUrl,
169
169
  body,
170
- sync: opts.unload && (isWorkerScope || isIE),
170
+ sync: opts.unload && isWorkerScope,
171
171
  headers
172
172
  });
173
173
  if (!opts.unload && cbFinished && submitMethod === submitData.xhr) {
@@ -3,7 +3,6 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
- import { mapOwn } from '../util/map-own';
7
6
  import { stringify } from '../util/stringify';
8
7
  import { Obfuscator } from '../util/obfuscate';
9
8
  var hasOwnProp = Object.prototype.hasOwnProperty;
@@ -39,7 +38,8 @@ export function getAddStringContext(agentIdentifier) {
39
38
  }
40
39
  export function addCustomAttributes(attrs, addString) {
41
40
  var attrParts = [];
42
- mapOwn(attrs, function (key, val) {
41
+ Object.entries(attrs || {}).forEach(_ref => {
42
+ let [key, val] = _ref;
43
43
  if (attrParts.length >= MAX_ATTRIBUTES) return;
44
44
  var type = 5;
45
45
  var serializedValue;
@@ -3,7 +3,7 @@ import { warn } from '../util/console';
3
3
  import { stringify } from '../util/stringify';
4
4
  import { ee } from '../event-emitter/contextual-ee';
5
5
  import { Timer } from '../timer/timer';
6
- import { isBrowserScope, isIE } from '../constants/runtime';
6
+ import { isBrowserScope } from '../constants/runtime';
7
7
  import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, MODE, PREFIX, SESSION_EVENTS, SESSION_EVENT_TYPES } from './constants';
8
8
  import { InteractionTimer } from '../timer/interaction-timer';
9
9
  import { wrapEvents } from '../wrap';
@@ -59,7 +59,7 @@ export class SessionEntity {
59
59
  * if the event was spawned on the current page or an adjacent page, and the behavior tied
60
60
  * to storage events is critical to apply only to cross-tab behavior
61
61
  * */
62
- if (isBrowserScope && !isIE) {
62
+ if (isBrowserScope) {
63
63
  windowAddEventListener('storage', event => {
64
64
  if (event.key === this.lookupKey) {
65
65
  const obj = typeof event.newValue === 'string' ? JSON.parse(event.newValue) : event.newValue;
@@ -190,7 +190,7 @@ export class SessionEntity {
190
190
  }
191
191
  return obj;
192
192
  } catch (e) {
193
- warn('Failed to read from storage API', e);
193
+ warn(10, e);
194
194
  // storage is inaccessible
195
195
  return {};
196
196
  }
@@ -216,7 +216,7 @@ export class SessionEntity {
216
216
  return data;
217
217
  } catch (e) {
218
218
  // storage is inaccessible
219
- warn('Failed to write to the storage API', e);
219
+ warn(11, e);
220
220
  return null;
221
221
  }
222
222
  }
@@ -1,5 +1,6 @@
1
1
  import { originTime } from '../constants/runtime';
2
2
  import { getRuntime } from '../config/config';
3
+ const rfc2616Regex = /^(Mon|Tue|Wed|Thu|Fri|Sat|Sun), ([0-3][0-9]) (Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec) ([0-9]{4}) ([01][0-9]|2[0-3])(:[0-5][0-9]){2} GMT$/;
3
4
 
4
5
  /**
5
6
  * Class used to adjust the timestamp of harvested data to New Relic server time. This
@@ -29,7 +30,7 @@ export class TimeKeeper {
29
30
  /**
30
31
  * Represents whether the timekeeper is in a state that it can accurately convert
31
32
  * timestamps.
32
- * @type {number}
33
+ * @type {boolean}
33
34
  */
34
35
  #ready = false;
35
36
  constructor(agentIdentifier) {
@@ -42,6 +43,9 @@ export class TimeKeeper {
42
43
  get correctedOriginTime() {
43
44
  return this.#correctedOriginTime;
44
45
  }
46
+ get localTimeDiff() {
47
+ return this.#localTimeDiff;
48
+ }
45
49
 
46
50
  /**
47
51
  * Process a rum request to calculate NR server time.
@@ -50,12 +54,16 @@ export class TimeKeeper {
50
54
  * @param endTime {number} The end time of the RUM request
51
55
  */
52
56
  processRumRequest(rumRequest, startTime, endTime) {
53
- this.processStoredDiff();
57
+ this.processStoredDiff(); // Check session entity for stored time diff
54
58
  if (this.#ready) return; // Server time calculated from session entity
59
+
55
60
  const responseDateHeader = rumRequest.getResponseHeader('Date');
56
61
  if (!responseDateHeader) {
57
62
  throw new Error('Missing date header on rum response.');
58
63
  }
64
+ if (!rfc2616Regex.test(responseDateHeader)) {
65
+ throw new Error('Date header invalid format.');
66
+ }
59
67
  const medianRumOffset = (endTime - startTime) / 2;
60
68
  const serverOffset = startTime + medianRumOffset;
61
69
 
@@ -92,6 +100,8 @@ export class TimeKeeper {
92
100
 
93
101
  /** Process the session entity and use the info to set the main time calculations if present */
94
102
  processStoredDiff() {
103
+ if (this.#ready) return; // Time diff has already been calculated
104
+
95
105
  const storedServerTimeDiff = this.#session?.read()?.serverTimeDiff;
96
106
  if (typeof storedServerTimeDiff === 'number' && !isNaN(storedServerTimeDiff)) {
97
107
  this.#localTimeDiff = storedServerTimeDiff;
@@ -3,7 +3,6 @@
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
5
 
6
- import { mapOwn } from '../util/map-own';
7
6
  import { stringify } from '../util/stringify';
8
7
 
9
8
  // Characters that are safe in a qs, but get encoded.
@@ -15,9 +14,7 @@ var charMap = {
15
14
  '%24': '$',
16
15
  '%3B': ';'
17
16
  };
18
- var charList = mapOwn(charMap, function (k) {
19
- return k;
20
- });
17
+ var charList = Object.keys(charMap);
21
18
  var safeEncoded = new RegExp(charList.join('|'), 'g');
22
19
  function real(c) {
23
20
  return charMap[c];
@@ -40,7 +37,8 @@ export function fromArray(qs, maxBytes) {
40
37
  export function obj(payload, maxBytes) {
41
38
  var total = 0;
42
39
  var result = '';
43
- mapOwn(payload, function (feature, dataArray) {
40
+ Object.entries(payload || {}).forEach(_ref => {
41
+ let [feature, dataArray] = _ref;
44
42
  var intermediate = [];
45
43
  var next;
46
44
  var i;
@@ -4,8 +4,7 @@
4
4
  * @param {*} [secondary] Secondary data to include, usually an error or object
5
5
  * @returns
6
6
  */
7
- export function warn(message, secondary) {
8
- if (typeof console.warn !== 'function') return;
9
- console.warn("New Relic: ".concat(message));
10
- if (secondary) console.warn(secondary);
7
+ export function warn(code, secondary) {
8
+ if (typeof console.debug !== 'function') return;
9
+ console.debug("New Relic Warning: https://github.com/newrelic/newrelic-browser-agent/blob/main/docs/warning-codes.md#".concat(code), secondary);
11
10
  }
@@ -45,15 +45,15 @@ export function validateRules(rules) {
45
45
  var invalidRegexDetected = false;
46
46
  for (var i = 0; i < rules.length; i++) {
47
47
  if (!('regex' in rules[i])) {
48
- warn('An obfuscation replacement rule was detected missing a "regex" value.');
48
+ warn(12);
49
49
  invalidRegexDetected = true;
50
50
  } else if (typeof rules[i].regex !== 'string' && !(rules[i].regex instanceof RegExp)) {
51
- warn('An obfuscation replacement rule contains a "regex" value with an invalid type (must be a string or RegExp)');
51
+ warn(13);
52
52
  invalidRegexDetected = true;
53
53
  }
54
54
  var replacement = rules[i].replacement;
55
55
  if (replacement && typeof replacement !== 'string') {
56
- warn('An obfuscation replacement rule contains a "replacement" value with an invalid type (must be a string)');
56
+ warn(14);
57
57
  invalidReplacementDetected = true;
58
58
  }
59
59
  }
@@ -23,7 +23,6 @@ export function getSubmitMethod() {
23
23
  return isFinalHarvest && isBrowserScope && supportsSendBeacon
24
24
  // Use sendBeacon for final harvest
25
25
  ? beacon
26
- // Only IE does not support sendBeacon for final harvest
27
26
  // If not final harvest, or not browserScope, always use xhr post
28
27
  : xhr;
29
28
  }
@@ -1,5 +1,5 @@
1
1
  export class VitalMetric {
2
- #subscribers = new Set();
2
+ #subscribers = (() => new Set())();
3
3
  history = [];
4
4
  constructor(name, roundingMethod) {
5
5
  this.name = name;
@@ -7,7 +7,6 @@
7
7
  * This module is used by: jserrors, spa.
8
8
  */
9
9
 
10
- import { LOGGING_FAILURE_MESSAGE } from '../../features/logging/constants';
11
10
  import { ee as baseEE, contextId } from '../event-emitter/contextual-ee';
12
11
  import { EventContext } from '../event-emitter/event-context';
13
12
  import { warn } from '../util/console';
@@ -22,7 +21,7 @@ import { createWrapperWithEmitter as wfn } from './wrap-function';
22
21
  */
23
22
  // eslint-disable-next-line
24
23
  export function wrapLogger(sharedEE, parent, loggerFn, context) {
25
- if (!(typeof parent === 'object' && !!parent && typeof loggerFn === 'string' && !!loggerFn && typeof parent[loggerFn] === 'function')) return warn(LOGGING_FAILURE_MESSAGE + 'invalid argument(s)');
24
+ if (!(typeof parent === 'object' && !!parent && typeof loggerFn === 'string' && !!loggerFn && typeof parent[loggerFn] === 'function')) return warn(29);
26
25
  const ee = scopedEE(sharedEE);
27
26
  const wrapFn = wfn(ee);
28
27
 
@@ -49,7 +49,7 @@ export function wrapXhr(sharedEE) {
49
49
  ee.emit('new-xhr', [xhr], context);
50
50
  xhr.addEventListener(READY_STATE_CHANGE, wrapXHR(context), eventListenerOpts(false));
51
51
  } catch (e) {
52
- warn('An error occurred while intercepting XHR', e);
52
+ warn(15, e);
53
53
  try {
54
54
  ee.emit('internal-error', [e]);
55
55
  } catch (err) {
@@ -16,7 +16,7 @@ import { parseGQL } from './gql';
16
16
  import { getNREUMInitializedAgent } from '../../../common/window/nreum';
17
17
  import Chunk from './chunk';
18
18
  export class Aggregate extends AggregateBase {
19
- static featureName = FEATURE_NAME;
19
+ static featureName = (() => FEATURE_NAME)();
20
20
  #agentInfo;
21
21
  #agentRuntime;
22
22
  #agentInit;
@@ -23,7 +23,7 @@ var handlersLen = handlers.length;
23
23
  var origRequest = originals.REQ;
24
24
  var origXHR = originals.XHR;
25
25
  export class Instrument extends InstrumentBase {
26
- static featureName = FEATURE_NAME;
26
+ static featureName = (() => FEATURE_NAME)();
27
27
  constructor(agentIdentifier, aggregator) {
28
28
  let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
29
29
  super(agentIdentifier, aggregator, FEATURE_NAME, auto);
@@ -0,0 +1,129 @@
1
+ /*
2
+ * Copyright 2020 New Relic Corporation. All rights reserved.
3
+ * SPDX-License-Identifier: Apache-2.0
4
+ */
5
+ import { stringify } from '../../../common/util/stringify';
6
+ import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
7
+ import { cleanURL } from '../../../common/url/clean-url';
8
+ import { getConfigurationValue, getInfo, getRuntime } from '../../../common/config/config';
9
+ import { FEATURE_NAME } from '../constants';
10
+ import { isBrowserScope } from '../../../common/constants/runtime';
11
+ import { AggregateBase } from '../../utils/aggregate-base';
12
+ import { warn } from '../../../common/util/console';
13
+ import { now } from '../../../common/timing/now';
14
+ import { registerHandler } from '../../../common/event-emitter/register-handler';
15
+ import { deregisterDrain } from '../../../common/drain/drain';
16
+ import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
17
+ export class Aggregate extends AggregateBase {
18
+ #agentRuntime;
19
+ static featureName = (() => FEATURE_NAME)();
20
+ constructor(agentIdentifier, aggregator) {
21
+ var _this;
22
+ super(agentIdentifier, aggregator, FEATURE_NAME);
23
+ _this = this;
24
+ this.eventsPerHarvest = 1000;
25
+ this.harvestTimeSeconds = getConfigurationValue(this.agentIdentifier, 'generic_events.harvestTimeSeconds');
26
+ this.referrerUrl = isBrowserScope && document.referrer ? cleanURL(document.referrer) : undefined;
27
+ this.currentEvents = [];
28
+ this.events = [];
29
+ this.overflow = [];
30
+ this.#agentRuntime = getRuntime(this.agentIdentifier);
31
+ this.waitForFlags(['ins']).then(_ref => {
32
+ let [ins] = _ref;
33
+ if (!ins) {
34
+ this.blocked = true;
35
+ deregisterDrain(this.agentIdentifier, this.featureName);
36
+ return;
37
+ }
38
+ if (getConfigurationValue(this.agentIdentifier, 'page_action.enabled')) {
39
+ registerHandler('api-addPageAction', (timestamp, name, attributes) => {
40
+ this.addEvent({
41
+ ...attributes,
42
+ eventType: 'PageAction',
43
+ timestamp: this.#agentRuntime.timeKeeper.convertRelativeTimestamp(timestamp),
44
+ timeSinceLoad: timestamp / 1000,
45
+ actionName: name,
46
+ referrerUrl: this.referrerUrl,
47
+ currentUrl: cleanURL('' + location),
48
+ ...(isBrowserScope && {
49
+ browserWidth: window.document.documentElement?.clientWidth,
50
+ browserHeight: window.document.documentElement?.clientHeight
51
+ })
52
+ });
53
+ }, this.featureName, this.ee);
54
+ }
55
+ this.harvestScheduler = new HarvestScheduler('ins', {
56
+ onFinished: function () {
57
+ return _this.onHarvestFinished(...arguments);
58
+ }
59
+ }, this);
60
+ this.harvestScheduler.harvest.on('ins', function () {
61
+ return _this.onHarvestStarted(...arguments);
62
+ });
63
+ this.harvestScheduler.startTimer(this.harvestTimeSeconds, 0);
64
+ this.drain();
65
+ });
66
+ }
67
+ onHarvestStarted(options) {
68
+ const {
69
+ userAttributes,
70
+ atts
71
+ } = getInfo(this.agentIdentifier);
72
+ const harvestEvents = this.overflow.length ? this.overflow.splice(0, Infinity) : this.events.splice(0, Infinity);
73
+ var payload = {
74
+ qs: {
75
+ ua: userAttributes,
76
+ at: atts
77
+ },
78
+ body: {
79
+ ins: harvestEvents
80
+ }
81
+ };
82
+ if (options.retry) {
83
+ this.currentEvents = harvestEvents;
84
+ }
85
+ return payload;
86
+ }
87
+ onHarvestFinished(result) {
88
+ if (result && result.sent && result.retry && this.currentEvents.length) {
89
+ this.events = this.currentEvents.concat(this.events);
90
+ this.currentEvents = [];
91
+ }
92
+ }
93
+
94
+ // WARNING: Insights times are in seconds. EXCEPT timestamp, which is in ms.
95
+ addEvent() {
96
+ let obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
97
+ if (!obj || !Object.keys(obj).length) return;
98
+ if (!obj.eventType) {
99
+ warn(44);
100
+ return;
101
+ }
102
+ for (let key in obj) {
103
+ let val = obj[key];
104
+ obj[key] = val && typeof val === 'object' ? stringify(val) : val;
105
+ }
106
+ const defaultEventAttributes = {
107
+ /** should be overridden by the event-specific attributes, but just in case -- set it to now() */
108
+ timestamp: this.#agentRuntime.timeKeeper.convertRelativeTimestamp(now()),
109
+ /** all generic events require a pageUrl */
110
+ pageUrl: cleanURL(getRuntime(this.agentIdentifier).origin)
111
+ };
112
+ const eventAttributes = {
113
+ /** Agent-level custom attributes */
114
+ ...(getInfo(this.agentIdentifier).jsAttributes || {}),
115
+ /** Fallbacks for required properties in-case the event did not supply them, should take precedence over agent-level custom attrs */
116
+ ...defaultEventAttributes,
117
+ /** Event-specific attributes take precedence over agent-level custom attributes and fallbacks */
118
+ ...obj
119
+ };
120
+ this.events.push(eventAttributes);
121
+
122
+ // check if we've reached the harvest limit...
123
+ if (this.events.length >= this.eventsPerHarvest) {
124
+ this.ee.emit(SUPPORTABILITY_METRIC_CHANNEL, ['GenericEvents/Harvest/Max/Seen']);
125
+ this.overflow = [...this.overflow, ...this.events.splice(0, Infinity)];
126
+ this.harvestScheduler.runHarvest();
127
+ }
128
+ }
129
+ }
@@ -0,0 +1,2 @@
1
+ import { FEATURE_NAMES } from '../../loaders/features/features';
2
+ export const FEATURE_NAME = FEATURE_NAMES.genericEvents;
@@ -0,0 +1 @@
1
+ export { Instrument as GenericEvents } from './instrument/index';
@@ -0,0 +1,20 @@
1
+ /* Copyright 2020 New Relic Corporation. All rights reserved.
2
+ * SPDX-License-Identifier: Apache-2.0
3
+ */
4
+
5
+ import { getConfigurationValue } from '../../../common/config/config';
6
+ import { deregisterDrain } from '../../../common/drain/drain';
7
+ import { InstrumentBase } from '../../utils/instrument-base';
8
+ import { FEATURE_NAME } from '../constants';
9
+ export class Instrument extends InstrumentBase {
10
+ static featureName = (() => FEATURE_NAME)();
11
+ constructor(agentIdentifier, aggregator) {
12
+ let auto = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true;
13
+ super(agentIdentifier, aggregator, FEATURE_NAME, auto);
14
+ const genericEventSourceConfigs = [getConfigurationValue(this.agentIdentifier, 'page_action.enabled')
15
+ // other future generic event source configs to go here, like M&Ms, PageResouce, etc.
16
+ ];
17
+ /** If any of the sources are active, import the aggregator. otherwise deregister */
18
+ if (genericEventSourceConfigs.some(x => x)) this.importAggregator();else deregisterDrain(this.agentIdentifier, this.featureName);
19
+ }
20
+ }
@@ -11,7 +11,6 @@ import { registerHandler as register } from '../../../common/event-emitter/regis
11
11
  import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
12
12
  import { stringify } from '../../../common/util/stringify';
13
13
  import { handle } from '../../../common/event-emitter/handle';
14
- import { mapOwn } from '../../../common/util/map-own';
15
14
  import { getInfo, getConfigurationValue, getRuntime } from '../../../common/config/config';
16
15
  import { globalScope } from '../../../common/constants/runtime';
17
16
  import { FEATURE_NAME } from '../constants';
@@ -26,7 +25,7 @@ import { now } from '../../../common/timing/now';
26
25
  */
27
26
 
28
27
  export class Aggregate extends AggregateBase {
29
- static featureName = FEATURE_NAME;
28
+ static featureName = (() => FEATURE_NAME)();
30
29
  constructor(agentIdentifier, aggregator) {
31
30
  var _this;
32
31
  super(agentIdentifier, aggregator, FEATURE_NAME);
@@ -95,7 +94,8 @@ export class Aggregate extends AggregateBase {
95
94
  }
96
95
  onHarvestFinished(result) {
97
96
  if (result.retry && this.currentBody) {
98
- mapOwn(this.currentBody, (key, value) => {
97
+ Object.entries(this.currentBody || {}).forEach(_ref2 => {
98
+ let [key, value] = _ref2;
99
99
  for (var i = 0; i < value.length; i++) {
100
100
  var bucket = value[i];
101
101
  var name = this.getBucketName(key, bucket.params, bucket.custom);
@@ -225,8 +225,8 @@ export class Aggregate extends AggregateBase {
225
225
  let [type, bucketHash, params, newMetrics, localAttrs] = errorInfoArr;
226
226
  const allCustomAttrs = {};
227
227
  if (softNavOccurredFinished) {
228
- Object.entries(softNavCustomAttrs).forEach(_ref2 => {
229
- let [k, v] = _ref2;
228
+ Object.entries(softNavCustomAttrs).forEach(_ref3 => {
229
+ let [k, v] = _ref3;
230
230
  return setCustom(k, v);
231
231
  }); // when an ixn finishes, it'll include stuff in jsAttributes + attrs specific to the ixn
232
232
  bucketHash += params.browserInteractionId;
@@ -234,14 +234,14 @@ export class Aggregate extends AggregateBase {
234
234
  delete params._softNavFinished;
235
235
  } else {
236
236
  // interaction was cancelled -> error should not be associated OR there was no interaction
237
- Object.entries(getInfo(this.agentIdentifier).jsAttributes).forEach(_ref3 => {
238
- let [k, v] = _ref3;
237
+ Object.entries(getInfo(this.agentIdentifier).jsAttributes).forEach(_ref4 => {
238
+ let [k, v] = _ref4;
239
239
  return setCustom(k, v);
240
240
  });
241
241
  delete params.browserInteractionId;
242
242
  }
243
- if (localAttrs) Object.entries(localAttrs).forEach(_ref4 => {
244
- let [k, v] = _ref4;
243
+ if (localAttrs) Object.entries(localAttrs).forEach(_ref5 => {
244
+ let [k, v] = _ref5;
245
245
  return setCustom(k, v);
246
246
  }); // local custom attrs are applied in either case with the highest precedence
247
247
 
@@ -259,8 +259,8 @@ export class Aggregate extends AggregateBase {
259
259
  this.bufferedErrorsUnderSpa[interaction.id].forEach(item => {
260
260
  var allCustomAttrs = {};
261
261
  const localCustomAttrs = item[4];
262
- mapOwn(interaction.root.attrs.custom, setCustom); // tack on custom attrs from the interaction
263
- mapOwn(localCustomAttrs, setCustom);
262
+ Object.entries(interaction.root.attrs.custom || {}).forEach(setCustom); // tack on custom attrs from the interaction
263
+ Object.entries(localCustomAttrs || {}).forEach(setCustom);
264
264
  var params = item[2];
265
265
  if (wasSaved) {
266
266
  params.browserInteractionId = interaction.root.attrs.id;
@@ -272,7 +272,8 @@ export class Aggregate extends AggregateBase {
272
272
  var jsAttributesHash = stringHashCode(stringify(allCustomAttrs));
273
273
  var aggregateHash = hash + ':' + jsAttributesHash;
274
274
  this.aggregator.store(item[0], aggregateHash, params, item[3], allCustomAttrs);
275
- function setCustom(key, val) {
275
+ function setCustom(_ref6) {
276
+ let [key, val] = _ref6;
276
277
  allCustomAttrs[key] = val && typeof val === 'object' ? stringify(val) : val;
277
278
  }
278
279
  });