@newrelic/browser-agent 0.1.230 → 0.1.231

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 (221) hide show
  1. package/README.md +25 -1
  2. package/dist/cjs/common/browser-version/ios-version.js +4 -3
  3. package/dist/cjs/common/config/state/configurable.js +1 -1
  4. package/dist/cjs/common/config/state/info.js +1 -1
  5. package/dist/cjs/common/config/state/init.js +1 -1
  6. package/dist/cjs/common/config/state/loader-config.js +1 -1
  7. package/dist/cjs/common/config/state/runtime.js +5 -5
  8. package/dist/cjs/common/constants/env.cdn.js +29 -0
  9. package/dist/cjs/common/constants/env.js +32 -0
  10. package/dist/cjs/common/constants/env.npm.js +30 -0
  11. package/dist/cjs/common/event-emitter/contextual-ee.test.js +282 -0
  12. package/dist/cjs/common/event-emitter/handle.test.js +58 -0
  13. package/dist/cjs/common/event-emitter/register-handler.test.js +55 -0
  14. package/dist/cjs/common/harvest/harvest.js +2 -2
  15. package/dist/cjs/common/ids/id.js +14 -6
  16. package/dist/cjs/common/ids/id.test.js +85 -0
  17. package/dist/cjs/common/ids/unique-id.js +75 -51
  18. package/dist/cjs/common/ids/unique-id.test.js +49 -0
  19. package/dist/cjs/common/timing/nav-timing.js +51 -30
  20. package/dist/cjs/common/timing/nav-timing.test.js +192 -0
  21. package/dist/cjs/common/url/clean-url.test.js +9 -0
  22. package/dist/cjs/common/url/encode.test.js +74 -0
  23. package/dist/cjs/common/url/location.js +4 -0
  24. package/dist/cjs/common/url/location.test.js +13 -0
  25. package/dist/cjs/common/url/parse-url.test.js +111 -0
  26. package/dist/cjs/common/url/protocol.js +2 -12
  27. package/dist/cjs/common/url/protocol.test.js +16 -0
  28. package/dist/cjs/common/util/console.js +1 -1
  29. package/dist/cjs/common/util/map-own.test.js +3 -3
  30. package/dist/cjs/common/util/obfuscate.js +1 -1
  31. package/dist/cjs/common/window/page-visibility.js +2 -1
  32. package/dist/cjs/common/wrap/index.js +0 -7
  33. package/dist/cjs/common/wrap/wrap-events.js +6 -9
  34. package/dist/cjs/common/wrap/wrap-fetch.js +6 -6
  35. package/dist/cjs/common/wrap/wrap-history.js +7 -6
  36. package/dist/cjs/common/wrap/wrap-jsonp.js +7 -6
  37. package/dist/cjs/common/wrap/wrap-mutation.js +7 -6
  38. package/dist/cjs/common/wrap/wrap-promise.js +7 -6
  39. package/dist/cjs/common/wrap/wrap-promise.test.js +119 -0
  40. package/dist/cjs/common/wrap/wrap-raf.js +6 -6
  41. package/dist/cjs/common/wrap/wrap-timer.js +6 -6
  42. package/dist/cjs/common/wrap/wrap-xhr.js +5 -6
  43. package/dist/cjs/features/ajax/aggregate/index.js +1 -1
  44. package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +5 -5
  45. package/dist/cjs/features/jserrors/aggregate/format-stack-trace.test.js +1 -1
  46. package/dist/cjs/features/jserrors/aggregate/index.js +3 -3
  47. package/dist/cjs/features/jserrors/instrument/index.js +2 -2
  48. package/dist/cjs/features/metrics/aggregate/index.js +6 -7
  49. package/dist/cjs/features/metrics/instrument/index.js +0 -25
  50. package/dist/cjs/features/metrics/instrument/workers-helper.js +5 -5
  51. package/dist/cjs/features/page_action/aggregate/index.js +1 -1
  52. package/dist/cjs/features/page_view_event/aggregate/index.js +17 -6
  53. package/dist/cjs/features/page_view_timing/aggregate/index.js +36 -26
  54. package/dist/cjs/features/session_trace/aggregate/index.js +16 -13
  55. package/dist/cjs/features/utils/instrument-base.js +6 -2
  56. package/dist/cjs/features/utils/lazy-loader.js +1 -1
  57. package/dist/cjs/loaders/agent.js +1 -1
  58. package/dist/cjs/loaders/api/api.js +8 -5
  59. package/dist/cjs/loaders/features/enabled-features.js +1 -1
  60. package/dist/cjs/loaders/micro-agent.js +2 -1
  61. package/dist/esm/common/browser-version/ios-version.js +4 -3
  62. package/dist/esm/common/config/state/configurable.js +1 -1
  63. package/dist/esm/common/config/state/info.js +1 -1
  64. package/dist/esm/common/config/state/init.js +1 -1
  65. package/dist/esm/common/config/state/loader-config.js +1 -1
  66. package/dist/esm/common/config/state/runtime.js +2 -2
  67. package/dist/esm/common/constants/env.cdn.js +20 -0
  68. package/dist/esm/common/constants/env.js +23 -0
  69. package/dist/esm/common/constants/env.npm.js +21 -0
  70. package/dist/esm/common/event-emitter/contextual-ee.test.js +278 -0
  71. package/dist/esm/common/event-emitter/handle.test.js +54 -0
  72. package/dist/esm/common/event-emitter/register-handler.test.js +51 -0
  73. package/dist/esm/common/harvest/harvest.js +1 -1
  74. package/dist/esm/common/ids/id.js +16 -6
  75. package/dist/esm/common/ids/id.test.js +81 -0
  76. package/dist/esm/common/ids/unique-id.js +75 -51
  77. package/dist/esm/common/ids/unique-id.test.js +44 -0
  78. package/dist/esm/common/timing/nav-timing.js +51 -29
  79. package/dist/esm/common/timing/nav-timing.test.js +190 -0
  80. package/dist/esm/common/url/clean-url.test.js +7 -0
  81. package/dist/esm/common/url/encode.test.js +70 -0
  82. package/dist/esm/common/url/location.js +4 -0
  83. package/dist/esm/common/url/location.test.js +11 -0
  84. package/dist/esm/common/url/parse-url.test.js +107 -0
  85. package/dist/esm/common/url/protocol.js +3 -12
  86. package/dist/esm/common/url/protocol.test.js +14 -0
  87. package/dist/esm/common/util/console.js +1 -1
  88. package/dist/esm/common/util/map-own.test.js +3 -3
  89. package/dist/esm/common/util/obfuscate.js +2 -2
  90. package/dist/esm/common/window/page-visibility.js +2 -1
  91. package/dist/esm/common/wrap/index.js +1 -2
  92. package/dist/esm/common/wrap/wrap-events.js +6 -9
  93. package/dist/esm/common/wrap/wrap-fetch.js +6 -6
  94. package/dist/esm/common/wrap/wrap-history.js +7 -6
  95. package/dist/esm/common/wrap/wrap-jsonp.js +7 -6
  96. package/dist/esm/common/wrap/wrap-mutation.js +7 -6
  97. package/dist/esm/common/wrap/wrap-promise.js +7 -6
  98. package/dist/esm/common/wrap/wrap-promise.test.js +115 -0
  99. package/dist/esm/common/wrap/wrap-raf.js +6 -6
  100. package/dist/esm/common/wrap/wrap-timer.js +6 -6
  101. package/dist/esm/common/wrap/wrap-xhr.js +5 -6
  102. package/dist/esm/features/ajax/aggregate/index.js +1 -1
  103. package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +5 -5
  104. package/dist/esm/features/jserrors/aggregate/format-stack-trace.test.js +1 -1
  105. package/dist/esm/features/jserrors/aggregate/index.js +3 -3
  106. package/dist/esm/features/jserrors/instrument/index.js +2 -2
  107. package/dist/esm/features/metrics/aggregate/index.js +7 -8
  108. package/dist/esm/features/metrics/instrument/index.js +0 -25
  109. package/dist/esm/features/metrics/instrument/workers-helper.js +5 -5
  110. package/dist/esm/features/page_action/aggregate/index.js +1 -1
  111. package/dist/esm/features/page_view_event/aggregate/index.js +17 -6
  112. package/dist/esm/features/page_view_timing/aggregate/index.js +36 -26
  113. package/dist/esm/features/session_trace/aggregate/index.js +16 -13
  114. package/dist/esm/features/utils/instrument-base.js +1 -1
  115. package/dist/esm/features/utils/lazy-loader.js +1 -1
  116. package/dist/esm/loaders/agent.js +1 -1
  117. package/dist/esm/loaders/api/api.js +4 -4
  118. package/dist/esm/loaders/features/enabled-features.js +1 -1
  119. package/dist/types/common/config/state/runtime.d.ts.map +1 -1
  120. package/dist/types/common/constants/env.cdn.d.ts +18 -0
  121. package/dist/types/common/constants/env.cdn.d.ts.map +1 -0
  122. package/dist/types/common/constants/env.d.ts +13 -0
  123. package/dist/types/common/constants/env.d.ts.map +1 -0
  124. package/dist/types/common/constants/env.npm.d.ts +19 -0
  125. package/dist/types/common/constants/env.npm.d.ts.map +1 -0
  126. package/dist/types/common/ids/id.d.ts +11 -1
  127. package/dist/types/common/ids/id.d.ts.map +1 -1
  128. package/dist/types/common/ids/unique-id.d.ts +24 -1
  129. package/dist/types/common/ids/unique-id.d.ts.map +1 -1
  130. package/dist/types/common/timing/nav-timing.d.ts +1 -2
  131. package/dist/types/common/timing/nav-timing.d.ts.map +1 -1
  132. package/dist/types/common/unload/eol.d.ts.map +1 -1
  133. package/dist/types/common/url/location.d.ts +4 -0
  134. package/dist/types/common/url/location.d.ts.map +1 -1
  135. package/dist/types/common/url/parse-url.d.ts.map +1 -1
  136. package/dist/types/common/url/protocol.d.ts +1 -6
  137. package/dist/types/common/url/protocol.d.ts.map +1 -1
  138. package/dist/types/common/util/global-scope.d.ts.map +1 -1
  139. package/dist/types/common/wrap/index.d.ts +1 -2
  140. package/dist/types/common/wrap/index.d.ts.map +1 -1
  141. package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
  142. package/dist/types/common/wrap/wrap-history.d.ts.map +1 -1
  143. package/dist/types/common/wrap/wrap-jsonp.d.ts.map +1 -1
  144. package/dist/types/common/wrap/wrap-mutation.d.ts.map +1 -1
  145. package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
  146. package/dist/types/common/wrap/wrap-raf.d.ts.map +1 -1
  147. package/dist/types/common/wrap/wrap-timer.d.ts.map +1 -1
  148. package/dist/types/common/wrap/wrap-xhr.d.ts.map +1 -1
  149. package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
  150. package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
  151. package/dist/types/features/metrics/instrument/index.d.ts +0 -1
  152. package/dist/types/features/metrics/instrument/index.d.ts.map +1 -1
  153. package/dist/types/features/metrics/instrument/workers-helper.d.ts.map +1 -1
  154. package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
  155. package/dist/types/features/page_view_timing/aggregate/index.d.ts +1 -2
  156. package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
  157. package/dist/types/features/session_trace/aggregate/index.d.ts +1 -1
  158. package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
  159. package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
  160. package/dist/types/features/spa/instrument/index.d.ts.map +1 -1
  161. package/package.json +9 -30
  162. package/src/common/browser-version/ios-version.js +4 -3
  163. package/src/common/config/state/runtime.js +26 -24
  164. package/src/common/constants/env.cdn.js +20 -0
  165. package/src/common/constants/env.js +23 -0
  166. package/src/common/constants/env.npm.js +21 -0
  167. package/src/common/event-emitter/contextual-ee.test.js +310 -0
  168. package/src/common/event-emitter/handle.test.js +56 -0
  169. package/src/common/event-emitter/register-handler.test.js +61 -0
  170. package/src/common/harvest/harvest.js +2 -2
  171. package/src/common/ids/id.js +15 -6
  172. package/src/common/ids/id.test.js +92 -0
  173. package/src/common/ids/unique-id.js +77 -54
  174. package/src/common/ids/unique-id.test.js +58 -0
  175. package/src/common/timing/nav-timing.js +50 -30
  176. package/src/common/timing/nav-timing.test.js +161 -0
  177. package/src/common/unload/eol.js +1 -2
  178. package/src/common/url/clean-url.test.js +25 -0
  179. package/src/common/url/encode.test.js +80 -0
  180. package/src/common/url/location.js +4 -0
  181. package/src/common/url/location.test.js +15 -0
  182. package/src/common/url/parse-url.js +1 -2
  183. package/src/common/url/parse-url.test.js +110 -0
  184. package/src/common/url/protocol.js +3 -13
  185. package/src/common/url/protocol.test.js +18 -0
  186. package/src/common/util/global-scope.js +1 -2
  187. package/src/common/util/obfuscate.js +2 -2
  188. package/src/common/window/page-visibility.js +1 -1
  189. package/src/common/wrap/index.js +1 -2
  190. package/src/common/wrap/wrap-events.js +5 -5
  191. package/src/common/wrap/wrap-fetch.js +4 -3
  192. package/src/common/wrap/wrap-history.js +6 -3
  193. package/src/common/wrap/wrap-jsonp.js +5 -3
  194. package/src/common/wrap/wrap-mutation.js +6 -3
  195. package/src/common/wrap/wrap-promise.js +7 -6
  196. package/src/common/wrap/wrap-promise.test.js +140 -0
  197. package/src/common/wrap/wrap-raf.js +5 -3
  198. package/src/common/wrap/wrap-timer.js +5 -3
  199. package/src/common/wrap/wrap-xhr.js +4 -3
  200. package/src/features/ajax/instrument/index.js +1 -1
  201. package/src/features/jserrors/instrument/index.js +4 -2
  202. package/src/features/metrics/aggregate/index.js +3 -4
  203. package/src/features/metrics/instrument/index.js +0 -30
  204. package/src/features/metrics/instrument/workers-helper.js +9 -6
  205. package/src/features/page_view_event/aggregate/index.js +15 -6
  206. package/src/features/page_view_timing/aggregate/index.js +36 -25
  207. package/src/features/page_view_timing/long-tasks.js +10 -10
  208. package/src/features/session_trace/aggregate/index.js +15 -12
  209. package/src/features/session_trace/instrument/index.js +3 -2
  210. package/src/features/spa/instrument/index.js +4 -2
  211. package/src/loaders/api/api.js +1 -1
  212. package/dist/cjs/common/constants/environment-variables.js +0 -20
  213. package/dist/cjs/common/wrap/wrap-console.js +0 -54
  214. package/dist/esm/common/constants/environment-variables.js +0 -11
  215. package/dist/esm/common/wrap/wrap-console.js +0 -46
  216. package/dist/types/common/constants/environment-variables.d.ts +0 -4
  217. package/dist/types/common/constants/environment-variables.d.ts.map +0 -1
  218. package/dist/types/common/wrap/wrap-console.d.ts +0 -16
  219. package/dist/types/common/wrap/wrap-console.d.ts.map +0 -1
  220. package/src/common/constants/environment-variables.js +0 -11
  221. package/src/common/wrap/wrap-console.js +0 -47
@@ -0,0 +1,110 @@
1
+ afterEach(() => {
2
+ jest.resetModules()
3
+ jest.clearAllMocks()
4
+ })
5
+
6
+ const urlTests = [
7
+ {
8
+ input: 'http://example.com/path/name?qs=5&a=b',
9
+ expected: {
10
+ hostname: 'example.com',
11
+ pathname: '/path/name',
12
+ protocol: 'http',
13
+ port: '80',
14
+ sameOrigin: false
15
+ }
16
+ },
17
+ {
18
+ input: 'http://foo:bar@example.com:8080/path/@name?qs=5&a=b',
19
+ expected: {
20
+ hostname: 'example.com',
21
+ pathname: '/path/@name',
22
+ protocol: 'http',
23
+ port: '8080',
24
+ sameOrigin: false
25
+ }
26
+ },
27
+ {
28
+ input: 'https://foo:bar@example.com/path/name?qs=5&a=b',
29
+ expected: {
30
+ hostname: 'example.com',
31
+ pathname: '/path/name',
32
+ protocol: 'https',
33
+ port: '443',
34
+ sameOrigin: false
35
+ }
36
+ },
37
+ {
38
+ input: '/path/name?qs=5&a=b',
39
+ expected: {
40
+ hostname: location.hostname,
41
+ pathname: '/path/name',
42
+ protocol: location.protocol.split(':')[0],
43
+ port: '80',
44
+ sameOrigin: true
45
+ }
46
+ },
47
+ {
48
+ input: location.protocol + '//' + location.hostname + ':' + location.port + '/path/name?qs=5&a=b',
49
+ expected: {
50
+ hostname: location.hostname,
51
+ pathname: '/path/name',
52
+ protocol: location.protocol.split(':')[0],
53
+ port: '80',
54
+ sameOrigin: true
55
+ }
56
+ },
57
+ {
58
+ input: 'data:text/plain;base64,SGVsbG8sIFdvcmxkIQ==',
59
+ expected: {
60
+ protocol: 'data'
61
+ }
62
+ }
63
+ ]
64
+
65
+ test.each(urlTests)('verify url parsing inside browser scope', async ({ input, expected }) => {
66
+ jest.doMock('../util/global-scope', () => ({
67
+ __esModule: true,
68
+ isBrowserScope: true,
69
+ globalScope: global
70
+ }))
71
+
72
+ const { parseUrl } = await import('./parse-url')
73
+ expect(parseUrl(input)).toEqual(expected)
74
+ })
75
+
76
+ test.each(urlTests)('verify url parsing outside browser scope', async ({ input, expected }) => {
77
+ jest.doMock('../util/global-scope', () => ({
78
+ __esModule: true,
79
+ isBrowserScope: false,
80
+ globalScope: global
81
+ }))
82
+
83
+ const { parseUrl } = await import('./parse-url')
84
+ expect(parseUrl(input)).toEqual(expected)
85
+ })
86
+
87
+ test('should cache parsed urls', async () => {
88
+ jest.doMock('../util/global-scope', () => ({
89
+ __esModule: true,
90
+ isBrowserScope: true,
91
+ globalScope: global
92
+ }))
93
+
94
+ const input = 'http://example.com/'
95
+ const expected = {
96
+ hostname: 'example.com',
97
+ pathname: '/',
98
+ protocol: 'http',
99
+ port: '80',
100
+ sameOrigin: false
101
+ }
102
+
103
+ jest.spyOn(document, 'createElement')
104
+
105
+ const { parseUrl } = await import('./parse-url')
106
+ parseUrl(input)
107
+
108
+ expect(parseUrl(input)).toEqual(expected)
109
+ expect(document.createElement).toHaveBeenCalledTimes(1)
110
+ })
@@ -2,18 +2,8 @@
2
2
  * Copyright 2020 New Relic Corporation. All rights reserved.
3
3
  * SPDX-License-Identifier: Apache-2.0
4
4
  */
5
- import { getGlobalScope } from '../util/global-scope'
5
+ import { globalScope } from '../util/global-scope'
6
6
 
7
- export const protocol = {
8
- isFileProtocol: isFileProtocol,
9
- supportabilityMetricSent: false
10
- }
11
-
12
- function isFileProtocol () {
13
- let isFile = Boolean(getGlobalScope()?.location?.protocol === 'file:')
14
- if (isFile) {
15
- //metrics.recordSupportability('Generic/FileProtocol/Detected') -- may be implemented later? Probably make sure it's once per window
16
- protocol.supportabilityMetricSent = true
17
- }
18
- return isFile
7
+ export function isFileProtocol () {
8
+ return Boolean(globalScope?.location?.protocol === 'file:')
19
9
  }
@@ -0,0 +1,18 @@
1
+ import { faker } from '@faker-js/faker'
2
+ import { isFileProtocol } from './protocol'
3
+
4
+ test('should return true when location url contains file protocol', () => {
5
+ jest.spyOn(window, 'location', 'get').mockReturnValue({
6
+ protocol: 'file:'
7
+ })
8
+
9
+ expect(isFileProtocol()).toEqual(true)
10
+ })
11
+
12
+ test('should return false when location url does not contains file protocol', () => {
13
+ jest.spyOn(window, 'location', 'get').mockReturnValue({
14
+ protocol: 'http:'
15
+ })
16
+
17
+ expect(isFileProtocol()).toEqual(false)
18
+ })
@@ -38,8 +38,7 @@ export function resetScope () {
38
38
  } else if (self instanceof WorkerGlobalScope) {
39
39
  globalScope = self
40
40
  }
41
- }
42
- else {
41
+ } else {
43
42
  throw new Error('New Relic browser agent shutting down due to error: Unable to locate global scope. This is possibly due to code redefining browser global variables like "self" and "window".')
44
43
  }
45
44
  }
@@ -1,6 +1,6 @@
1
1
  import { getConfigurationValue } from '../config/config'
2
2
  import { SharedContext } from '../context/shared-context'
3
- import { protocol } from '../url/protocol'
3
+ import { isFileProtocol } from '../url/protocol'
4
4
  import { warn } from './console'
5
5
 
6
6
  var fileProtocolRule = {
@@ -41,7 +41,7 @@ export function getRules (agentIdentifier) {
41
41
 
42
42
  rules = rules.concat(configRules)
43
43
 
44
- if (protocol.isFileProtocol()) rules.push(fileProtocolRule)
44
+ if (isFileProtocol()) rules.push(fileProtocolRule)
45
45
  // could add additional runtime/environment-specific rules here
46
46
 
47
47
  return rules
@@ -17,7 +17,7 @@ export function subscribeToVisibilityChange (cb, toHiddenOnly = false) {
17
17
  function handleVisibilityChange () {
18
18
  if (toHiddenOnly) { // trigger cb on change to hidden state only
19
19
  if (document.visibilityState == 'hidden') cb()
20
- else return
20
+ return
21
21
  }
22
22
  cb(document.visibilityState)
23
23
  }
@@ -2,7 +2,6 @@
2
2
  * @file Wraps assorted native objects and functions for instrumentation.
3
3
  */
4
4
 
5
- import { wrapConsole } from './wrap-console'
6
5
  import { wrapEvents } from './wrap-events'
7
6
  import { wrapFetch } from './wrap-fetch'
8
7
  import { wrapHistory } from './wrap-history'
@@ -14,5 +13,5 @@ import { wrapTimer } from './wrap-timer'
14
13
  import { wrapXhr } from './wrap-xhr'
15
14
 
16
15
  export {
17
- wrapConsole, wrapEvents, wrapFetch, wrapHistory, wrapJsonP, wrapMutation, wrapPromise, wrapRaf, wrapTimer, wrapXhr
16
+ wrapEvents, wrapFetch, wrapHistory, wrapJsonP, wrapMutation, wrapPromise, wrapRaf, wrapTimer, wrapXhr
18
17
  }
@@ -26,16 +26,16 @@ const REMOVE_EVENT_LISTENER = 'removeEventListener'
26
26
  */
27
27
  export function wrapEvents (sharedEE) {
28
28
  var ee = scopedEE(sharedEE)
29
- if (wrapped[ee.debugId]++) // Notice if our wrapping never ran yet, the falsey NaN will not early return; but if it has,
30
- { return ee } // then we increment the count to track # of feats using this at runtime.
31
- wrapped[ee.debugId] = 1
32
29
 
30
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
31
+ // then we increment the count to track # of feats using this at runtime.
32
+ if (wrapped[ee.debugId]++) return ee
33
+ wrapped[ee.debugId] = 1 // otherwise, first feature to wrap events
33
34
  var wrapFn = wfn(ee, true)
34
35
 
35
36
  // Guard against instrumenting environments w/o necessary features
36
37
  if ('getPrototypeOf' in Object) {
37
- if (isBrowserScope)
38
- { findEventListenerProtoAndCb(document, wrapNode) }
38
+ if (isBrowserScope) findEventListenerProtoAndCb(document, wrapNode)
39
39
  findEventListenerProtoAndCb(globalScope, wrapNode)
40
40
  findEventListenerProtoAndCb(XHR.prototype, wrapNode)
41
41
  }
@@ -35,9 +35,10 @@ export function wrapFetch (sharedEE) {
35
35
  return ee
36
36
  }
37
37
 
38
- if (wrapped[ee.debugId]++) // Notice if our wrapping never ran yet, the falsey NaN will not early return; but if it has,
39
- { return ee } // then we increment the count to track # of feats using this at runtime.
40
- wrapped[ee.debugId] = 1
38
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
39
+ // then we increment the count to track # of feats using this at runtime.
40
+ if (wrapped[ee.debugId]++) return ee
41
+ wrapped[ee.debugId] = 1 // otherwise, first feature to wrap fetch
41
42
 
42
43
  bodyMethods.forEach(method => {
43
44
  wrapPromiseMethod(Req[proto], method, bodyPrefix)
@@ -21,9 +21,12 @@ const HISTORY_FNS = ['pushState', 'replaceState']
21
21
  */
22
22
  export function wrapHistory (sharedEE) {
23
23
  const ee = scopedEE(sharedEE)
24
- if (!isBrowserScope || wrapped[ee.debugId]++) // Notice if our wrapping never ran yet, the falsey NaN will not early return; but if it has,
25
- { return ee } // then we increment the count to track # of feats using this at runtime. (History API is only avail in browser DOM context.)
26
- wrapped[ee.debugId] = 1
24
+
25
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
26
+ // then we increment the count to track # of feats using this at runtime. History API is only
27
+ // available in browser DOM context.
28
+ if (!isBrowserScope || wrapped[ee.debugId]++) return ee
29
+ wrapped[ee.debugId] = 1 // otherwise, first feature to wrap history
27
30
 
28
31
  var wrapFn = wfn(ee)
29
32
  /*
@@ -24,9 +24,11 @@ const domInsertMethods = ['appendChild', 'insertBefore', 'replaceChild']
24
24
  export function wrapJsonP (sharedEE) {
25
25
  const ee = scopedEE(sharedEE)
26
26
 
27
- if (!isBrowserScope || wrapped[ee.debugId]) // JSONP deals with DOM tags so browser window env is req'd
28
- { return ee }
29
- wrapped[ee.debugId] = true
27
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
28
+ // then we increment the count to track # of feats using this at runtime. JSONP deals with DOM
29
+ // tags so browser window env is required.
30
+ if (!isBrowserScope || wrapped[ee.debugId]) return ee
31
+ wrapped[ee.debugId] = true // otherwise, first feature to wrap JSONP
30
32
 
31
33
  var wrapFn = wfn(ee)
32
34
 
@@ -22,9 +22,12 @@ const wrapped = {}
22
22
  */
23
23
  export function wrapMutation (sharedEE) {
24
24
  const ee = scopedEE(sharedEE)
25
- if (!isBrowserScope || wrapped[ee.debugId]) // relates to the DOM tree (web env only)
26
- { return ee }
27
- wrapped[ee.debugId] = true
25
+
26
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
27
+ // then we increment the count to track # of feats using this at runtime. Mutations API is only
28
+ // available in browser DOM context.
29
+ if (!isBrowserScope || wrapped[ee.debugId]) return ee
30
+ wrapped[ee.debugId] = true // otherwise, first feature to wrap mutations
28
31
 
29
32
  var wrapFn = wfn(ee)
30
33
  var OriginalObserver = originals.MO
@@ -24,9 +24,10 @@ const wrapped = {}
24
24
  export function wrapPromise (sharedEE) {
25
25
  const promiseEE = scopedEE(sharedEE)
26
26
 
27
- if (wrapped[promiseEE.debugId])
28
- { return promiseEE }
29
- wrapped[promiseEE.debugId] = true
27
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
28
+ // then we increment the count to track # of feats using this at runtime.
29
+ if (wrapped[promiseEE.debugId]) return promiseEE
30
+ wrapped[promiseEE.debugId] = true // otherwise, first feature to wrap promise
30
31
 
31
32
  var getContext = getOrSetContext
32
33
  var promiseWrapper = wrapFn(promiseEE)
@@ -69,9 +70,9 @@ export function wrapPromise (sharedEE) {
69
70
  const prevStaticFn = prevPromiseObj[method]
70
71
  WrappedPromise[method] = function (subPromises) { // use our own wrapped version of "Promise.all" and ".race" static fns
71
72
  let finalized = false
72
- subPromises?.forEach(sub => {
73
- // eslint-disable-next-line
74
- this.resolve(sub).then(setNrId(method === 'all'), setNrId(false));
73
+
74
+ Array.from(subPromises || []).forEach(sub => {
75
+ this.resolve(sub).then(setNrId(method === 'all'), setNrId(false))
75
76
  })
76
77
 
77
78
  const origFnCallWithThis = prevStaticFn.apply(this, arguments)
@@ -0,0 +1,140 @@
1
+ import { faker } from '@faker-js/faker'
2
+ import { globalScope } from '../util/global-scope'
3
+ import { originals } from '../config/config'
4
+
5
+ jest.mock('./wrap-function', () => ({
6
+ __esModule: true,
7
+ createWrapperWithEmitter: jest.fn(() => (fn) => (...args) => {
8
+ return fn.apply(null, args)
9
+ })
10
+ }))
11
+ jest.mock('../event-emitter/contextual-ee', () => ({
12
+ __esModule: true,
13
+ getOrSetContext: jest.fn(() => ({})),
14
+ ee: {
15
+ get: jest.fn((name) => ({
16
+ debugId: name,
17
+ on: jest.fn(),
18
+ context: jest.fn(() => ({})),
19
+ emit: jest.fn()
20
+ }))
21
+ }
22
+ }))
23
+ jest.mock('../config/config', () => ({
24
+ __esModule: true,
25
+ originals: {}
26
+ }))
27
+ jest.mock('../util/global-scope', () => ({
28
+ __esModule: true,
29
+ globalScope: {
30
+ NREUM: {}
31
+ }
32
+ }))
33
+
34
+ let promiseConstructorCalls
35
+
36
+ beforeEach(async () => {
37
+ promiseConstructorCalls = []
38
+
39
+ // Proxy the global Promise to prevent the wrapping from
40
+ // messing with Jest internal promises
41
+ originals.PR = new Proxy(class extends Promise {}, {
42
+ construct (target, args) {
43
+ promiseConstructorCalls.push(args)
44
+
45
+ return Reflect.construct(target, args)
46
+ }
47
+ })
48
+
49
+ ;(await import('./wrap-promise')).wrapPromise()
50
+ })
51
+
52
+ afterEach(() => {
53
+ jest.resetModules()
54
+ })
55
+
56
+ test('should wrap promise constructor', async () => {
57
+ const promiseInstance = new globalScope.Promise(jest.fn())
58
+
59
+ expect(promiseInstance).toBeInstanceOf(Promise)
60
+ expect(promiseConstructorCalls.length).toEqual(1)
61
+ expect(globalScope.Promise.toString()).toMatch(/\[native code\]/)
62
+ expect(globalScope.Promise.name).toEqual('Promise')
63
+ })
64
+
65
+ describe('all', () => {
66
+ test('should work with acceptable iterables', async () => {
67
+ const resolveValue = faker.datatype.uuid()
68
+ const customIterable = new CustomIterable([
69
+ new globalScope.Promise(resolve => resolve(resolveValue))
70
+ ])
71
+ const arrayIterable = [
72
+ new globalScope.Promise(resolve => resolve(resolveValue))
73
+ ]
74
+ const setIterable = new Set()
75
+ setIterable.add(new globalScope.Promise(resolve => resolve(resolveValue)))
76
+
77
+ await expect(globalScope.Promise.all(customIterable)).resolves.toEqual([resolveValue])
78
+ await expect(globalScope.Promise.all(arrayIterable)).resolves.toEqual([resolveValue])
79
+ await expect(globalScope.Promise.all(setIterable)).resolves.toEqual([resolveValue])
80
+ })
81
+
82
+ test.each([null, undefined])('should not try to iterate a non-iterable %s', async (input) => {
83
+ jest.spyOn(globalScope.Promise, 'resolve')
84
+
85
+ await expect(globalScope.Promise.all(input)).rejects.toThrow()
86
+ expect(globalScope.Promise.resolve).not.toHaveBeenCalled()
87
+ })
88
+ })
89
+
90
+ describe('race', () => {
91
+ test('should work with acceptable iterables', async () => {
92
+ jest.spyOn(globalScope.Promise, 'resolve')
93
+
94
+ const resolveValue = faker.datatype.uuid()
95
+ const customIterable = new CustomIterable([
96
+ new globalScope.Promise(resolve => resolve(resolveValue))
97
+ ])
98
+ const arrayIterable = [
99
+ new globalScope.Promise(resolve => resolve(resolveValue))
100
+ ]
101
+ const setIterable = new Set()
102
+ setIterable.add(new globalScope.Promise(resolve => resolve(resolveValue)))
103
+
104
+ await expect(globalScope.Promise.race(customIterable)).resolves.toEqual(resolveValue)
105
+ await expect(globalScope.Promise.race(arrayIterable)).resolves.toEqual(resolveValue)
106
+ await expect(globalScope.Promise.race(setIterable)).resolves.toEqual(resolveValue)
107
+ expect(globalScope.Promise.resolve).toHaveBeenCalled()
108
+ })
109
+
110
+ test.each([null, undefined])('should not try to iterate a non-iterable %s', async (input) => {
111
+ jest.spyOn(globalScope.Promise, 'resolve')
112
+
113
+ await expect(globalScope.Promise.race(input)).rejects.toThrow()
114
+ expect(globalScope.Promise.resolve).not.toHaveBeenCalled()
115
+ })
116
+ })
117
+
118
+ class CustomIterable {
119
+ #iterables = []
120
+
121
+ constructor (iterables) {
122
+ this.#iterables = iterables
123
+ }
124
+
125
+ [Symbol.iterator] () {
126
+ return {
127
+ index: 0,
128
+ iterables: this.#iterables,
129
+ next () {
130
+ return {
131
+ done: this.index >= this.iterables.length,
132
+ value: this.iterables[this.index++] || undefined
133
+ }
134
+ },
135
+ [Symbol.iterator] () {
136
+ return this
137
+ }
138
+ }
139
+ }
140
+ }
@@ -22,9 +22,11 @@ const RAF_NAME = 'requestAnimationFrame'
22
22
  */
23
23
  export function wrapRaf (sharedEE) {
24
24
  const ee = scopedEE(sharedEE)
25
- if (!isBrowserScope || wrapped[ee.debugId]++) // Notice if our wrapping never ran yet, the falsey NaN will not early return; but if it has,
26
- { return ee } // then we increment the count to track # of feats using this at runtime. (RAF is only avail in browser DOM context.)
27
- wrapped[ee.debugId] = 1
25
+
26
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
27
+ // then we increment the count to track # of feats using this at runtime.
28
+ if (!isBrowserScope || wrapped[ee.debugId]++) return ee
29
+ wrapped[ee.debugId] = 1 // otherwise, first feature to wrap RAF
28
30
 
29
31
  var wrapFn = wfn(ee)
30
32
 
@@ -29,9 +29,11 @@ const TIMER_FNS = [SET_TIMEOUT, 'setImmediate', SET_INTERVAL, CLEAR_TIMEOUT, 'cl
29
29
  //eslint-disable-next-line
30
30
  export function wrapTimer(sharedEE) {
31
31
  const ee = scopedEE(sharedEE)
32
- if (wrapped[ee.debugId]++) // Notice if our wrapping never ran yet, the falsey NaN will not early return; but if it has,
33
- { return ee } // then we increment the count to track # of feats using this at runtime.
34
- wrapped[ee.debugId] = 1
32
+
33
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
34
+ // then we increment the count to track # of feats using this at runtime.
35
+ if (wrapped[ee.debugId]++) return ee
36
+ wrapped[ee.debugId] = 1 // otherwise, first feature to wrap timer
35
37
 
36
38
  var wrapFn = wfn(ee)
37
39
 
@@ -29,9 +29,10 @@ export function wrapXhr (sharedEE) {
29
29
  var baseEE = sharedEE || contextualEE
30
30
  const ee = scopedEE(baseEE)
31
31
 
32
- if (wrapped[ee.debugId]++) // Notice if our wrapping never ran yet, the falsey NaN will not early return; but if it has,
33
- { return ee } // then we increment the count to track # of feats using this at runtime.
34
- wrapped[ee.debugId] = 1 // <- otherwise, first feature to wrap XHR
32
+ // Notice if our wrapping never ran yet, the falsy NaN will not early return; but if it has,
33
+ // then we increment the count to track # of feats using this at runtime.
34
+ if (wrapped[ee.debugId]++) return ee
35
+ wrapped[ee.debugId] = 1 // otherwise, first feature to wrap XHR
35
36
 
36
37
  wrapEvents(baseEE) // wrap-events patches XMLHttpRequest.prototype.addEventListener for us
37
38
  var wrapFn = wfn(ee)
@@ -140,7 +140,7 @@ function subscribeToEvents (agentIdentifier, ee, handler, dt) {
140
140
  if (evt.type === 'abort' && !(context.loadCaptureCalled)) {
141
141
  context.params.aborted = true
142
142
  }
143
- if (evt.type !== 'load' || (context.called === context.totalCbs) && (context.onloadCalled || typeof (xhr.onload) !== 'function') && typeof context.end === 'function') context.end(xhr)
143
+ if (evt.type !== 'load' || ((context.called === context.totalCbs) && (context.onloadCalled || typeof (xhr.onload) !== 'function') && typeof context.end === 'function')) context.end(xhr)
144
144
  } catch (e) {
145
145
  try {
146
146
  ee.emit('internal-error', [e])
@@ -24,8 +24,10 @@ export class Instrument extends InstrumentBase {
24
24
  // skipNext counter to keep track of uncaught
25
25
  // errors that will be the same as caught errors.
26
26
  this.skipNext = 0
27
- try { this.removeOnAbort = new AbortController() } // this try-catch can be removed when IE11 is completely unsupported & gone
28
- catch (e) {}
27
+ try {
28
+ // this try-catch can be removed when IE11 is completely unsupported & gone
29
+ this.removeOnAbort = new AbortController()
30
+ } catch (e) {}
29
31
 
30
32
  const thisInstrument = this
31
33
  thisInstrument.ee.on('fn-start', function (args, obj, methodName) {
@@ -5,9 +5,9 @@ import { AggregateBase } from '../../utils/aggregate-base'
5
5
  import { FEATURE_NAME, SUPPORTABILITY_METRIC, CUSTOM_METRIC, SUPPORTABILITY_METRIC_CHANNEL, CUSTOM_METRIC_CHANNEL } from '../constants'
6
6
  import { drain } from '../../../common/drain/drain'
7
7
  import { getFrameworks } from '../../../common/metrics/framework-detection'
8
- import { protocol } from '../../../common/url/protocol'
8
+ import { isFileProtocol } from '../../../common/url/protocol'
9
9
  import { getRules, validateRules } from '../../../common/util/obfuscate'
10
- import { VERSION } from '../../../common/constants/environment-variables'
10
+ import { VERSION } from '../../../common/constants/env'
11
11
  import { onDOMContentLoaded } from '../../../common/window/load'
12
12
  import { windowAddEventListener } from '../../../common/event-listener/event-listener-opts'
13
13
  import { isBrowserScope } from '../../../common/util/global-scope'
@@ -70,9 +70,8 @@ export class Aggregate extends AggregateBase {
70
70
  }
71
71
 
72
72
  // file protocol detection
73
- if (protocol.isFileProtocol()) {
73
+ if (isFileProtocol()) {
74
74
  this.storeSupportabilityMetrics('Generic/FileProtocol/Detected')
75
- protocol.supportabilityMetricSent = true
76
75
  }
77
76
 
78
77
  // obfuscation rules detection
@@ -3,42 +3,12 @@ import { insertSupportMetrics } from './workers-helper'
3
3
  import { FEATURE_NAME, SUPPORTABILITY_METRIC_CHANNEL } from '../constants'
4
4
  import { handle } from '../../../common/event-emitter/handle'
5
5
  import { FEATURE_NAMES } from '../../../loaders/features/features'
6
- import { wrapConsole } from '../../../common/wrap'
7
- import { stringify } from '../../../common/util/stringify'
8
6
 
9
7
  export class Instrument extends InstrumentBase {
10
8
  static featureName = FEATURE_NAME
11
9
  constructor (agentIdentifier, aggregator, auto = true) {
12
10
  super(agentIdentifier, aggregator, FEATURE_NAME, auto)
13
11
  insertSupportMetrics(tag => handle(SUPPORTABILITY_METRIC_CHANNEL, [tag], undefined, FEATURE_NAMES.metrics, this.ee))
14
-
15
- this.addConsoleSupportabilityMetrics()
16
-
17
12
  this.importAggregator()
18
13
  }
19
-
20
- addConsoleSupportabilityMetrics () {
21
- // For now we are just capturing supportability metrics on `console` usage to assess log forwarding feature.
22
- const consoleEE = wrapConsole(this.ee)
23
-
24
- for (const method of ['Debug', 'Error', 'Info', 'Log', 'Trace', 'Warn']) {
25
- consoleEE.on(`${method.toLowerCase()}-console-start`, function (args, target) {
26
- // Parsing the args individually into a new array ensures that functions and Error objects are represented with
27
- // useful string values. By default, functions stringify to null and Error objects stringify to empty objects.
28
- // Note that stack traces printed by the console.trace method are not captured.
29
- let parsedArgs = []
30
- for (const arg of args) {
31
- if (typeof arg === 'function' ||
32
- (arg && arg.message && arg.stack) // Duck typing for Error objects
33
- ) {
34
- parsedArgs.push(arg.toString())
35
- } else {
36
- parsedArgs.push(arg)
37
- }
38
- }
39
- const parsedArgsJSON = stringify(parsedArgs)
40
- handle(SUPPORTABILITY_METRIC_CHANNEL, [`Console/${method}/Seen`, parsedArgsJSON.length], undefined, FEATURE_NAMES.metrics, consoleEE)
41
- })
42
- }
43
- }
44
14
  }
@@ -37,23 +37,26 @@ export function insertSupportMetrics (report) {
37
37
  return // similarly, if dedicated is n/a, none of them are supported so quit
38
38
  } else {
39
39
  origWorker = Worker
40
- try { globalScope.Worker = extendWorkerConstructor(origWorker, 'Dedicated') }
41
- catch (e) { handleInsertionError(e, 'Dedicated') }
40
+ try {
41
+ globalScope.Worker = extendWorkerConstructor(origWorker, 'Dedicated')
42
+ } catch (e) { handleInsertionError(e, 'Dedicated') }
42
43
  }
43
44
 
44
45
  if (!workersApiIsSupported.shared) {
45
46
  reportUnavailable('Shared')
46
47
  } else {
47
48
  origSharedWorker = SharedWorker
48
- try { globalScope.SharedWorker = extendWorkerConstructor(origSharedWorker, 'Shared') }
49
- catch (e) { handleInsertionError(e, 'Shared') }
49
+ try {
50
+ globalScope.SharedWorker = extendWorkerConstructor(origSharedWorker, 'Shared')
51
+ } catch (e) { handleInsertionError(e, 'Shared') }
50
52
  }
51
53
  if (!workersApiIsSupported.service) {
52
54
  reportUnavailable('Service')
53
55
  } else {
54
56
  origServiceWorkerCreate = navigator.serviceWorker.register
55
- try { globalScope.navigator.serviceWorker.register = extendServiceCreation(origServiceWorkerCreate) }
56
- catch (e) { handleInsertionError(e, 'Service') }
57
+ try {
58
+ globalScope.navigator.serviceWorker.register = extendServiceCreation(origServiceWorkerCreate)
59
+ } catch (e) { handleInsertionError(e, 'Service') }
57
60
  }
58
61
  return
59
62