@newrelic/browser-agent 1.232.1 → 1.233.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 (242) hide show
  1. package/dist/cjs/cdn/experimental.js +27 -0
  2. package/dist/cjs/cdn/polyfills.js +5 -2
  3. package/dist/cjs/common/config/state/configurable.js +15 -26
  4. package/dist/cjs/common/config/state/info.js +1 -1
  5. package/dist/cjs/common/config/state/init.js +101 -56
  6. package/dist/cjs/common/config/state/loader-config.js +1 -1
  7. package/dist/cjs/common/config/state/runtime.js +1 -5
  8. package/dist/cjs/common/constants/env.cdn.js +1 -1
  9. package/dist/cjs/common/constants/env.npm.js +1 -1
  10. package/dist/cjs/common/drain/drain.js +1 -1
  11. package/dist/cjs/common/harvest/harvest-scheduler.js +43 -8
  12. package/dist/cjs/common/harvest/harvest-scheduler.test.js +39 -0
  13. package/dist/cjs/common/harvest/harvest.js +106 -55
  14. package/dist/cjs/common/session/session-entity.js +35 -22
  15. package/dist/cjs/common/session/session-entity.test.js +73 -49
  16. package/dist/cjs/common/timer/interaction-timer.js +9 -12
  17. package/dist/cjs/common/url/protocol.test.js +0 -1
  18. package/dist/cjs/common/util/feature-flags.js +2 -1
  19. package/dist/cjs/common/util/submit-data.js +57 -18
  20. package/dist/cjs/common/wrap/wrap-fetch.js +1 -1
  21. package/dist/cjs/common/wrap/wrap-function.js +1 -1
  22. package/dist/cjs/common/wrap/wrap-promise.js +1 -1
  23. package/dist/cjs/features/ajax/aggregate/index.js +2 -2
  24. package/dist/cjs/features/jserrors/aggregate/index.js +7 -5
  25. package/dist/cjs/features/metrics/aggregate/framework-detection.js +67 -0
  26. package/dist/cjs/features/metrics/aggregate/framework-detection.test.js +137 -0
  27. package/dist/cjs/features/metrics/aggregate/index.js +7 -3
  28. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.js +14 -0
  29. package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.test.js +17 -0
  30. package/dist/cjs/features/metrics/aggregate/polyfill-detection.js +53 -0
  31. package/dist/cjs/features/metrics/aggregate/polyfill-detection.test.js +165 -0
  32. package/dist/cjs/features/page_action/aggregate/index.js +2 -2
  33. package/dist/cjs/features/page_view_event/aggregate/index.js +6 -3
  34. package/dist/cjs/features/page_view_timing/aggregate/index.js +2 -2
  35. package/dist/cjs/features/session_replay/aggregate/index.js +336 -0
  36. package/dist/cjs/features/session_replay/constants.js +9 -0
  37. package/dist/cjs/features/session_replay/index.js +12 -0
  38. package/dist/cjs/features/session_replay/instrument/index.js +29 -0
  39. package/dist/cjs/features/session_trace/aggregate/index.js +163 -162
  40. package/dist/cjs/features/session_trace/constants.js +2 -9
  41. package/dist/cjs/features/session_trace/instrument/index.js +24 -66
  42. package/dist/cjs/features/spa/aggregate/index.js +2 -2
  43. package/dist/cjs/features/utils/agent-session.js +1 -2
  44. package/dist/cjs/features/utils/aggregate-base.js +64 -0
  45. package/dist/cjs/features/utils/feature-base.js +0 -31
  46. package/dist/cjs/features/utils/handler-cache.js +3 -4
  47. package/dist/cjs/features/utils/instrument-base.js +42 -10
  48. package/dist/cjs/features/utils/{lazy-loader.js → lazy-feature-loader.js} +4 -2
  49. package/dist/cjs/loaders/agent.js +1 -1
  50. package/dist/cjs/loaders/api/apiAsync.js +3 -1
  51. package/dist/cjs/loaders/configure/configure.js +3 -3
  52. package/dist/cjs/loaders/features/featureDependencies.js +0 -12
  53. package/dist/cjs/loaders/features/features.js +3 -1
  54. package/dist/cjs/loaders/micro-agent.js +6 -6
  55. package/dist/esm/cdn/experimental.js +24 -0
  56. package/dist/esm/cdn/polyfills.js +5 -2
  57. package/dist/esm/common/config/state/configurable.js +14 -24
  58. package/dist/esm/common/config/state/info.js +2 -2
  59. package/dist/esm/common/config/state/init.js +102 -57
  60. package/dist/esm/common/config/state/loader-config.js +2 -2
  61. package/dist/esm/common/config/state/runtime.js +2 -4
  62. package/dist/esm/common/constants/env.cdn.js +1 -1
  63. package/dist/esm/common/constants/env.npm.js +1 -1
  64. package/dist/esm/common/drain/drain.js +1 -1
  65. package/dist/esm/common/harvest/harvest-scheduler.js +43 -8
  66. package/dist/esm/common/harvest/harvest-scheduler.test.js +37 -0
  67. package/dist/esm/common/harvest/harvest.js +108 -56
  68. package/dist/esm/common/session/session-entity.js +35 -22
  69. package/dist/esm/common/session/session-entity.test.js +73 -49
  70. package/dist/esm/common/timer/interaction-timer.js +9 -12
  71. package/dist/esm/common/url/protocol.test.js +0 -1
  72. package/dist/esm/common/util/feature-flags.js +2 -1
  73. package/dist/esm/common/util/submit-data.js +57 -18
  74. package/dist/esm/common/wrap/wrap-fetch.js +1 -1
  75. package/dist/esm/common/wrap/wrap-function.js +1 -1
  76. package/dist/esm/common/wrap/wrap-promise.js +1 -1
  77. package/dist/esm/features/ajax/aggregate/index.js +2 -2
  78. package/dist/esm/features/jserrors/aggregate/index.js +7 -5
  79. package/dist/esm/features/metrics/aggregate/framework-detection.js +61 -0
  80. package/dist/esm/features/metrics/aggregate/framework-detection.test.js +133 -0
  81. package/dist/esm/features/metrics/aggregate/index.js +7 -3
  82. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.js +8 -0
  83. package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.test.js +15 -0
  84. package/dist/esm/features/metrics/aggregate/polyfill-detection.js +47 -0
  85. package/dist/esm/features/metrics/aggregate/polyfill-detection.test.js +163 -0
  86. package/dist/esm/features/page_action/aggregate/index.js +2 -2
  87. package/dist/esm/features/page_view_event/aggregate/index.js +6 -3
  88. package/dist/esm/features/page_view_timing/aggregate/index.js +2 -2
  89. package/dist/esm/features/session_replay/aggregate/index.js +330 -0
  90. package/dist/esm/features/session_replay/constants.js +2 -0
  91. package/dist/esm/features/session_replay/index.js +12 -0
  92. package/dist/esm/features/session_replay/instrument/index.js +21 -0
  93. package/dist/esm/features/session_trace/aggregate/index.js +163 -162
  94. package/dist/esm/features/session_trace/constants.js +1 -5
  95. package/dist/esm/features/session_trace/instrument/index.js +24 -66
  96. package/dist/esm/features/spa/aggregate/index.js +2 -2
  97. package/dist/esm/features/utils/agent-session.js +1 -2
  98. package/dist/esm/features/utils/aggregate-base.js +57 -0
  99. package/dist/esm/features/utils/feature-base.js +1 -32
  100. package/dist/esm/features/utils/handler-cache.js +3 -4
  101. package/dist/esm/features/utils/instrument-base.js +42 -10
  102. package/dist/esm/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
  103. package/dist/esm/loaders/agent.js +1 -1
  104. package/dist/esm/loaders/api/apiAsync.js +3 -1
  105. package/dist/esm/loaders/configure/configure.js +3 -3
  106. package/dist/esm/loaders/features/featureDependencies.js +0 -11
  107. package/dist/esm/loaders/features/features.js +3 -1
  108. package/dist/esm/loaders/micro-agent.js +6 -6
  109. package/dist/types/cdn/experimental.d.ts +2 -0
  110. package/dist/types/cdn/experimental.d.ts.map +1 -0
  111. package/dist/types/common/config/state/configurable.d.ts +1 -3
  112. package/dist/types/common/config/state/configurable.d.ts.map +1 -1
  113. package/dist/types/common/config/state/init.d.ts.map +1 -1
  114. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  115. package/dist/types/common/harvest/harvest-scheduler.d.ts +26 -3
  116. package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
  117. package/dist/types/common/harvest/harvest.d.ts +37 -34
  118. package/dist/types/common/harvest/harvest.d.ts.map +1 -1
  119. package/dist/types/common/session/session-entity.d.ts +6 -3
  120. package/dist/types/common/session/session-entity.d.ts.map +1 -1
  121. package/dist/types/common/timer/interaction-timer.d.ts +2 -1
  122. package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
  123. package/dist/types/common/util/feature-flags.d.ts.map +1 -1
  124. package/dist/types/common/util/submit-data.d.ts +40 -14
  125. package/dist/types/common/util/submit-data.d.ts.map +1 -1
  126. package/dist/types/features/ajax/aggregate/index.d.ts +2 -2
  127. package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
  128. package/dist/types/features/jserrors/aggregate/index.d.ts +2 -2
  129. package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
  130. package/dist/types/features/metrics/aggregate/framework-detection.d.ts.map +1 -0
  131. package/dist/types/features/metrics/aggregate/index.d.ts +2 -2
  132. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  133. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts +6 -0
  134. package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts.map +1 -0
  135. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts +7 -0
  136. package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -0
  137. package/dist/types/features/page_action/aggregate/index.d.ts +2 -2
  138. package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
  139. package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -2
  140. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  141. package/dist/types/features/page_view_timing/aggregate/index.d.ts +2 -2
  142. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  143. package/dist/types/features/session_replay/aggregate/index.d.ts +100 -0
  144. package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -0
  145. package/dist/types/features/session_replay/constants.d.ts +2 -0
  146. package/dist/types/features/session_replay/constants.d.ts.map +1 -0
  147. package/dist/types/features/session_replay/index.d.ts +2 -0
  148. package/dist/types/features/session_replay/index.d.ts.map +1 -0
  149. package/dist/types/features/session_replay/instrument/index.d.ts +6 -0
  150. package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -0
  151. package/dist/types/features/session_trace/aggregate/index.d.ts +8 -57
  152. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  153. package/dist/types/features/session_trace/constants.d.ts +0 -3
  154. package/dist/types/features/session_trace/constants.d.ts.map +1 -1
  155. package/dist/types/features/session_trace/instrument/index.d.ts +1 -3
  156. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  157. package/dist/types/features/spa/aggregate/index.d.ts +2 -2
  158. package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
  159. package/dist/types/features/utils/agent-session.d.ts.map +1 -1
  160. package/dist/types/features/utils/aggregate-base.d.ts +11 -0
  161. package/dist/types/features/utils/aggregate-base.d.ts.map +1 -0
  162. package/dist/types/features/utils/feature-base.d.ts +0 -5
  163. package/dist/types/features/utils/feature-base.d.ts.map +1 -1
  164. package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
  165. package/dist/types/features/utils/instrument-base.d.ts +3 -1
  166. package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
  167. package/dist/types/features/utils/{lazy-loader.d.ts → lazy-feature-loader.d.ts} +2 -2
  168. package/dist/types/features/utils/lazy-feature-loader.d.ts.map +1 -0
  169. package/dist/types/loaders/configure/configure.d.ts.map +1 -1
  170. package/dist/types/loaders/features/featureDependencies.d.ts +0 -1
  171. package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
  172. package/dist/types/loaders/features/features.d.ts +1 -0
  173. package/dist/types/loaders/features/features.d.ts.map +1 -1
  174. package/package.json +30 -20
  175. package/src/cdn/experimental.js +36 -0
  176. package/src/cdn/polyfills.js +4 -1
  177. package/src/common/config/state/configurable.js +18 -24
  178. package/src/common/config/state/info.js +2 -2
  179. package/src/common/config/state/init.js +62 -28
  180. package/src/common/config/state/loader-config.js +2 -2
  181. package/src/common/config/state/runtime.js +2 -4
  182. package/src/common/drain/drain.js +1 -1
  183. package/src/common/harvest/harvest-scheduler.js +48 -8
  184. package/src/common/harvest/harvest-scheduler.test.js +25 -0
  185. package/src/common/harvest/harvest.js +72 -50
  186. package/src/common/session/session-entity.js +34 -23
  187. package/src/common/session/session-entity.test.js +57 -51
  188. package/src/common/timer/interaction-timer.js +9 -12
  189. package/src/common/url/protocol.test.js +0 -1
  190. package/src/common/util/feature-flags.js +2 -2
  191. package/src/common/util/submit-data.js +28 -17
  192. package/src/common/wrap/wrap-fetch.js +1 -1
  193. package/src/common/wrap/wrap-function.js +1 -1
  194. package/src/common/wrap/wrap-promise.js +1 -1
  195. package/src/features/ajax/aggregate/index.js +2 -2
  196. package/src/features/jserrors/aggregate/index.js +7 -5
  197. package/src/features/metrics/aggregate/framework-detection.js +73 -0
  198. package/src/features/metrics/aggregate/framework-detection.test.js +201 -0
  199. package/src/features/metrics/aggregate/index.js +8 -3
  200. package/src/features/metrics/aggregate/polyfill-detection.es5.js +9 -0
  201. package/src/features/metrics/aggregate/polyfill-detection.es5.test.js +16 -0
  202. package/src/features/metrics/aggregate/polyfill-detection.js +48 -0
  203. package/src/features/metrics/aggregate/polyfill-detection.test.js +163 -0
  204. package/src/features/page_action/aggregate/index.js +2 -2
  205. package/src/features/page_view_event/aggregate/index.js +5 -5
  206. package/src/features/page_view_timing/aggregate/index.js +2 -2
  207. package/src/features/session_replay/aggregate/index.js +319 -0
  208. package/src/features/session_replay/constants.js +3 -0
  209. package/src/features/session_replay/index.js +12 -0
  210. package/src/features/session_replay/instrument/index.js +22 -0
  211. package/src/features/session_trace/aggregate/index.js +148 -187
  212. package/src/features/session_trace/constants.js +0 -4
  213. package/src/features/session_trace/instrument/index.js +17 -69
  214. package/src/features/spa/aggregate/index.js +2 -2
  215. package/src/features/utils/agent-session.js +1 -2
  216. package/src/features/utils/aggregate-base.js +51 -0
  217. package/src/features/utils/feature-base.js +1 -31
  218. package/src/features/utils/handler-cache.js +3 -4
  219. package/src/features/utils/instrument-base.js +40 -8
  220. package/src/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
  221. package/src/loaders/agent.js +1 -1
  222. package/src/loaders/api/apiAsync.js +1 -1
  223. package/src/loaders/configure/configure.js +4 -3
  224. package/src/loaders/features/featureDependencies.js +0 -12
  225. package/src/loaders/features/features.js +3 -1
  226. package/src/loaders/micro-agent.js +4 -4
  227. package/dist/cjs/common/metrics/framework-detection.js +0 -72
  228. package/dist/cjs/common/util/user-agent.js +0 -57
  229. package/dist/cjs/common/window/supports-performance-observer.js +0 -15
  230. package/dist/esm/common/metrics/framework-detection.js +0 -66
  231. package/dist/esm/common/util/user-agent.js +0 -48
  232. package/dist/esm/common/window/supports-performance-observer.js +0 -9
  233. package/dist/types/common/metrics/framework-detection.d.ts.map +0 -1
  234. package/dist/types/common/util/user-agent.d.ts +0 -5
  235. package/dist/types/common/util/user-agent.d.ts.map +0 -1
  236. package/dist/types/common/window/supports-performance-observer.d.ts +0 -2
  237. package/dist/types/common/window/supports-performance-observer.d.ts.map +0 -1
  238. package/dist/types/features/utils/lazy-loader.d.ts.map +0 -1
  239. package/src/common/metrics/framework-detection.js +0 -71
  240. package/src/common/util/user-agent.js +0 -56
  241. package/src/common/window/supports-performance-observer.js +0 -10
  242. /package/dist/types/{common/metrics → features/metrics/aggregate}/framework-detection.d.ts +0 -0
@@ -1,61 +1,106 @@
1
1
  import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS } from '../../session/constants';
2
- import { globalScope } from '../../util/global-scope';
3
2
  import { gosNREUMInitializedAgents } from '../../window/nreum';
4
- import { Configurable } from './configurable';
5
- const model = {
6
- allow_bfcache: true,
7
- // *cli - temporary feature flag for BFCache work
8
- privacy: {
9
- cookies_enabled: true
10
- },
11
- // *cli - per discussion, default should be true
12
- ajax: {
13
- deny_list: undefined,
14
- enabled: true,
15
- harvestTimeSeconds: 10
16
- },
17
- distributed_tracing: {
18
- enabled: undefined,
19
- exclude_newrelic_header: undefined,
20
- cors_use_newrelic_header: undefined,
21
- cors_use_tracecontext_headers: undefined,
22
- allowed_origins: undefined
23
- },
24
- session: {
25
- domain: undefined,
26
- // used by first party cookies to set the top-level domain
27
- expiresMs: DEFAULT_EXPIRES_MS,
28
- inactiveMs: DEFAULT_INACTIVE_MS
29
- },
30
- ssl: undefined,
31
- obfuscate: undefined,
32
- jserrors: {
33
- enabled: true,
34
- harvestTimeSeconds: 10
35
- },
36
- metrics: {
37
- enabled: true
38
- },
39
- page_action: {
40
- enabled: true,
41
- harvestTimeSeconds: 30
42
- },
43
- page_view_event: {
44
- enabled: true
45
- },
46
- page_view_timing: {
47
- enabled: true,
48
- harvestTimeSeconds: 30,
49
- long_task: false
50
- },
51
- session_trace: {
52
- enabled: true,
53
- harvestTimeSeconds: 10
54
- },
55
- spa: {
56
- enabled: true,
57
- harvestTimeSeconds: 10
58
- }
3
+ import { getModeledObject } from './configurable';
4
+ const model = () => {
5
+ const hiddenState = {
6
+ blockSelector: '[data-nr-block]',
7
+ maskInputOptions: {
8
+ password: true
9
+ }
10
+ };
11
+ return {
12
+ allow_bfcache: true,
13
+ // *cli - temporary feature flag for BFCache work
14
+ privacy: {
15
+ cookies_enabled: true
16
+ },
17
+ // *cli - per discussion, default should be true
18
+ ajax: {
19
+ deny_list: undefined,
20
+ enabled: true,
21
+ harvestTimeSeconds: 10
22
+ },
23
+ distributed_tracing: {
24
+ enabled: undefined,
25
+ exclude_newrelic_header: undefined,
26
+ cors_use_newrelic_header: undefined,
27
+ cors_use_tracecontext_headers: undefined,
28
+ allowed_origins: undefined
29
+ },
30
+ session: {
31
+ domain: undefined,
32
+ // used by first party cookies to set the top-level domain
33
+ expiresMs: DEFAULT_EXPIRES_MS,
34
+ inactiveMs: DEFAULT_INACTIVE_MS
35
+ },
36
+ ssl: undefined,
37
+ obfuscate: undefined,
38
+ jserrors: {
39
+ enabled: true,
40
+ harvestTimeSeconds: 10
41
+ },
42
+ metrics: {
43
+ enabled: true
44
+ },
45
+ page_action: {
46
+ enabled: true,
47
+ harvestTimeSeconds: 30
48
+ },
49
+ page_view_event: {
50
+ enabled: true
51
+ },
52
+ page_view_timing: {
53
+ enabled: true,
54
+ harvestTimeSeconds: 30,
55
+ long_task: false
56
+ },
57
+ session_trace: {
58
+ enabled: true,
59
+ harvestTimeSeconds: 10
60
+ },
61
+ session_replay: {
62
+ // feature settings
63
+ enabled: false,
64
+ harvestTimeSeconds: 60,
65
+ sampleRate: 0.1,
66
+ errorSampleRate: 0.1,
67
+ // recording config settings
68
+ maskTextSelector: '*',
69
+ maskAllInputs: true,
70
+ // these properties only have getters because they are enforcable constants and should error if someone tries to override them
71
+ get blockClass() {
72
+ return 'nr-block';
73
+ },
74
+ get ignoreClass() {
75
+ return 'nr-ignore';
76
+ },
77
+ get maskTextClass() {
78
+ return 'nr-mask';
79
+ },
80
+ // props with a getter and setter are used to extend enforcable constants with customer input
81
+ // we must preserve data-nr-block no matter what else the customer sets
82
+ get blockSelector() {
83
+ return hiddenState.blockSelector;
84
+ },
85
+ set blockSelector(val) {
86
+ hiddenState.blockSelector += ",".concat(val);
87
+ },
88
+ // password: must always be present and true no matter what customer sets
89
+ get maskInputOptions() {
90
+ return hiddenState.maskInputOptions;
91
+ },
92
+ set maskInputOptions(val) {
93
+ hiddenState.maskInputOptions = {
94
+ ...val,
95
+ password: true
96
+ };
97
+ }
98
+ },
99
+ spa: {
100
+ enabled: true,
101
+ harvestTimeSeconds: 10
102
+ }
103
+ };
59
104
  };
60
105
  const _cache = {};
61
106
  export function getConfiguration(id) {
@@ -65,7 +110,7 @@ export function getConfiguration(id) {
65
110
  }
66
111
  export function setConfiguration(id, obj) {
67
112
  if (!id) throw new Error('All configuration objects require an agent identifier!');
68
- _cache[id] = new Configurable(obj, model);
113
+ _cache[id] = getModeledObject(obj, model());
69
114
  gosNREUMInitializedAgents(id, _cache[id], 'config');
70
115
  }
71
116
  export function getConfigurationValue(id, path) {
@@ -1,5 +1,5 @@
1
1
  import { gosNREUMInitializedAgents } from '../../window/nreum';
2
- import { Configurable } from './configurable';
2
+ import { getModeledObject } from './configurable';
3
3
  const model = {
4
4
  accountID: undefined,
5
5
  trustKey: undefined,
@@ -16,6 +16,6 @@ export function getLoaderConfig(id) {
16
16
  }
17
17
  export function setLoaderConfig(id, obj) {
18
18
  if (!id) throw new Error('All loader-config objects require an agent identifier!');
19
- _cache[id] = new Configurable(obj, model);
19
+ _cache[id] = getModeledObject(obj, model);
20
20
  gosNREUMInitializedAgents(id, _cache[id], 'loader_config');
21
21
  }
@@ -1,5 +1,4 @@
1
- import * as userAgent from '../../util/user-agent';
2
- import { Configurable } from './configurable';
1
+ import { getModeledObject } from './configurable';
3
2
  import { gosNREUMInitializedAgents } from '../../window/nreum';
4
3
  import { globalScope } from '../../util/global-scope';
5
4
  import { BUILD_ENV, DIST_METHOD, VERSION } from "../../constants/env.npm";
@@ -24,7 +23,6 @@ const model = {
24
23
  releaseIds: {},
25
24
  session: undefined,
26
25
  xhrWrappable: typeof globalScope.XMLHttpRequest?.prototype?.addEventListener === 'function',
27
- userAgent,
28
26
  version: VERSION
29
27
  };
30
28
  const _cache = {};
@@ -35,6 +33,6 @@ export function getRuntime(id) {
35
33
  }
36
34
  export function setRuntime(id, obj) {
37
35
  if (!id) throw new Error('All runtime objects require an agent identifier!');
38
- _cache[id] = new Configurable(obj, model);
36
+ _cache[id] = getModeledObject(obj, model);
39
37
  gosNREUMInitializedAgents(id, _cache[id], 'runtime');
40
38
  }
@@ -6,7 +6,7 @@
6
6
  /**
7
7
  * Exposes the version of the agent
8
8
  */
9
- export const VERSION = "1.232.1";
9
+ export const VERSION = "1.233.1";
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.232.1";
9
+ export const VERSION = "1.233.1";
10
10
 
11
11
  /**
12
12
  * Exposes the build type of the agent
@@ -59,7 +59,7 @@ export function drain() {
59
59
 
60
60
  // Only when the event-groups for all features are ready to drain (staged) do we execute the drain. This has the effect
61
61
  // that the last feature to call drain triggers drain for all features.
62
- const items = Array.from(registry[agentIdentifier]);
62
+ const items = [...registry[agentIdentifier]];
63
63
  if (items.every(_ref => {
64
64
  let [key, values] = _ref;
65
65
  return values.staged;
@@ -13,6 +13,17 @@ import { getConfigurationValue } from '../config/config';
13
13
  * Periodically invokes harvest calls and handles retries
14
14
  */
15
15
  export class HarvestScheduler extends SharedContext {
16
+ /**
17
+ * Create a HarvestScheduler
18
+ * @param {string} endpoint - The base BAM endpoint name -- ex. 'events'
19
+ * @param {object} opts - The options used to configure the HarvestScheduler
20
+ * @param {Function} opts.onFinished - The callback to be fired when a harvest has finished
21
+ * @param {Function} opts.getPayload - A callback which can be triggered to return a payload for harvesting
22
+ * @param {number} opts.retryDelay - The number of seconds to wait before retrying after a network failure
23
+ * @param {boolean} opts.raw - Use a prefabricated payload shape as the harvest payload without the need for formatting
24
+ * @param {string} opts.customUrl - A custom url that falls outside of the shape of the standard BAM harvester url pattern. Will use directly instead of concatenating various pieces
25
+ * @param {*} parent - The parent object, whose state can be passed into SharedContext
26
+ */
16
27
  constructor(endpoint, opts, parent) {
17
28
  super(parent); // gets any allowed properties from the parent and stores them in `sharedContext`
18
29
  this.endpoint = endpoint;
@@ -64,23 +75,47 @@ export class HarvestScheduler extends SharedContext {
64
75
  runHarvest(opts) {
65
76
  if (this.aborted) return;
66
77
  var scheduler = this;
78
+ let harvests = [];
79
+ let submitMethod;
67
80
  if (this.opts.getPayload) {
68
- // Ajax & PVT
69
- var submitMethod = getSubmitMethod(this.endpoint, opts);
81
+ // Ajax & PVT & SR
82
+ submitMethod = getSubmitMethod(this.endpoint, opts);
70
83
  if (!submitMethod) return false;
71
- var retry = submitMethod.method === submitData.xhr;
84
+ const retry = submitMethod.method === submitData.xhr;
72
85
  var payload = this.opts.getPayload({
73
86
  retry: retry
74
87
  });
75
- if (payload) {
76
- payload = Object.prototype.toString.call(payload) === '[object Array]' ? payload : [payload];
77
- for (var i = 0; i < payload.length; i++) {
78
- this.harvest.send(this.endpoint, payload[i], opts, submitMethod, onHarvestFinished);
88
+ if (!payload) {
89
+ if (this.started) {
90
+ this.scheduleHarvest();
79
91
  }
92
+ return;
80
93
  }
94
+ payload = Object.prototype.toString.call(payload) === '[object Array]' ? payload : [payload];
95
+ harvests.push(...payload);
96
+ }
97
+
98
+ /** sendX is used for features that do not supply a preformatted payload via "getPayload" */
99
+ let send = args => this.harvest.sendX(args);
100
+ if (harvests.length) {
101
+ /** _send is the underlying method for sending in the harvest, if sending raw we can bypass the other helpers completely which format the payloads */
102
+ if (this.opts.raw) send = args => this.harvest._send(args);
103
+ /** send is used to formated the payloads from "getPayload" and obfuscate before sending */else send = args => this.harvest.send(args);
81
104
  } else {
82
- this.harvest.sendX(this.endpoint, opts, onHarvestFinished);
105
+ // force it to run at least once in sendX mode
106
+ harvests.push(undefined);
83
107
  }
108
+ harvests.forEach(payload => {
109
+ send({
110
+ endpoint: this.endpoint,
111
+ payload,
112
+ opts,
113
+ submitMethod,
114
+ cbFinished: onHarvestFinished,
115
+ customUrl: this.opts.customUrl,
116
+ raw: this.opts.raw
117
+ });
118
+ });
84
119
  if (this.started) {
85
120
  this.scheduleHarvest();
86
121
  }
@@ -0,0 +1,37 @@
1
+ import { setConfiguration } from '../config/state/init';
2
+ import { HarvestScheduler } from './harvest-scheduler';
3
+ describe('runHarvest', () => {
4
+ it('should re-schedule harvest even if there is no accumulated data', () => {
5
+ setConfiguration('asdf', {});
6
+ const scheduler = new HarvestScheduler('events', {
7
+ getPayload: jest.fn()
8
+ }, {
9
+ agentIdentifier: 'asdf',
10
+ ee: {
11
+ on: jest.fn()
12
+ }
13
+ });
14
+ scheduler.started = true;
15
+ jest.spyOn(scheduler, 'scheduleHarvest');
16
+ scheduler.runHarvest();
17
+ expect(scheduler.opts.getPayload()).toBeFalsy();
18
+ expect(scheduler.scheduleHarvest).toHaveBeenCalledTimes(1);
19
+ });
20
+ it('should also re-schedule harvest if there is accumulated data', () => {
21
+ setConfiguration('asdf', {});
22
+ const scheduler = new HarvestScheduler('events', {
23
+ getPayload: jest.fn().mockImplementation(() => 'payload')
24
+ }, {
25
+ agentIdentifier: 'asdf',
26
+ ee: {
27
+ on: jest.fn()
28
+ }
29
+ });
30
+ scheduler.started = true;
31
+ scheduler.harvest._send = () => {};
32
+ jest.spyOn(scheduler, 'scheduleHarvest');
33
+ scheduler.runHarvest();
34
+ expect(scheduler.opts.getPayload()).toBeTruthy();
35
+ expect(scheduler.scheduleHarvest).toHaveBeenCalledTimes(1);
36
+ });
37
+ });
@@ -8,7 +8,7 @@ import { obj as encodeObj, param as encodeParam } from '../url/encode';
8
8
  import { stringify } from '../util/stringify';
9
9
  import { submitData } from '../util/submit-data';
10
10
  import { getLocation } from '../url/location';
11
- import { getInfo, getConfigurationValue, getRuntime, getConfiguration } from '../config/config';
11
+ import { getInfo, getConfigurationValue, getRuntime } from '../config/config';
12
12
  import { cleanURL } from '../url/clean-url';
13
13
  import { now } from '../timing/now';
14
14
  import { eventListenerOpts } from '../event-listener/event-listener-opts';
@@ -17,6 +17,24 @@ import { applyFnToProps } from '../util/traverse';
17
17
  import { SharedContext } from '../context/shared-context';
18
18
  import { VERSION } from "../constants/env.npm";
19
19
  import { isBrowserScope, isWorkerScope } from '../util/global-scope';
20
+
21
+ /**
22
+ * @typedef {object} NetworkSendSpec
23
+ * @param {string} endpoint The endpoint to use (jserrors, events, resources etc.)
24
+ * @param {object} payload Object representing payload.
25
+ * @param {object} payload.qs Map of values that should be sent as part of the request query string.
26
+ * @param {string} payload.body String that should be sent as the body of the request.
27
+ * @param {string} payload.body.e Special case of body used for browser interactions.
28
+ * @param {object} opts Additional options for sending data
29
+ * @param {boolean} opts.needResponse Specify whether the caller expects a response data.
30
+ * @param {boolean} opts.unload Specify whether the call is a final harvest during page unload.
31
+ * @param {boolean} opts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
32
+ * @param {function} submitMethod The submit method to use {@link ../util/submit-data}
33
+ * @param {string} customUrl Override the beacon url the data is sent to; must include protocol if defined
34
+ * @param {boolean} gzip Enabled gzip compression on the body of the request before it is sent
35
+ * @param {boolean} includeBaseParams Enables the use of base query parameters in the beacon url {@see Harvest.baseQueryString}
36
+ */
37
+
20
38
  const haveSendBeacon = !!navigator.sendBeacon; // only the web window obj has sendBeacon at this time, so 'false' for other envs
21
39
 
22
40
  export class Harvest extends SharedContext {
@@ -32,62 +50,78 @@ export class Harvest extends SharedContext {
32
50
  /**
33
51
  * Initiate a harvest from multiple sources. An event that corresponds to the endpoint
34
52
  * name is emitted, which gives any listeners the opportunity to provide payload data.
35
- *
36
- * @param {string} endpoint - The endpoint of the harvest (jserrors, events, resources etc.)
37
- *
38
- * @param {object} opts
39
- * @param {bool} opts.needResponse - Specify whether the caller expects a response data.
40
- * @param {bool} opts.unload - Specify whether the call is a final harvest during page unload.
53
+ * @param {NetworkSendSpec} spec Specification for sending data
41
54
  */
42
- sendX(endpoint, opts, cbFinished) {
55
+ sendX(spec) {
56
+ const {
57
+ endpoint,
58
+ opts
59
+ } = spec;
43
60
  var submitMethod = getSubmitMethod(endpoint, opts);
44
61
  if (!submitMethod) return false;
45
62
  var options = {
46
63
  retry: submitMethod.method === submitData.xhr
47
64
  };
48
- return this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend(endpoint, this.createPayload(endpoint, options), opts, submitMethod, cbFinished) : this._send(endpoint, this.createPayload(endpoint, options), opts, submitMethod, cbFinished);
65
+ const payload = this.createPayload(endpoint, options);
66
+ var caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this);
67
+ return caller({
68
+ ...spec,
69
+ payload,
70
+ submitMethod
71
+ });
49
72
  }
50
73
 
51
74
  /**
52
- * Initiate a harvest call.
53
- *
54
- * @param {string} endpoint - The endpoint of the harvest (jserrors, events, resources etc.)
55
- * @param {object} nr - The loader singleton.
56
- *
57
- * @param {object} singlePayload - Object representing payload.
58
- * @param {object} singlePayload.qs - Map of values that should be sent as part of the request query string.
59
- * @param {string} singlePayload.body - String that should be sent as the body of the request.
60
- * @param {string} singlePayload.body.e - Special case of body used for browser interactions.
61
- *
62
- * @param {object} opts
63
- * @param {bool} opts.needResponse - Specify whether the caller expects a response data.
64
- * @param {bool} opts.unload - Specify whether the call is a final harvest during page unload.
65
- */
66
- send(endpoint, singlePayload, opts, submitMethod, cbFinished) {
67
- var _this = this;
75
+ * Initiate a harvest call.
76
+ * @param {NetworkSendSpec} spec Specification for sending data
77
+ */
78
+ send(spec) {
79
+ const {
80
+ payload = {}
81
+ } = spec;
68
82
  var makeBody = createAccumulator();
69
83
  var makeQueryString = createAccumulator();
70
- if (singlePayload.body) mapOwn(singlePayload.body, makeBody);
71
- if (singlePayload.qs) mapOwn(singlePayload.qs, makeQueryString);
72
- var payload = {
84
+ if (payload.body) mapOwn(payload.body, makeBody);
85
+ if (payload.qs) mapOwn(payload.qs, makeQueryString);
86
+ var newPayload = {
73
87
  body: makeBody(),
74
88
  qs: makeQueryString()
75
89
  };
76
- var caller = this.obfuscator.shouldObfuscate() ? function () {
77
- return _this.obfuscateAndSend(...arguments);
78
- } : function () {
79
- return _this._send(...arguments);
80
- };
81
- return caller(endpoint, payload, opts, submitMethod, cbFinished);
90
+ var caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this);
91
+ return caller({
92
+ ...spec,
93
+ payload: newPayload
94
+ });
82
95
  }
83
- obfuscateAndSend(endpoint, payload, opts, submitMethod, cbFinished) {
84
- var _this2 = this;
96
+
97
+ /**
98
+ * Apply obfuscation rules to the payload and then initial the harvest network call.
99
+ * @param {NetworkSendSpec} spec Specification for sending data
100
+ */
101
+ obfuscateAndSend(spec) {
102
+ var _this = this;
103
+ const {
104
+ payload = {}
105
+ } = spec;
85
106
  applyFnToProps(payload, function () {
86
- return _this2.obfuscator.obfuscateString(...arguments);
107
+ return _this.obfuscator.obfuscateString(...arguments);
87
108
  }, 'string', ['e']);
88
- return this._send(endpoint, payload, opts, submitMethod, cbFinished);
109
+ return this._send({
110
+ ...spec,
111
+ payload
112
+ });
89
113
  }
90
- _send(endpoint, payload, opts, submitMethod, cbFinished) {
114
+ _send(_ref) {
115
+ let {
116
+ endpoint,
117
+ payload = {},
118
+ opts = {},
119
+ submitMethod,
120
+ cbFinished,
121
+ customUrl,
122
+ raw,
123
+ includeBaseParams = true
124
+ } = _ref;
91
125
  var info = getInfo(this.sharedContext.agentIdentifier);
92
126
  if (!info.errorBeacon) return false;
93
127
  var agentRuntime = getRuntime(this.sharedContext.agentIdentifier);
@@ -100,38 +134,54 @@ export class Harvest extends SharedContext {
100
134
  }
101
135
  return false;
102
136
  }
103
- if (!opts) opts = {};
104
- var url = this.getScheme() + '://' + info.errorBeacon + '/' + endpoint + '/1/' + info.licenseKey + this.baseQueryString();
105
- if (payload.qs) url += encodeObj(payload.qs, agentRuntime.maxBytes);
137
+ let url = '';
138
+ if (customUrl) url = customUrl;else if (raw) url = "".concat(this.getScheme(), "://").concat(info.errorBeacon, "/").concat(endpoint);else url = "".concat(this.getScheme(), "://").concat(info.errorBeacon, "/").concat(endpoint, "/1/").concat(info.licenseKey);
139
+ var baseParams = !raw && includeBaseParams ? this.baseQueryString() : '';
140
+ var payloadParams = payload.qs ? encodeObj(payload.qs, agentRuntime.maxBytes) : '';
106
141
  if (!submitMethod) {
107
142
  submitMethod = getSubmitMethod(endpoint, opts);
108
143
  }
109
144
  var method = submitMethod.method;
110
145
  var useBody = submitMethod.useBody;
111
146
  var body;
112
- var fullUrl = url;
113
- if (useBody && endpoint === 'events') {
114
- body = payload.body.e;
115
- } else if (useBody) {
116
- body = stringify(payload.body);
117
- } else {
118
- fullUrl = url + encodeObj(payload.body, agentRuntime.maxBytes);
119
- }
147
+ var fullUrl = "".concat(url, "?").concat(baseParams).concat(payloadParams);
148
+ const gzip = payload?.qs?.content_encoding === 'gzip';
149
+ if (!gzip) {
150
+ if (useBody && endpoint === 'events') {
151
+ body = payload.body.e;
152
+ } else if (useBody) {
153
+ body = stringify(payload.body);
154
+ } else {
155
+ fullUrl = fullUrl + encodeObj(payload.body, agentRuntime.maxBytes);
156
+ }
157
+ } else body = payload.body;
120
158
 
121
159
  // Get bytes harvested per endpoint as a supportability metric. See metrics aggregator (on unload).
122
160
  agentRuntime.bytesSent[endpoint] = (agentRuntime.bytesSent[endpoint] || 0) + body?.length || 0;
123
161
  // Get query bytes harvested per endpoint as a supportability metric. See metrics aggregator (on unload).
124
162
  agentRuntime.queryBytesSent[endpoint] = (agentRuntime.queryBytesSent[endpoint] || 0) + fullUrl.split('?').slice(-1)[0]?.length || 0;
163
+ const headers = [];
164
+ headers.push({
165
+ key: 'content-type',
166
+ value: 'text/plain'
167
+ });
125
168
 
126
169
  /* Since workers don't support sendBeacon right now, or Image(), they can only use XHR method.
127
170
  Because they still do permit synch XHR, the idea is that at final harvest time (worker is closing),
128
171
  we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon. */
129
- var result = method(fullUrl, body, opts.unload && isWorkerScope);
172
+
173
+ var result = method({
174
+ url: fullUrl,
175
+ body,
176
+ sync: opts.unload && isWorkerScope,
177
+ headers
178
+ });
130
179
  if (cbFinished && method === submitData.xhr) {
131
180
  var xhr = result;
132
181
  xhr.addEventListener('load', function () {
133
182
  var result = {
134
- sent: true
183
+ sent: true,
184
+ status: this.status
135
185
  };
136
186
  if (this.status === 429) {
137
187
  result.retry = true;
@@ -149,7 +199,9 @@ export class Harvest extends SharedContext {
149
199
  // if beacon request failed, retry with an alternative method -- will not happen for workers
150
200
  if (!result && method === submitData.beacon) {
151
201
  method = submitData.img;
152
- result = method(url + encodeObj(payload.body, agentRuntime.maxBytes));
202
+ result = method({
203
+ url: fullUrl + encodeObj(payload.body, agentRuntime.maxBytes)
204
+ });
153
205
  }
154
206
  return result;
155
207
  }
@@ -160,9 +212,9 @@ export class Harvest extends SharedContext {
160
212
  var info = getInfo(this.sharedContext.agentIdentifier);
161
213
  var location = cleanURL(getLocation());
162
214
  var ref = this.obfuscator.shouldObfuscate() ? this.obfuscator.obfuscateString(location) : location;
163
- return ['?a=' + info.applicationID, encodeParam('sa', info.sa ? '' + info.sa : ''), encodeParam('v', VERSION), transactionNameParam(info), encodeParam('ct', runtime.customTransaction), '&rst=' + now(), '&ck=0',
215
+ return ['a=' + info.applicationID, encodeParam('sa', info.sa ? '' + info.sa : ''), encodeParam('v', VERSION), transactionNameParam(info), encodeParam('ct', runtime.customTransaction), '&rst=' + now(), '&ck=0',
164
216
  // ck param DEPRECATED - still expected by backend
165
- '&s=' + (runtime.session?.value || '0'),
217
+ '&s=' + (runtime.session?.state.value || '0'),
166
218
  // the 0 id encaps all untrackable and default traffic
167
219
  encodeParam('ref', ref), encodeParam('ptid', runtime.ptid ? '' + runtime.ptid : '')].join('');
168
220
  }
@@ -232,7 +284,7 @@ function createAccumulator() {
232
284
  var accumulator = {};
233
285
  var hasData = false;
234
286
  return function (key, val) {
235
- if (val && val.length) {
287
+ if (val !== null && val !== undefined && val.length) {
236
288
  accumulator[key] = val;
237
289
  hasData = true;
238
290
  }