@newrelic/browser-agent 1.237.1 → 1.238.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.
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/deny-list/deny-list.js +1 -1
- package/dist/cjs/common/event-emitter/contextual-ee.js +18 -26
- package/dist/cjs/common/event-emitter/event-context.js +12 -0
- package/dist/cjs/common/harvest/harvest.js +2 -1
- package/dist/cjs/common/ids/bundle-id.js +19 -0
- package/dist/cjs/common/wrap/wrap-events.js +3 -2
- package/dist/cjs/common/wrap/wrap-fetch.js +1 -3
- package/dist/cjs/common/wrap/wrap-function.js +15 -46
- package/dist/cjs/common/wrap/wrap-mutation.js +1 -2
- package/dist/cjs/common/wrap/wrap-promise.js +2 -3
- package/dist/cjs/common/wrap/wrap-xhr.js +23 -27
- package/dist/cjs/features/ajax/instrument/distributed-tracing.js +0 -4
- package/dist/cjs/features/ajax/instrument/index.js +19 -9
- package/dist/cjs/features/session_replay/aggregate/index.js +2 -0
- package/dist/cjs/features/session_trace/aggregate/index.js +14 -8
- package/dist/cjs/loaders/agent-base.js +12 -0
- package/dist/cjs/loaders/api/api.js +14 -1
- package/dist/cjs/loaders/api/interaction-types.js +11 -4
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/deny-list/deny-list.js +1 -1
- package/dist/esm/common/event-emitter/contextual-ee.js +16 -23
- package/dist/esm/common/event-emitter/event-context.js +5 -0
- package/dist/esm/common/harvest/harvest.js +2 -1
- package/dist/esm/common/ids/bundle-id.js +13 -0
- package/dist/esm/common/wrap/wrap-events.js +4 -3
- package/dist/esm/common/wrap/wrap-fetch.js +2 -4
- package/dist/esm/common/wrap/wrap-function.js +15 -44
- package/dist/esm/common/wrap/wrap-mutation.js +2 -3
- package/dist/esm/common/wrap/wrap-promise.js +3 -4
- package/dist/esm/common/wrap/wrap-xhr.js +23 -27
- package/dist/esm/features/ajax/instrument/distributed-tracing.js +0 -4
- package/dist/esm/features/ajax/instrument/index.js +20 -10
- package/dist/esm/features/session_replay/aggregate/index.js +2 -0
- package/dist/esm/features/session_trace/aggregate/index.js +14 -8
- package/dist/esm/loaders/agent-base.js +12 -0
- package/dist/esm/loaders/api/api.js +14 -1
- package/dist/esm/loaders/api/interaction-types.js +11 -4
- package/dist/types/common/event-emitter/contextual-ee.d.ts +22 -2
- package/dist/types/common/event-emitter/contextual-ee.d.ts.map +1 -1
- package/dist/types/common/event-emitter/event-context.d.ts +5 -0
- package/dist/types/common/event-emitter/event-context.d.ts.map +1 -0
- package/dist/types/common/event-emitter/register-handler.d.ts +1 -1
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/ids/bundle-id.d.ts +5 -0
- package/dist/types/common/ids/bundle-id.d.ts.map +1 -0
- package/dist/types/common/session/session-entity.d.ts +6 -6
- package/dist/types/common/window/nreum.d.ts +2 -2
- package/dist/types/common/wrap/wrap-events.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-fetch.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-function.d.ts +1 -19
- package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-mutation.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-xhr.d.ts.map +1 -1
- package/dist/types/features/ajax/instrument/distributed-tracing.d.ts +1 -1
- package/dist/types/features/ajax/instrument/distributed-tracing.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/endpoint-map.d.ts +5 -5
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/aggregate/index.d.ts +5 -0
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/loaders/agent-base.d.ts +9 -0
- package/dist/types/loaders/agent-base.d.ts.map +1 -1
- package/dist/types/loaders/api/api.d.ts +6 -0
- package/dist/types/loaders/api/api.d.ts.map +1 -1
- package/dist/types/loaders/api/interaction-types.d.ts +18 -7
- package/dist/types/loaders/api/interaction-types.d.ts.map +1 -1
- package/dist/types/loaders/configure/configure.d.ts +1 -0
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/dist/types/loaders/features/features.d.ts +9 -9
- package/dist/types/loaders/micro-agent.d.ts +1 -1
- package/dist/types/loaders/micro-agent.d.ts.map +1 -1
- package/package.json +22 -27
- package/src/common/deny-list/deny-list.js +1 -1
- package/src/common/deny-list/deny-list.test.js +103 -30
- package/src/common/event-emitter/{contextual-ee.test.js → contextual-ee.component-test.js} +15 -32
- package/src/common/event-emitter/contextual-ee.js +20 -31
- package/src/common/event-emitter/event-context.js +5 -0
- package/src/common/harvest/harvest.js +2 -1
- package/src/common/harvest/harvest.test.js +1 -1
- package/src/common/ids/__mocks__/bundle-id.js +2 -0
- package/src/common/ids/__mocks__/unique-id.js +17 -0
- package/src/common/ids/bundle-id.js +13 -0
- package/src/common/url/__mocks__/parse-url.js +15 -0
- package/src/common/util/__mocks__/get-or-set.js +5 -0
- package/src/common/window/__mocks__/nreum.js +10 -0
- package/src/common/wrap/wrap-events.js +4 -3
- package/src/common/wrap/wrap-fetch.js +2 -4
- package/src/common/wrap/wrap-function.js +16 -44
- package/src/common/wrap/wrap-mutation.js +2 -3
- package/src/common/wrap/{wrap-promise.test.js → wrap-promise.component-test.js} +2 -32
- package/src/common/wrap/wrap-promise.js +3 -4
- package/src/common/wrap/wrap-xhr.js +24 -28
- package/src/features/ajax/instrument/distributed-tracing.js +0 -4
- package/src/features/ajax/instrument/distributed-tracing.test.js +375 -0
- package/src/features/ajax/instrument/index.js +22 -10
- package/src/features/session_replay/aggregate/index.js +2 -0
- package/src/features/session_trace/aggregate/index.js +16 -7
- package/src/loaders/agent-base.js +12 -0
- package/src/loaders/api/api.component-test.js +45 -0
- package/src/loaders/api/api.js +14 -1
- package/src/loaders/api/interaction-types.js +11 -4
- /package/src/common/url/{encode.component-test.js → encode.test.js} +0 -0
- /package/src/common/url/{protocol.component-test.js → protocol.test.js} +0 -0
|
@@ -1,31 +1,104 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
1
|
+
jest.enableAutomock()
|
|
2
|
+
jest.unmock('./deny-list')
|
|
3
|
+
|
|
4
|
+
let denyListModule
|
|
5
|
+
|
|
6
|
+
beforeEach(async () => {
|
|
7
|
+
denyListModule = await import('./deny-list')
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
jest.resetModules()
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
test('domain-only blocks all subdomains and all paths', () => {
|
|
15
|
+
denyListModule.setDenyList(['foo.com'])
|
|
16
|
+
|
|
17
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/' })).toBeFalsy()
|
|
18
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/a' })).toBeFalsy()
|
|
19
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/a/b' })).toBeFalsy()
|
|
20
|
+
|
|
21
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'www.foo.com', pathname: '/' })).toBeFalsy()
|
|
22
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'a.b.foo.com', pathname: '/' })).toBeFalsy()
|
|
23
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'a.b.foo.com', pathname: '/c/d' })).toBeFalsy()
|
|
24
|
+
|
|
25
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'oo.com', pathname: '/' })).toBeTruthy()
|
|
26
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bar.com', pathname: '/' })).toBeTruthy()
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
test('subdomain blocks further subdomains, but not parent domain', () => {
|
|
30
|
+
denyListModule.setDenyList(['bar.foo.com'])
|
|
31
|
+
|
|
32
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bar.foo.com', pathname: '/' })).toBeFalsy()
|
|
33
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bar.foo.com', pathname: '/a' })).toBeFalsy()
|
|
34
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bar.foo.com', pathname: '/a/b' })).toBeFalsy()
|
|
35
|
+
|
|
36
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'a.bar.foo.com', pathname: '/' })).toBeFalsy()
|
|
37
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'a.bar.foo.com', pathname: '/a' })).toBeFalsy()
|
|
38
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'a.bar.foo.com', pathname: '/a/b' })).toBeFalsy()
|
|
39
|
+
|
|
40
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/' })).toBeTruthy()
|
|
41
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/a' })).toBeTruthy()
|
|
42
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/a/b' })).toBeTruthy()
|
|
43
|
+
|
|
44
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'oo.com', pathname: '/' })).toBeTruthy()
|
|
45
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bar.com', pathname: '/' })).toBeTruthy()
|
|
46
|
+
})
|
|
47
|
+
|
|
48
|
+
test('* blocks all domains', () => {
|
|
49
|
+
denyListModule.setDenyList(['*'])
|
|
50
|
+
|
|
51
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/' })).toBeFalsy()
|
|
52
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'www.foo.com', pathname: '/' })).toBeFalsy()
|
|
53
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bar.com', pathname: '/' })).toBeFalsy()
|
|
54
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'www.bar.com', pathname: '/' })).toBeFalsy()
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
test('respects path', () => {
|
|
58
|
+
denyListModule.setDenyList(['bam.nr-data.net/somepath'])
|
|
59
|
+
|
|
60
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.net', pathname: '/somepath' })).toBeFalsy()
|
|
61
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.net', port: '7890', protocol: 'https', host: 'bam.nr-data.net:7890', pathname: '/somepath' })).toBeFalsy()
|
|
62
|
+
|
|
63
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.com', pathname: '' })).toBeTruthy()
|
|
64
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.com', pathname: '/someotherpath' })).toBeTruthy()
|
|
65
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.com', pathname: '/some/otherpath' })).toBeTruthy()
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
test('ignores port', () => {
|
|
69
|
+
denyListModule.setDenyList(['bam.nr-data.net:1234'])
|
|
70
|
+
|
|
71
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.net', pathname: '', port: '4321' })).toBeFalsy()
|
|
72
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.net', port: '7890', protocol: 'http', host: 'bam.nr-data.net:7890', pathname: '/somepath' })).toBeFalsy()
|
|
73
|
+
|
|
74
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.com', pathname: '' })).toBeTruthy()
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('ignores protocol', () => {
|
|
78
|
+
denyListModule.setDenyList(['http://bam.nr-data.net'])
|
|
79
|
+
|
|
80
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.net', pathname: '', protocol: 'https' })).toBeFalsy()
|
|
81
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.net', port: '7890', protocol: 'https', host: 'bam.nr-data.net:7890', pathname: '/somepath' })).toBeFalsy()
|
|
82
|
+
|
|
83
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bam.nr-data.com', pathname: '', protocol: 'http' })).toBeTruthy()
|
|
84
|
+
})
|
|
85
|
+
|
|
86
|
+
test.each([
|
|
87
|
+
null,
|
|
88
|
+
undefined,
|
|
89
|
+
'!@$%^*',
|
|
90
|
+
'https://example.com/http://foo.bar/'
|
|
91
|
+
])('ignores invalid deny list value %s', (denyListValue) => {
|
|
92
|
+
denyListModule.setDenyList([denyListValue])
|
|
93
|
+
|
|
94
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/' })).toBeTruthy()
|
|
95
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/a' })).toBeTruthy()
|
|
96
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'foo.com', pathname: '/a/b' })).toBeTruthy()
|
|
97
|
+
|
|
98
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'www.foo.com', pathname: '/' })).toBeTruthy()
|
|
99
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'a.b.foo.com', pathname: '/' })).toBeTruthy()
|
|
100
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'a.b.foo.com', pathname: '/c/d' })).toBeTruthy()
|
|
101
|
+
|
|
102
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'oo.com', pathname: '/' })).toBeTruthy()
|
|
103
|
+
expect(denyListModule.shouldCollectEvent({ hostname: 'bar.com', pathname: '/' })).toBeTruthy()
|
|
31
104
|
})
|
|
@@ -24,19 +24,18 @@ afterEach(() => {
|
|
|
24
24
|
})
|
|
25
25
|
|
|
26
26
|
describe('global event-emitter', () => {
|
|
27
|
-
test('it
|
|
28
|
-
const mockEE = {}
|
|
29
|
-
mockNREUM.ee = mockEE
|
|
30
|
-
|
|
27
|
+
test('it sets the global event-emitter on window.NREUM when it does not already exist', async () => {
|
|
31
28
|
const { ee } = await import('./contextual-ee')
|
|
32
29
|
|
|
33
|
-
expect(ee).toEqual(
|
|
30
|
+
expect(ee).toEqual(mockNREUM.ee)
|
|
34
31
|
})
|
|
35
32
|
|
|
36
|
-
test('it
|
|
33
|
+
test('it does not set the global event-emitter on window.NREUM when it already exists', async () => {
|
|
34
|
+
mockNREUM.ee = {}
|
|
35
|
+
|
|
37
36
|
const { ee } = await import('./contextual-ee')
|
|
38
37
|
|
|
39
|
-
expect(ee).toEqual(mockNREUM.ee)
|
|
38
|
+
expect(ee).not.toEqual(mockNREUM.ee)
|
|
40
39
|
})
|
|
41
40
|
})
|
|
42
41
|
|
|
@@ -79,7 +78,9 @@ describe('event-emitter context', () => {
|
|
|
79
78
|
|
|
80
79
|
const result = ee.context()
|
|
81
80
|
|
|
82
|
-
expect(result).toEqual({
|
|
81
|
+
expect(result).toEqual(expect.objectContaining({
|
|
82
|
+
contextId: expect.stringContaining('nr@context:')
|
|
83
|
+
}))
|
|
83
84
|
})
|
|
84
85
|
|
|
85
86
|
test('it returns the same context', async () => {
|
|
@@ -87,7 +88,7 @@ describe('event-emitter context', () => {
|
|
|
87
88
|
|
|
88
89
|
const result = ee.context()
|
|
89
90
|
|
|
90
|
-
expect(result).
|
|
91
|
+
expect(result).toBe(ee.context(result))
|
|
91
92
|
})
|
|
92
93
|
|
|
93
94
|
test('it adds the context to the provided object', async () => {
|
|
@@ -95,8 +96,9 @@ describe('event-emitter context', () => {
|
|
|
95
96
|
|
|
96
97
|
const obj = {}
|
|
97
98
|
const result = ee.context(obj)
|
|
99
|
+
const ctxKey = Object.getOwnPropertyNames(obj).find(k => k.startsWith('nr@context'))
|
|
98
100
|
|
|
99
|
-
expect(result).
|
|
101
|
+
expect(result).toBe(obj[ctxKey])
|
|
100
102
|
})
|
|
101
103
|
})
|
|
102
104
|
|
|
@@ -281,30 +283,11 @@ describe('event-emitter emit', () => {
|
|
|
281
283
|
scopeEE,
|
|
282
284
|
eventType,
|
|
283
285
|
eventArgs,
|
|
284
|
-
{
|
|
286
|
+
expect.objectContaining({
|
|
287
|
+
contextId: expect.stringContaining('nr@context:')
|
|
288
|
+
})
|
|
285
289
|
])
|
|
286
290
|
]))
|
|
287
291
|
expect(ee.backlog.feature).toEqual(scopeEE.backlog.feature)
|
|
288
292
|
})
|
|
289
293
|
})
|
|
290
|
-
|
|
291
|
-
describe('getOrSetContext', () => {
|
|
292
|
-
test('it returns a new context', async () => {
|
|
293
|
-
const { getOrSetContext } = await import('./contextual-ee')
|
|
294
|
-
|
|
295
|
-
const obj = {}
|
|
296
|
-
const result = getOrSetContext(obj)
|
|
297
|
-
|
|
298
|
-
expect(result).toEqual({})
|
|
299
|
-
expect(result).toEqual(obj['nr@context'])
|
|
300
|
-
})
|
|
301
|
-
|
|
302
|
-
test('it returns the same context', async () => {
|
|
303
|
-
const { getOrSetContext } = await import('./contextual-ee')
|
|
304
|
-
|
|
305
|
-
const obj = {}
|
|
306
|
-
const result = getOrSetContext(obj)
|
|
307
|
-
|
|
308
|
-
expect(getOrSetContext(obj)).toEqual(result)
|
|
309
|
-
})
|
|
310
|
-
})
|
|
@@ -5,25 +5,22 @@
|
|
|
5
5
|
|
|
6
6
|
import { gosNREUM } from '../window/nreum'
|
|
7
7
|
import { getOrSet } from '../util/get-or-set'
|
|
8
|
-
import { mapOwn } from '../util/map-own'
|
|
9
8
|
import { getRuntime } from '../config/config'
|
|
9
|
+
import { EventContext } from './event-context'
|
|
10
|
+
import { bundleId } from '../ids/bundle-id'
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
12
|
+
// create a unique id to store event context data for the current agent bundle
|
|
13
|
+
const contextId = `nr@context:${bundleId}`
|
|
13
14
|
// create global emitter instance that can be shared among bundles
|
|
14
|
-
|
|
15
|
-
var globalInstance
|
|
15
|
+
const globalInstance = ee(undefined, 'globalEE')
|
|
16
16
|
|
|
17
|
-
if
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
globalInstance = ee(undefined, 'globalEE')
|
|
17
|
+
// Only override the exposed event emitter if one has not already been exposed
|
|
18
|
+
const nr = gosNREUM()
|
|
19
|
+
if (!nr.ee) {
|
|
21
20
|
nr.ee = globalInstance
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
export { globalInstance as ee }
|
|
25
|
-
|
|
26
|
-
function EventContext () { }
|
|
23
|
+
export { globalInstance as ee, contextId }
|
|
27
24
|
|
|
28
25
|
function ee (old, debugId) {
|
|
29
26
|
var handlers = {}
|
|
@@ -65,9 +62,9 @@ function ee (old, debugId) {
|
|
|
65
62
|
if (contextOrStore && contextOrStore instanceof EventContext) {
|
|
66
63
|
return contextOrStore
|
|
67
64
|
} else if (contextOrStore) {
|
|
68
|
-
return getOrSet(contextOrStore,
|
|
65
|
+
return getOrSet(contextOrStore, contextId, () => new EventContext(contextId))
|
|
69
66
|
} else {
|
|
70
|
-
return
|
|
67
|
+
return new EventContext(contextId)
|
|
71
68
|
}
|
|
72
69
|
}
|
|
73
70
|
|
|
@@ -119,17 +116,18 @@ function ee (old, debugId) {
|
|
|
119
116
|
}
|
|
120
117
|
|
|
121
118
|
function bufferEventsByGroup (types, group) {
|
|
122
|
-
|
|
119
|
+
const eventBuffer = getBuffer()
|
|
120
|
+
group = group || 'feature'
|
|
123
121
|
|
|
124
122
|
// do not buffer events if agent has been aborted
|
|
125
123
|
if (emitter.aborted) return
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
124
|
+
Object.entries(types || {})
|
|
125
|
+
.forEach(([_, type]) => {
|
|
126
|
+
bufferGroupMap[type] = group
|
|
127
|
+
if (!(group in eventBuffer)) {
|
|
128
|
+
eventBuffer[group] = []
|
|
129
|
+
}
|
|
130
|
+
})
|
|
133
131
|
}
|
|
134
132
|
|
|
135
133
|
function isBuffering (type) {
|
|
@@ -144,15 +142,6 @@ function ee (old, debugId) {
|
|
|
144
142
|
}
|
|
145
143
|
}
|
|
146
144
|
|
|
147
|
-
// get context object from store object, or create if does not exist
|
|
148
|
-
export function getOrSetContext (obj) {
|
|
149
|
-
return getOrSet(obj, ctxId, getNewContext)
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
function getNewContext () {
|
|
153
|
-
return new EventContext()
|
|
154
|
-
}
|
|
155
|
-
|
|
156
145
|
function abort () {
|
|
157
146
|
globalInstance.aborted = true
|
|
158
147
|
globalInstance.backlog = {}
|
|
@@ -47,7 +47,8 @@ export class Harvest extends SharedContext {
|
|
|
47
47
|
sendX (spec = {}) {
|
|
48
48
|
const submitMethod = submitData.getSubmitMethod({ isFinalHarvest: spec.opts?.unload })
|
|
49
49
|
const options = {
|
|
50
|
-
retry: !spec.opts?.unload && submitMethod === submitData.xhr
|
|
50
|
+
retry: !spec.opts?.unload && submitMethod === submitData.xhr,
|
|
51
|
+
isFinalHarvest: spec.opts?.unload === true
|
|
51
52
|
}
|
|
52
53
|
const payload = this.createPayload(spec.endpoint, options)
|
|
53
54
|
const caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this)
|
|
@@ -53,7 +53,7 @@ describe('sendX', () => {
|
|
|
53
53
|
|
|
54
54
|
harvestInstance.sendX(spec)
|
|
55
55
|
|
|
56
|
-
expect(harvestInstance.createPayload).toHaveBeenCalledWith(spec.endpoint, { retry: true })
|
|
56
|
+
expect(harvestInstance.createPayload).toHaveBeenCalledWith(spec.endpoint, { retry: true, isFinalHarvest: false })
|
|
57
57
|
})
|
|
58
58
|
|
|
59
59
|
test('should not use obfuscateAndSend', async () => {
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { faker } from '@faker-js/faker'
|
|
2
|
+
|
|
3
|
+
export function generateUuid () {
|
|
4
|
+
return faker.datatype.uuid()
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export function generateRandomHexString (length) {
|
|
8
|
+
return faker.datatype.hexadecimal({ length, prefix: '' })
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function generateSpanId () {
|
|
12
|
+
return generateRandomHexString(16)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function generateTraceId () {
|
|
16
|
+
return generateRandomHexString(32)
|
|
17
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Contains a unique identifier for the running agent bundle
|
|
3
|
+
* when loaded.
|
|
4
|
+
* @copyright 2023 New Relic Corporation. All rights reserved.
|
|
5
|
+
* @license Apache-2.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { generateUuid } from './unique-id'
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Provides a unique id for the current agent bundle
|
|
12
|
+
*/
|
|
13
|
+
export const bundleId = generateUuid()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function parseUrl (url) {
|
|
2
|
+
try {
|
|
3
|
+
const result = new URL(url)
|
|
4
|
+
|
|
5
|
+
return {
|
|
6
|
+
hostname: result.hostname,
|
|
7
|
+
port: result.port || result.protocol.startsWith('https') ? '443' : '80',
|
|
8
|
+
pathname: result.pathname,
|
|
9
|
+
protocol: result.protocol.replace(':', ''),
|
|
10
|
+
sameOrigin: false
|
|
11
|
+
}
|
|
12
|
+
} catch (err) {
|
|
13
|
+
return {}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const defaults = {}
|
|
2
|
+
export const gosNREUM = jest.fn(() => ({}))
|
|
3
|
+
export const gosNREUMInfo = jest.fn(() => ({}))
|
|
4
|
+
export const gosNREUMLoaderConfig = jest.fn(() => ({}))
|
|
5
|
+
export const gosNREUMInit = jest.fn(() => ({}))
|
|
6
|
+
export const gosNREUMOriginals = jest.fn(() => ({}))
|
|
7
|
+
export const gosNREUMInitializedAgents = jest.fn(() => ({}))
|
|
8
|
+
export const addToNREUM = jest.fn(() => ({}))
|
|
9
|
+
export const NREUMinitialized = jest.fn(() => ({}))
|
|
10
|
+
export const gosCDN = jest.fn(() => ({}))
|
|
@@ -7,15 +7,16 @@
|
|
|
7
7
|
* This module is used directly by: session_trace.
|
|
8
8
|
* It is also called by -> wrapXhr <-, so see "wrap-xhr.js" for features that use this indirectly.
|
|
9
9
|
*/
|
|
10
|
-
import { ee as baseEE } from '../event-emitter/contextual-ee'
|
|
10
|
+
import { ee as baseEE, contextId } from '../event-emitter/contextual-ee'
|
|
11
11
|
import { createWrapperWithEmitter as wfn } from './wrap-function'
|
|
12
12
|
import { getOrSet } from '../util/get-or-set'
|
|
13
13
|
import { globalScope, isBrowserScope } from '../constants/runtime'
|
|
14
14
|
|
|
15
15
|
const wrapped = {}
|
|
16
|
-
const XHR = XMLHttpRequest
|
|
16
|
+
const XHR = globalScope.XMLHttpRequest
|
|
17
17
|
const ADD_EVENT_LISTENER = 'addEventListener'
|
|
18
18
|
const REMOVE_EVENT_LISTENER = 'removeEventListener'
|
|
19
|
+
const flag = `nr@wrapped:${contextId}`
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Wraps `addEventListener` and `removeEventListener` on: global scope; the prototype of `XMLHttpRequest`, and
|
|
@@ -48,7 +49,7 @@ export function wrapEvents (sharedEE) {
|
|
|
48
49
|
return
|
|
49
50
|
}
|
|
50
51
|
|
|
51
|
-
var wrapped = getOrSet(originalListener,
|
|
52
|
+
var wrapped = getOrSet(originalListener, flag, function () {
|
|
52
53
|
var listener = {
|
|
53
54
|
object: wrapHandleEvent,
|
|
54
55
|
function: originalListener
|
|
@@ -6,9 +6,8 @@
|
|
|
6
6
|
* @file Wraps `fetch` and related methods for instrumentation.
|
|
7
7
|
* This module is used by: ajax, spa.
|
|
8
8
|
*/
|
|
9
|
-
import { ee as baseEE } from '../event-emitter/contextual-ee'
|
|
9
|
+
import { ee as baseEE, contextId } from '../event-emitter/contextual-ee'
|
|
10
10
|
import { globalScope } from '../constants/runtime'
|
|
11
|
-
import { flag } from './wrap-function'
|
|
12
11
|
|
|
13
12
|
var prefix = 'fetch-'
|
|
14
13
|
var bodyPrefix = prefix + 'body-'
|
|
@@ -16,7 +15,6 @@ var bodyMethods = ['arrayBuffer', 'blob', 'json', 'text', 'formData']
|
|
|
16
15
|
var Req = globalScope.Request
|
|
17
16
|
var Res = globalScope.Response
|
|
18
17
|
var proto = 'prototype'
|
|
19
|
-
var ctxId = 'nr@context'
|
|
20
18
|
|
|
21
19
|
const wrapped = {}
|
|
22
20
|
|
|
@@ -76,7 +74,7 @@ export function wrapFetch (sharedEE) {
|
|
|
76
74
|
// we are wrapping args in an array so we can preserve the reference
|
|
77
75
|
ee.emit(prefix + 'before-start', [args], ctx)
|
|
78
76
|
var dtPayload
|
|
79
|
-
if (ctx[
|
|
77
|
+
if (ctx[contextId] && ctx[contextId].dt) dtPayload = ctx[contextId].dt
|
|
80
78
|
|
|
81
79
|
var origPromiseFromFetch = fn.apply(this, args)
|
|
82
80
|
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { ee } from '../event-emitter/contextual-ee'
|
|
10
|
-
|
|
10
|
+
import { bundleId } from '../ids/bundle-id'
|
|
11
|
+
|
|
12
|
+
export const flag = `nr@original:${bundleId}`
|
|
11
13
|
|
|
12
14
|
/**
|
|
13
15
|
* A convenience alias of `hasOwnProperty`.
|
|
@@ -107,26 +109,24 @@ export function createWrapperWithEmitter (emitter, always) {
|
|
|
107
109
|
|
|
108
110
|
/**
|
|
109
111
|
* Creates wrapper functions around each of an array of methods on a specified object.
|
|
110
|
-
* @param {Object} obj
|
|
111
|
-
* @param {string[]} methods
|
|
112
|
-
* @param {string} [prefix='']
|
|
113
|
-
*
|
|
114
|
-
* @param {function|object} [getContext]
|
|
115
|
-
*
|
|
116
|
-
* @param {boolean} [bubble=false]
|
|
117
|
-
*
|
|
112
|
+
* @param {Object} obj The object to which the specified methods belong.
|
|
113
|
+
* @param {string[]} methods An array of method names to be wrapped.
|
|
114
|
+
* @param {string} [prefix=''] A prefix to add to the names of emitted events. If `-` is the first character, also
|
|
115
|
+
* adds the method name before the prefix.
|
|
116
|
+
* @param {function|object} [getContext] The function or object that will serve as the 'this' context for handlers
|
|
117
|
+
* of events emitted by this wrapper.
|
|
118
|
+
* @param {boolean} [bubble=false] If `true`, emitted events should also bubble up to the old emitter upon which
|
|
119
|
+
* the `emitter` in the current scope was based (if it defines one).
|
|
118
120
|
*/
|
|
119
121
|
function inPlace (obj, methods, prefix, getContext, bubble) {
|
|
120
122
|
if (!prefix) prefix = ''
|
|
123
|
+
|
|
121
124
|
// If prefix starts with '-' set this boolean to add the method name to the prefix before passing each one to wrap.
|
|
122
|
-
|
|
123
|
-
var fn
|
|
124
|
-
var method
|
|
125
|
-
var i
|
|
125
|
+
const prependMethodPrefix = (prefix.charAt(0) === '-')
|
|
126
126
|
|
|
127
|
-
for (i = 0; i < methods.length; i++) {
|
|
128
|
-
method = methods[i]
|
|
129
|
-
fn = obj[method]
|
|
127
|
+
for (let i = 0; i < methods.length; i++) {
|
|
128
|
+
const method = methods[i]
|
|
129
|
+
const fn = obj[method]
|
|
130
130
|
|
|
131
131
|
// Unless fn is both wrappable and unwrapped, bail so we don't add extra properties with undefined values.
|
|
132
132
|
if (notWrappable(fn)) continue
|
|
@@ -217,31 +217,3 @@ function copy (from, to, emitter) {
|
|
|
217
217
|
function notWrappable (fn) {
|
|
218
218
|
return !(fn && fn instanceof Function && fn.apply && !fn[flag])
|
|
219
219
|
}
|
|
220
|
-
|
|
221
|
-
/**
|
|
222
|
-
* Creates a wrapped version of a function using a specified wrapper function. The new wrapped function references the
|
|
223
|
-
* original function. Also copies the properties of the original function to the wrapped function.
|
|
224
|
-
* @param {function} fn - A function to be wrapped.
|
|
225
|
-
* @param {function} wrapper - A higher order function that returns a new function, which executes the function passed
|
|
226
|
-
* to the higher order function as an argument.
|
|
227
|
-
* @returns {function} A wrapped function with an internal reference to the original function.
|
|
228
|
-
*/
|
|
229
|
-
export function wrapFunction (fn, wrapper) {
|
|
230
|
-
var wrapped = wrapper(fn)
|
|
231
|
-
wrapped[flag] = fn
|
|
232
|
-
copy(fn, wrapped, ee)
|
|
233
|
-
return wrapped
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Replaces a function with a wrapped version of itself. To preserve object references, rather than taking the function
|
|
238
|
-
* itself as an argument, takes the object on which the particular named function is a property.
|
|
239
|
-
* @param {Object} obj - The object on which the named function is a property.
|
|
240
|
-
* @param {string} fnName - The name of the function to be wrapped.
|
|
241
|
-
* @param {function} wrapper - A higher order function that returns a new function, which executes the function passed
|
|
242
|
-
* to the higher order function as an argument.
|
|
243
|
-
*/
|
|
244
|
-
export function wrapInPlace (obj, fnName, wrapper) {
|
|
245
|
-
var fn = obj[fnName]
|
|
246
|
-
obj[fnName] = wrapFunction(fn, wrapper)
|
|
247
|
-
}
|
|
@@ -9,8 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { ee as baseEE } from '../event-emitter/contextual-ee'
|
|
11
11
|
import { createWrapperWithEmitter as wfn } from './wrap-function'
|
|
12
|
-
import {
|
|
13
|
-
import { isBrowserScope } from '../constants/runtime'
|
|
12
|
+
import { globalScope, isBrowserScope } from '../constants/runtime'
|
|
14
13
|
|
|
15
14
|
const wrapped = {}
|
|
16
15
|
|
|
@@ -30,7 +29,7 @@ export function wrapMutation (sharedEE) {
|
|
|
30
29
|
wrapped[ee.debugId] = true // otherwise, first feature to wrap mutations
|
|
31
30
|
|
|
32
31
|
var wrapFn = wfn(ee)
|
|
33
|
-
var OriginalObserver =
|
|
32
|
+
var OriginalObserver = globalScope.MutationObserver
|
|
34
33
|
|
|
35
34
|
if (OriginalObserver) {
|
|
36
35
|
window.MutationObserver = function WrappedMutationObserver (cb) {
|
|
@@ -1,35 +1,5 @@
|
|
|
1
1
|
import { faker } from '@faker-js/faker'
|
|
2
2
|
import { globalScope } from '../constants/runtime'
|
|
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('../constants/runtime', () => ({
|
|
28
|
-
__esModule: true,
|
|
29
|
-
globalScope: {
|
|
30
|
-
NREUM: {}
|
|
31
|
-
}
|
|
32
|
-
}))
|
|
33
3
|
|
|
34
4
|
let promiseConstructorCalls
|
|
35
5
|
|
|
@@ -38,7 +8,7 @@ beforeEach(async () => {
|
|
|
38
8
|
|
|
39
9
|
// Proxy the global Promise to prevent the wrapping from
|
|
40
10
|
// messing with Jest internal promises
|
|
41
|
-
|
|
11
|
+
window.Promise = new Proxy(class extends Promise {}, {
|
|
42
12
|
construct (target, args) {
|
|
43
13
|
promiseConstructorCalls.push(args)
|
|
44
14
|
|
|
@@ -57,7 +27,7 @@ test('should wrap promise constructor', async () => {
|
|
|
57
27
|
const promiseInstance = new globalScope.Promise(jest.fn())
|
|
58
28
|
|
|
59
29
|
expect(promiseInstance).toBeInstanceOf(Promise)
|
|
60
|
-
expect(promiseConstructorCalls.length).
|
|
30
|
+
expect(promiseConstructorCalls.length).toBeGreaterThan(0)
|
|
61
31
|
expect(globalScope.Promise.toString()).toMatch(/\[native code\]/)
|
|
62
32
|
expect(globalScope.Promise.name).toEqual('Promise')
|
|
63
33
|
})
|
|
@@ -8,8 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { createWrapperWithEmitter as wrapFn, flag } from './wrap-function'
|
|
11
|
-
import { ee as baseEE
|
|
12
|
-
import { originals } from '../config/config'
|
|
11
|
+
import { ee as baseEE } from '../event-emitter/contextual-ee'
|
|
13
12
|
import { globalScope } from '../constants/runtime'
|
|
14
13
|
|
|
15
14
|
const wrapped = {}
|
|
@@ -29,9 +28,9 @@ export function wrapPromise (sharedEE) {
|
|
|
29
28
|
if (wrapped[promiseEE.debugId]) return promiseEE
|
|
30
29
|
wrapped[promiseEE.debugId] = true // otherwise, first feature to wrap promise
|
|
31
30
|
|
|
32
|
-
var getContext =
|
|
31
|
+
var getContext = promiseEE.context
|
|
33
32
|
var promiseWrapper = wrapFn(promiseEE)
|
|
34
|
-
var prevPromiseObj =
|
|
33
|
+
var prevPromiseObj = globalScope.Promise
|
|
35
34
|
|
|
36
35
|
if (prevPromiseObj) { // ensure there's a Promise API (native or otherwise) to even wrap
|
|
37
36
|
wrap()
|