@newrelic/browser-agent 1.253.0 → 1.254.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/CHANGELOG.md +15 -0
- package/README.md +1 -1
- package/dist/cjs/cdn/polyfills.js +2 -1
- package/dist/cjs/common/config/state/runtime.js +4 -1
- package/dist/cjs/common/constants/env.cdn.js +1 -1
- package/dist/cjs/common/constants/env.npm.js +1 -1
- package/dist/cjs/common/drain/drain.js +41 -27
- package/dist/cjs/common/event-emitter/contextual-ee.js +24 -22
- package/dist/cjs/common/harvest/harvest.js +5 -1
- package/dist/cjs/common/timing/time-keeper.js +94 -0
- package/dist/cjs/common/util/feature-flags.js +14 -31
- package/dist/cjs/common/wrap/wrap-events.js +2 -2
- package/dist/cjs/common/wrap/wrap-fetch.js +1 -2
- package/dist/cjs/common/wrap/wrap-function.js +7 -5
- package/dist/cjs/common/wrap/wrap-promise.js +1 -2
- package/dist/cjs/features/ajax/aggregate/index.js +7 -13
- package/dist/cjs/features/jserrors/aggregate/index.js +25 -24
- package/dist/cjs/features/metrics/aggregate/index.js +25 -24
- package/dist/cjs/features/page_action/aggregate/index.js +6 -4
- package/dist/cjs/features/page_view_event/aggregate/index.js +22 -2
- package/dist/cjs/features/page_view_timing/aggregate/index.js +15 -16
- package/dist/cjs/features/session_replay/aggregate/index.js +12 -4
- package/dist/cjs/features/session_trace/aggregate/index.js +11 -8
- package/dist/cjs/features/soft_navigations/aggregate/index.js +17 -12
- package/dist/cjs/features/spa/aggregate/index.js +19 -14
- package/dist/cjs/features/utils/aggregate-base.js +18 -5
- package/dist/cjs/features/utils/feature-base.js +2 -0
- package/dist/cjs/features/utils/instrument-base.js +1 -0
- package/dist/cjs/loaders/agent-base.js +2 -7
- package/dist/cjs/loaders/agent.js +4 -4
- package/dist/cjs/loaders/api/api.js +1 -1
- package/dist/cjs/loaders/configure/configure.js +1 -1
- package/dist/cjs/loaders/configure/nonce.cdn.js +13 -0
- package/dist/cjs/loaders/configure/nonce.js +2 -13
- package/dist/cjs/loaders/configure/public-path.cdn.js +16 -0
- package/dist/cjs/loaders/configure/public-path.js +2 -8
- package/dist/esm/cdn/polyfills.js +2 -1
- package/dist/esm/common/config/state/runtime.js +4 -1
- package/dist/esm/common/constants/env.cdn.js +1 -1
- package/dist/esm/common/constants/env.npm.js +1 -1
- package/dist/esm/common/drain/drain.js +40 -27
- package/dist/esm/common/event-emitter/contextual-ee.js +24 -22
- package/dist/esm/common/harvest/harvest.js +5 -1
- package/dist/esm/common/timing/time-keeper.js +88 -0
- package/dist/esm/common/util/feature-flags.js +14 -31
- package/dist/esm/common/wrap/wrap-events.js +3 -3
- package/dist/esm/common/wrap/wrap-fetch.js +2 -3
- package/dist/esm/common/wrap/wrap-function.js +5 -4
- package/dist/esm/common/wrap/wrap-promise.js +2 -3
- package/dist/esm/features/ajax/aggregate/index.js +7 -13
- package/dist/esm/features/jserrors/aggregate/index.js +25 -24
- package/dist/esm/features/metrics/aggregate/index.js +25 -24
- package/dist/esm/features/page_action/aggregate/index.js +6 -4
- package/dist/esm/features/page_view_event/aggregate/index.js +22 -2
- package/dist/esm/features/page_view_timing/aggregate/index.js +15 -16
- package/dist/esm/features/session_replay/aggregate/index.js +12 -4
- package/dist/esm/features/session_trace/aggregate/index.js +11 -8
- package/dist/esm/features/soft_navigations/aggregate/index.js +17 -12
- package/dist/esm/features/spa/aggregate/index.js +19 -14
- package/dist/esm/features/utils/aggregate-base.js +18 -5
- package/dist/esm/features/utils/feature-base.js +2 -0
- package/dist/esm/features/utils/instrument-base.js +1 -0
- package/dist/esm/loaders/agent-base.js +2 -7
- package/dist/esm/loaders/agent.js +4 -4
- package/dist/esm/loaders/api/api.js +1 -1
- package/dist/esm/loaders/configure/configure.js +1 -1
- package/dist/esm/loaders/configure/nonce.cdn.js +11 -0
- package/dist/esm/loaders/configure/nonce.js +1 -11
- package/dist/esm/loaders/configure/public-path.cdn.js +9 -0
- package/dist/esm/loaders/configure/public-path.js +2 -8
- package/dist/types/common/config/state/runtime.d.ts.map +1 -1
- package/dist/types/common/drain/drain.d.ts +6 -0
- package/dist/types/common/drain/drain.d.ts.map +1 -1
- package/dist/types/common/event-emitter/contextual-ee.d.ts +4 -3
- package/dist/types/common/event-emitter/contextual-ee.d.ts.map +1 -1
- package/dist/types/common/event-emitter/event-context.d.ts.map +1 -0
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/timing/time-keeper.d.ts +31 -0
- package/dist/types/common/timing/time-keeper.d.ts.map +1 -0
- package/dist/types/common/util/feature-flags.d.ts +11 -2
- package/dist/types/common/util/feature-flags.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 -0
- package/dist/types/common/wrap/wrap-function.d.ts.map +1 -1
- package/dist/types/common/wrap/wrap-promise.d.ts.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts +5 -5
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_timing/aggregate/index.d.ts +0 -2
- package/dist/types/features/page_view_timing/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/soft_navigations/aggregate/index.d.ts +0 -2
- package/dist/types/features/soft_navigations/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts +2 -0
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +2 -2
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -1
- package/dist/types/features/utils/feature-base.d.ts +1 -0
- package/dist/types/features/utils/feature-base.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/loaders/agent-base.d.ts +2 -2
- package/dist/types/loaders/agent-base.d.ts.map +1 -1
- package/dist/types/loaders/configure/public-path.d.ts +1 -1
- package/dist/types/loaders/configure/public-path.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/cdn/polyfills.js +1 -0
- package/src/common/config/state/runtime.js +4 -1
- package/src/common/drain/drain.js +41 -28
- package/src/common/event-emitter/contextual-ee.js +29 -31
- package/src/common/harvest/harvest.js +4 -1
- package/src/common/timing/time-keeper.js +96 -0
- package/src/common/util/feature-flags.js +13 -31
- package/src/common/wrap/wrap-events.js +3 -3
- package/src/common/wrap/wrap-fetch.js +2 -3
- package/src/common/wrap/wrap-function.js +6 -4
- package/src/common/wrap/wrap-promise.js +2 -3
- package/src/features/ajax/aggregate/index.js +8 -16
- package/src/features/jserrors/aggregate/index.js +12 -14
- package/src/features/metrics/aggregate/index.js +18 -17
- package/src/features/page_action/aggregate/index.js +6 -5
- package/src/features/page_view_event/aggregate/index.js +18 -2
- package/src/features/page_view_timing/aggregate/index.js +15 -15
- package/src/features/session_replay/aggregate/index.js +10 -4
- package/src/features/session_trace/aggregate/index.js +2 -2
- package/src/features/soft_navigations/aggregate/index.js +14 -12
- package/src/features/spa/aggregate/index.js +15 -13
- package/src/features/utils/aggregate-base.js +16 -8
- package/src/features/utils/feature-base.js +3 -0
- package/src/features/utils/instrument-base.js +1 -0
- package/src/loaders/agent-base.js +2 -7
- package/src/loaders/agent.js +2 -2
- package/src/loaders/api/api.js +1 -1
- package/src/loaders/configure/nonce.cdn.js +12 -0
- package/src/loaders/configure/nonce.js +1 -12
- package/src/loaders/configure/public-path.cdn.js +9 -0
- package/src/loaders/configure/public-path.js +2 -8
- package/dist/cjs/common/context/observation-context-manager.js +0 -56
- package/dist/cjs/loaders/configure/nonce.npm.js +0 -2
- package/dist/cjs/loaders/configure/public-path.npm.js +0 -10
- package/dist/esm/common/context/observation-context-manager.js +0 -49
- package/dist/esm/loaders/configure/nonce.npm.js +0 -1
- package/dist/esm/loaders/configure/public-path.npm.js +0 -3
- package/dist/types/common/context/event-context.d.ts.map +0 -1
- package/dist/types/common/context/observation-context-manager.d.ts +0 -28
- package/dist/types/common/context/observation-context-manager.d.ts.map +0 -1
- package/dist/types/loaders/configure/nonce.npm.d.ts +0 -1
- package/dist/types/loaders/configure/nonce.npm.d.ts.map +0 -1
- package/dist/types/loaders/configure/public-path.npm.d.ts +0 -2
- package/dist/types/loaders/configure/public-path.npm.d.ts.map +0 -1
- package/src/common/context/observation-context-manager.js +0 -55
- package/src/loaders/configure/nonce.npm.js +0 -1
- package/src/loaders/configure/public-path.npm.js +0 -3
- /package/dist/cjs/common/{context → event-emitter}/event-context.js +0 -0
- /package/dist/esm/common/{context → event-emitter}/event-context.js +0 -0
- /package/dist/types/common/{context → event-emitter}/event-context.d.ts +0 -0
- /package/src/common/{context → event-emitter}/event-context.js +0 -0
|
@@ -6,9 +6,11 @@
|
|
|
6
6
|
import { gosNREUM } from '../window/nreum'
|
|
7
7
|
import { getOrSet } from '../util/get-or-set'
|
|
8
8
|
import { getRuntime } from '../config/config'
|
|
9
|
-
import { EventContext } from '
|
|
10
|
-
import {
|
|
9
|
+
import { EventContext } from './event-context'
|
|
10
|
+
import { bundleId } from '../ids/bundle-id'
|
|
11
11
|
|
|
12
|
+
// create a unique id to store event context data for the current agent bundle
|
|
13
|
+
const contextId = `nr@context:${bundleId}`
|
|
12
14
|
// create global emitter instance that can be shared among bundles
|
|
13
15
|
const globalInstance = ee(undefined, 'globalEE')
|
|
14
16
|
|
|
@@ -18,7 +20,7 @@ if (!nr.ee) {
|
|
|
18
20
|
nr.ee = globalInstance
|
|
19
21
|
}
|
|
20
22
|
|
|
21
|
-
export { globalInstance as ee }
|
|
23
|
+
export { globalInstance as ee, contextId }
|
|
22
24
|
|
|
23
25
|
function ee (old, debugId) {
|
|
24
26
|
var handlers = {}
|
|
@@ -47,28 +49,41 @@ function ee (old, debugId) {
|
|
|
47
49
|
context,
|
|
48
50
|
buffer: bufferEventsByGroup,
|
|
49
51
|
abort,
|
|
50
|
-
aborted: false,
|
|
51
52
|
isBuffering,
|
|
52
53
|
debugId,
|
|
53
54
|
backlog: isolatedBacklog ? {} : old && typeof old.backlog === 'object' ? old.backlog : {},
|
|
54
|
-
|
|
55
|
+
isolatedBacklog
|
|
55
56
|
}
|
|
56
57
|
|
|
58
|
+
function abort () {
|
|
59
|
+
emitter._aborted = true
|
|
60
|
+
Object.keys(emitter.backlog).forEach(key => {
|
|
61
|
+
delete emitter.backlog[key]
|
|
62
|
+
})
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
Object.defineProperty(emitter, 'aborted', {
|
|
66
|
+
get: () => {
|
|
67
|
+
let aborted = emitter._aborted || false
|
|
68
|
+
|
|
69
|
+
if (aborted) return aborted
|
|
70
|
+
else if (old) {
|
|
71
|
+
aborted = old.aborted
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return aborted
|
|
75
|
+
}
|
|
76
|
+
})
|
|
77
|
+
|
|
57
78
|
return emitter
|
|
58
79
|
|
|
59
80
|
function context (contextOrStore) {
|
|
60
81
|
if (contextOrStore && contextOrStore instanceof EventContext) {
|
|
61
82
|
return contextOrStore
|
|
62
83
|
} else if (contextOrStore) {
|
|
63
|
-
return getOrSet(contextOrStore,
|
|
64
|
-
emitter.observationContextManager
|
|
65
|
-
? emitter.observationContextManager.getCreateContext(contextOrStore)
|
|
66
|
-
: new EventContext(ObservationContextManager.contextId)
|
|
67
|
-
)
|
|
84
|
+
return getOrSet(contextOrStore, contextId, () => new EventContext(contextId))
|
|
68
85
|
} else {
|
|
69
|
-
return
|
|
70
|
-
? emitter.observationContextManager.getCreateContext({})
|
|
71
|
-
: new EventContext(ObservationContextManager.contextId)
|
|
86
|
+
return new EventContext(contextId)
|
|
72
87
|
}
|
|
73
88
|
}
|
|
74
89
|
|
|
@@ -116,13 +131,7 @@ function ee (old, debugId) {
|
|
|
116
131
|
}
|
|
117
132
|
|
|
118
133
|
function getOrCreate (name) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
if (!newEventEmitter.observationContextManager && emitter.observationContextManager) {
|
|
122
|
-
newEventEmitter.observationContextManager = emitter.observationContextManager
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
return newEventEmitter
|
|
134
|
+
return (emitters[name] = emitters[name] || ee(emitter, name))
|
|
126
135
|
}
|
|
127
136
|
|
|
128
137
|
function bufferEventsByGroup (types, group) {
|
|
@@ -151,14 +160,3 @@ function ee (old, debugId) {
|
|
|
151
160
|
return emitter.backlog
|
|
152
161
|
}
|
|
153
162
|
}
|
|
154
|
-
|
|
155
|
-
function abort () {
|
|
156
|
-
globalInstance.aborted = true
|
|
157
|
-
// The global backlog can be referenced directly by other emitters,
|
|
158
|
-
// so we need to delete its contents as opposed to replacing it.
|
|
159
|
-
// Otherwise, these references to the old backlog would still exist
|
|
160
|
-
// and the keys will not be garbage collected.
|
|
161
|
-
Object.keys(globalInstance.backlog).forEach(key => {
|
|
162
|
-
delete globalInstance.backlog[key]
|
|
163
|
-
})
|
|
164
|
-
}
|
|
@@ -145,7 +145,7 @@ export class Harvest extends SharedContext {
|
|
|
145
145
|
result.addEventListener('loadend', function () {
|
|
146
146
|
// `this` refers to the XHR object in this scope, do not change this to a fat arrow
|
|
147
147
|
// status 0 refers to a local error, such as CORS or network failure, or a blocked request by the browser (e.g. adblocker)
|
|
148
|
-
const cbResult = { sent: this.status !== 0, status: this.status }
|
|
148
|
+
const cbResult = { sent: this.status !== 0, status: this.status, xhr: this, fullUrl }
|
|
149
149
|
if (this.status === 429) {
|
|
150
150
|
cbResult.retry = true
|
|
151
151
|
cbResult.delay = harvestScope.tooManyRequestsDelay
|
|
@@ -160,6 +160,9 @@ export class Harvest extends SharedContext {
|
|
|
160
160
|
}, eventListenerOpts(false))
|
|
161
161
|
}
|
|
162
162
|
|
|
163
|
+
const runtime = getRuntime(this.sharedContext.agentIdentifier)
|
|
164
|
+
runtime.harvestCount++
|
|
165
|
+
|
|
163
166
|
return result
|
|
164
167
|
}
|
|
165
168
|
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { gosNREUM } from '../window/nreum'
|
|
2
|
+
import { globalScope } from '../constants/runtime'
|
|
3
|
+
import { getRuntime } from '../config/config'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Class used to adjust the timestamp of harvested data to New Relic server time. This
|
|
7
|
+
* is done by tracking the performance timings of the RUM call and applying a calculation
|
|
8
|
+
* to the harvested data event offset time.
|
|
9
|
+
*/
|
|
10
|
+
export class TimeKeeper {
|
|
11
|
+
#agent
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Represents the browser origin time corrected to NR server time.
|
|
15
|
+
* @type {number}
|
|
16
|
+
*/
|
|
17
|
+
#correctedOriginTime
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Represents the difference in milliseconds between the calculated NR server time and
|
|
21
|
+
* the local time.
|
|
22
|
+
* @type {number}
|
|
23
|
+
*/
|
|
24
|
+
#localTimeDiff
|
|
25
|
+
|
|
26
|
+
constructor (agent) {
|
|
27
|
+
this.#agent = agent
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
static getTimeKeeperByAgentIdentifier (agentIdentifier) {
|
|
31
|
+
const nr = gosNREUM()
|
|
32
|
+
return Object.keys(nr?.initializedAgents || {}).indexOf(agentIdentifier) > -1
|
|
33
|
+
? nr.initializedAgents[agentIdentifier].timeKeeper
|
|
34
|
+
: undefined
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
get correctedPageOriginTime () {
|
|
38
|
+
return this.#correctedOriginTime
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Process a rum request to calculate NR server time.
|
|
43
|
+
* @param rumRequest {XMLHttpRequest} The xhr for the rum request
|
|
44
|
+
* @param rumRequestUrl {string} The full url of the rum request
|
|
45
|
+
*/
|
|
46
|
+
processRumRequest (rumRequest, rumRequestUrl) {
|
|
47
|
+
const responseDateHeader = rumRequest.getResponseHeader('Date')
|
|
48
|
+
if (!responseDateHeader) {
|
|
49
|
+
throw new Error('Missing date header on rum response.')
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const resourceEntries = globalScope.performance.getEntriesByName(rumRequestUrl, 'resource')
|
|
53
|
+
if (!Array.isArray((resourceEntries)) || resourceEntries.length === 0) {
|
|
54
|
+
throw new Error('Missing rum request performance entry.')
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
let medianRumOffset = 0
|
|
58
|
+
let serverOffset = 0
|
|
59
|
+
if (typeof resourceEntries[0].responseStart === 'number' && resourceEntries[0].responseStart !== 0) {
|
|
60
|
+
// Cors is enabled and we can make a more accurate calculation of NR server time
|
|
61
|
+
medianRumOffset = (resourceEntries[0].responseStart - resourceEntries[0].requestStart) / 2
|
|
62
|
+
serverOffset = Math.floor(resourceEntries[0].requestStart + medianRumOffset)
|
|
63
|
+
} else {
|
|
64
|
+
// Cors is disabled or erred, we need to use a less accurate calculation
|
|
65
|
+
medianRumOffset = (resourceEntries[0].responseEnd - resourceEntries[0].fetchStart) / 2
|
|
66
|
+
serverOffset = Math.floor(resourceEntries[0].fetchStart + medianRumOffset)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Corrected page origin time
|
|
70
|
+
this.#correctedOriginTime = Math.floor(Date.parse(responseDateHeader) - serverOffset)
|
|
71
|
+
this.#localTimeDiff = getRuntime(this.#agent.agentIdentifier).offset - this.#correctedOriginTime
|
|
72
|
+
|
|
73
|
+
if (Number.isNaN(this.#correctedOriginTime)) {
|
|
74
|
+
throw new Error('Date header invalid format.')
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Converts a page origin relative time to an absolute timestamp
|
|
80
|
+
* corrected to NR server time.
|
|
81
|
+
* @param relativeTime {number} The relative time of the event in milliseconds
|
|
82
|
+
* @returns {number} The correct timestamp as a unix/epoch timestamp value
|
|
83
|
+
*/
|
|
84
|
+
convertRelativeTimestamp (relativeTime) {
|
|
85
|
+
return this.#correctedOriginTime + relativeTime
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Corrects an event timestamp to NR server time.
|
|
90
|
+
* @param timestamp {number} The unix/epoch timestamp of the event with milliseconds
|
|
91
|
+
* @return {number} Corrected unix/epoch timestamp
|
|
92
|
+
*/
|
|
93
|
+
correctAbsoluteTimestamp (timestamp) {
|
|
94
|
+
return Math.floor(timestamp - this.#localTimeDiff)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -3,49 +3,31 @@
|
|
|
3
3
|
* SPDX-License-Identifier: Apache-2.0
|
|
4
4
|
*/
|
|
5
5
|
import { ee } from '../event-emitter/contextual-ee'
|
|
6
|
-
import { handle } from '../event-emitter/handle'
|
|
7
|
-
import { FEATURE_NAMES } from '../../loaders/features/features'
|
|
8
6
|
import { dispatchGlobalEvent } from '../dispatch/global-event'
|
|
9
7
|
|
|
10
|
-
const bucketMap = {
|
|
11
|
-
stn: [FEATURE_NAMES.sessionTrace],
|
|
12
|
-
err: [FEATURE_NAMES.jserrors, FEATURE_NAMES.metrics],
|
|
13
|
-
ins: [FEATURE_NAMES.pageAction],
|
|
14
|
-
spa: [FEATURE_NAMES.spa, FEATURE_NAMES.softNav],
|
|
15
|
-
sr: [FEATURE_NAMES.sessionReplay, FEATURE_NAMES.sessionTrace]
|
|
16
|
-
}
|
|
17
|
-
|
|
18
8
|
const sentIds = new Set()
|
|
19
9
|
|
|
20
|
-
/**
|
|
10
|
+
/** A map of feature flags and their values as provided by the rum call -- scoped by agent ID */
|
|
11
|
+
export const activatedFeatures = {}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Sets the activatedFeatures object, dispatches the global loaded event,
|
|
15
|
+
* and emits the rumresp flag to features
|
|
16
|
+
* @param {{[key:string]:number}} flags key-val pair of flag names and numeric
|
|
17
|
+
* @param {string} agentIdentifier agent instance identifier
|
|
18
|
+
* @returns {void}
|
|
19
|
+
*/
|
|
21
20
|
export function activateFeatures (flags, agentIdentifier) {
|
|
22
21
|
const sharedEE = ee.get(agentIdentifier)
|
|
22
|
+
activatedFeatures[agentIdentifier] ??= {}
|
|
23
23
|
if (!(flags && typeof flags === 'object')) return
|
|
24
24
|
if (sentIds.has(agentIdentifier)) return
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
bucketMap[flag].forEach(feat => {
|
|
29
|
-
if (!num) handle('block-' + flag, [], undefined, feat, sharedEE)
|
|
30
|
-
else handle('feat-' + flag, [], undefined, feat, sharedEE)
|
|
31
|
-
handle('rumresp-' + flag, [Boolean(num)], undefined, feat, sharedEE) // this is a duplicate of feat-/block- but makes awaiting for 1 event easier than 2
|
|
32
|
-
})
|
|
33
|
-
} else if (num) handle('feat-' + flag, [], undefined, undefined, sharedEE) // not sure what other flags are overlooked, but there's a test for ones not in the map --
|
|
34
|
-
activatedFeatures[flag] = Boolean(num)
|
|
35
|
-
})
|
|
26
|
+
sharedEE.emit('rumresp', [flags])
|
|
27
|
+
activatedFeatures[agentIdentifier] = flags
|
|
36
28
|
|
|
37
|
-
// Let the features waiting on their respective flags know that RUM response was received and that any missing flags are interpreted as bad entitlement / "off".
|
|
38
|
-
// Hence, those features will not be hanging forever if their flags aren't included in the response.
|
|
39
|
-
Object.keys(bucketMap).forEach(flag => {
|
|
40
|
-
if (activatedFeatures[flag] === undefined) {
|
|
41
|
-
bucketMap[flag]?.forEach(feat => handle('rumresp-' + flag, [false], undefined, feat, sharedEE))
|
|
42
|
-
activatedFeatures[flag] = false
|
|
43
|
-
}
|
|
44
|
-
})
|
|
45
29
|
sentIds.add(agentIdentifier)
|
|
46
30
|
|
|
47
31
|
// let any window level subscribers know that the agent is running
|
|
48
32
|
dispatchGlobalEvent({ loaded: true })
|
|
49
33
|
}
|
|
50
|
-
|
|
51
|
-
export const activatedFeatures = {}
|
|
@@ -7,16 +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
|
-
import { ObservationContextManager } from '../context/observation-context-manager'
|
|
15
14
|
|
|
16
15
|
const wrapped = {}
|
|
17
16
|
const XHR = globalScope.XMLHttpRequest
|
|
18
17
|
const ADD_EVENT_LISTENER = 'addEventListener'
|
|
19
18
|
const REMOVE_EVENT_LISTENER = 'removeEventListener'
|
|
19
|
+
const flag = `nr@wrapped:${contextId}`
|
|
20
20
|
|
|
21
21
|
/**
|
|
22
22
|
* Wraps `addEventListener` and `removeEventListener` on: global scope; the prototype of `XMLHttpRequest`, and
|
|
@@ -49,7 +49,7 @@ export function wrapEvents (sharedEE) {
|
|
|
49
49
|
return
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
var wrapped = getOrSet(originalListener,
|
|
52
|
+
var wrapped = getOrSet(originalListener, flag, function () {
|
|
53
53
|
var listener = {
|
|
54
54
|
object: wrapHandleEvent,
|
|
55
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 { ObservationContextManager } from '../context/observation-context-manager'
|
|
12
11
|
|
|
13
12
|
var prefix = 'fetch-'
|
|
14
13
|
var bodyPrefix = prefix + 'body-'
|
|
@@ -75,7 +74,7 @@ export function wrapFetch (sharedEE) {
|
|
|
75
74
|
// we are wrapping args in an array so we can preserve the reference
|
|
76
75
|
ee.emit(prefix + 'before-start', [args], ctx)
|
|
77
76
|
var dtPayload
|
|
78
|
-
if (ctx[
|
|
77
|
+
if (ctx[contextId] && ctx[contextId].dt) dtPayload = ctx[contextId].dt
|
|
79
78
|
|
|
80
79
|
var origPromiseFromFetch = fn.apply(this, args)
|
|
81
80
|
|
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { ee } from '../event-emitter/contextual-ee'
|
|
10
|
-
import {
|
|
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`.
|
|
@@ -40,7 +42,7 @@ export function createWrapperWithEmitter (emitter, always) {
|
|
|
40
42
|
* As a property on a wrapped function, contains the original function.
|
|
41
43
|
* @type {string}
|
|
42
44
|
*/
|
|
43
|
-
wrapFn.flag =
|
|
45
|
+
wrapFn.flag = flag
|
|
44
46
|
|
|
45
47
|
return wrapFn
|
|
46
48
|
|
|
@@ -59,7 +61,7 @@ export function createWrapperWithEmitter (emitter, always) {
|
|
|
59
61
|
|
|
60
62
|
if (!prefix) prefix = ''
|
|
61
63
|
|
|
62
|
-
nrWrapper[
|
|
64
|
+
nrWrapper[flag] = fn
|
|
63
65
|
copy(fn, nrWrapper, emitter)
|
|
64
66
|
return nrWrapper
|
|
65
67
|
|
|
@@ -213,5 +215,5 @@ function copy (from, to, emitter) {
|
|
|
213
215
|
* @returns {boolean} Whether the passed function is ineligible to be wrapped.
|
|
214
216
|
*/
|
|
215
217
|
function notWrappable (fn) {
|
|
216
|
-
return !(fn && typeof fn === 'function' && fn.apply && !fn[
|
|
218
|
+
return !(fn && typeof fn === 'function' && fn.apply && !fn[flag])
|
|
217
219
|
}
|
|
@@ -7,10 +7,9 @@
|
|
|
7
7
|
* This module is used by: spa.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { createWrapperWithEmitter as wrapFn } from './wrap-function'
|
|
10
|
+
import { createWrapperWithEmitter as wrapFn, flag } from './wrap-function'
|
|
11
11
|
import { ee as baseEE } from '../event-emitter/contextual-ee'
|
|
12
12
|
import { globalScope } from '../constants/runtime'
|
|
13
|
-
import { ObservationContextManager } from '../context/observation-context-manager'
|
|
14
13
|
|
|
15
14
|
const wrapped = {}
|
|
16
15
|
|
|
@@ -123,7 +122,7 @@ export function wrapPromise (sharedEE) {
|
|
|
123
122
|
|
|
124
123
|
return origFnCallWithThis
|
|
125
124
|
}
|
|
126
|
-
prevPromiseObj.prototype.then[
|
|
125
|
+
prevPromiseObj.prototype.then[flag] = prevPromiseOrigThen
|
|
127
126
|
|
|
128
127
|
promiseEE.on('executor-start', function (args) {
|
|
129
128
|
args[0] = promiseWrapper(args[0], 'resolve-', this, null, false)
|
|
@@ -21,13 +21,17 @@ export class Aggregate extends AggregateBase {
|
|
|
21
21
|
constructor (agentIdentifier, aggregator) {
|
|
22
22
|
super(agentIdentifier, aggregator, FEATURE_NAME)
|
|
23
23
|
const agentInit = getConfiguration(agentIdentifier)
|
|
24
|
-
const allAjaxIsEnabled = agentInit.ajax.enabled !== false
|
|
25
24
|
|
|
26
25
|
registerHandler('xhr', storeXhr, this.featureName, this.ee)
|
|
27
|
-
|
|
26
|
+
|
|
27
|
+
this.waitForFlags(([])).then(() => {
|
|
28
|
+
const scheduler = new HarvestScheduler('events', {
|
|
29
|
+
onFinished: onEventsHarvestFinished,
|
|
30
|
+
getPayload: prepareHarvest
|
|
31
|
+
}, this)
|
|
32
|
+
scheduler.startTimer(harvestTimeSeconds)
|
|
28
33
|
this.drain()
|
|
29
|
-
|
|
30
|
-
}
|
|
34
|
+
})
|
|
31
35
|
|
|
32
36
|
const denyList = getRuntime(agentIdentifier).denyList
|
|
33
37
|
setDenyList(denyList)
|
|
@@ -61,15 +65,6 @@ export class Aggregate extends AggregateBase {
|
|
|
61
65
|
registerHandler('returnAjax', event => ajaxEvents.push(event), this.featureName, this.ee)
|
|
62
66
|
// --- ^
|
|
63
67
|
|
|
64
|
-
const scheduler = new HarvestScheduler('events', {
|
|
65
|
-
onFinished: onEventsHarvestFinished,
|
|
66
|
-
getPayload: prepareHarvest
|
|
67
|
-
}, this)
|
|
68
|
-
|
|
69
|
-
ee.on(`drain-${this.featureName}`, () => { scheduler.startTimer(harvestTimeSeconds) })
|
|
70
|
-
|
|
71
|
-
this.drain()
|
|
72
|
-
|
|
73
68
|
const beacon = getInfo(agentIdentifier).errorBeacon
|
|
74
69
|
const proxyBeacon = agentInit.proxy.beacon
|
|
75
70
|
|
|
@@ -92,8 +87,6 @@ export class Aggregate extends AggregateBase {
|
|
|
92
87
|
aggregator.store('xhr', hash, params, metrics)
|
|
93
88
|
}
|
|
94
89
|
|
|
95
|
-
if (!allAjaxIsEnabled) return
|
|
96
|
-
|
|
97
90
|
if (!shouldCollect) {
|
|
98
91
|
if (params.hostname === beacon || (proxyBeacon && params.hostname === proxyBeacon)) {
|
|
99
92
|
// This doesn't make a distinction if the same-domain request is going to a different port or path...
|
|
@@ -143,7 +136,6 @@ export class Aggregate extends AggregateBase {
|
|
|
143
136
|
if (event.gql) handle(SUPPORTABILITY_METRIC_CHANNEL, ['Ajax/Events/GraphQL/Bytes-Added', stringify(event.gql).length], undefined, FEATURE_NAMES.metrics, ee)
|
|
144
137
|
|
|
145
138
|
const softNavInUse = Boolean(getNREUMInitializedAgent(agentIdentifier)?.features?.[FEATURE_NAMES.softNav])
|
|
146
|
-
|
|
147
139
|
if (softNavInUse) { // For newer soft nav (when running), pass the event to it for evaluation -- either part of an interaction or is given back
|
|
148
140
|
handle('ajax', [event], undefined, FEATURE_NAMES.softNav, ee)
|
|
149
141
|
} else if (this.spaNode) { // For old spa (when running), if the ajax happened inside an interaction, hold it until the interaction finishes
|
|
@@ -21,6 +21,7 @@ import { FEATURE_NAME } from '../constants'
|
|
|
21
21
|
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
22
22
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
23
23
|
import { getNREUMInitializedAgent } from '../../../common/window/nreum'
|
|
24
|
+
import { deregisterDrain } from '../../../common/drain/drain'
|
|
24
25
|
|
|
25
26
|
/**
|
|
26
27
|
* @typedef {import('./compute-stack-trace.js').StackInfo} StackInfo
|
|
@@ -48,21 +49,18 @@ export class Aggregate extends AggregateBase {
|
|
|
48
49
|
|
|
49
50
|
const harvestTimeSeconds = getConfigurationValue(this.agentIdentifier, 'jserrors.harvestTimeSeconds') || 10
|
|
50
51
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
52
|
+
// 0 == off, 1 == on
|
|
53
|
+
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
54
|
+
if (errFlag) {
|
|
55
|
+
const scheduler = new HarvestScheduler('jserrors', { onFinished: (...args) => this.onHarvestFinished(...args) }, this)
|
|
56
|
+
scheduler.harvest.on('jserrors', (...args) => this.onHarvestStarted(...args))
|
|
57
|
+
scheduler.startTimer(harvestTimeSeconds)
|
|
58
|
+
this.drain()
|
|
59
|
+
} else {
|
|
60
|
+
this.blocked = true // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
|
|
61
|
+
deregisterDrain(this.agentIdentifier, this.featureName)
|
|
62
|
+
}
|
|
57
63
|
})
|
|
58
|
-
|
|
59
|
-
// If RUM-call's response determines that customer lacks entitlements for the /jserror ingest endpoint, don't harvest at all.
|
|
60
|
-
register('block-err', () => {
|
|
61
|
-
this.blocked = true
|
|
62
|
-
scheduler.stopTimer(true)
|
|
63
|
-
}, this.featureName, this.ee)
|
|
64
|
-
|
|
65
|
-
this.drain()
|
|
66
64
|
}
|
|
67
65
|
|
|
68
66
|
onHarvestStarted (options) {
|
|
@@ -9,18 +9,25 @@ import { onDOMContentLoaded } from '../../../common/window/load'
|
|
|
9
9
|
import { windowAddEventListener } from '../../../common/event-listener/event-listener-opts'
|
|
10
10
|
import { isBrowserScope, isWorkerScope } from '../../../common/constants/runtime'
|
|
11
11
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
12
|
+
import { deregisterDrain } from '../../../common/drain/drain'
|
|
12
13
|
|
|
13
14
|
export class Aggregate extends AggregateBase {
|
|
14
15
|
static featureName = FEATURE_NAME
|
|
15
16
|
constructor (agentIdentifier, aggregator) {
|
|
16
17
|
super(agentIdentifier, aggregator, FEATURE_NAME)
|
|
17
|
-
let scheduler
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
this.waitForFlags(['err']).then(([errFlag]) => {
|
|
20
|
+
if (errFlag) {
|
|
21
|
+
// *cli, Mar 23 - Per NR-94597, this feature should only harvest ONCE at the (potential) EoL time of the page.
|
|
22
|
+
const scheduler = new HarvestScheduler('jserrors', { onUnload: () => this.unload() }, this)
|
|
23
|
+
// this is needed to ensure EoL is "on" and sent
|
|
24
|
+
scheduler.harvest.on('jserrors', () => ({ body: this.aggregator.take(['cm', 'sm']) }))
|
|
25
|
+
this.drain()
|
|
26
|
+
} else {
|
|
27
|
+
this.blocked = true // if rum response determines that customer lacks entitlements for spa endpoint, this feature shouldn't harvest
|
|
28
|
+
deregisterDrain(this.agentIdentifier, this.featureName)
|
|
29
|
+
}
|
|
30
|
+
})
|
|
24
31
|
|
|
25
32
|
// Allow features external to the metrics feature to capture SMs and CMs through the event emitter
|
|
26
33
|
registerHandler(SUPPORTABILITY_METRIC_CHANNEL, this.storeSupportabilityMetrics.bind(this), this.featureName, this.ee)
|
|
@@ -28,14 +35,6 @@ export class Aggregate extends AggregateBase {
|
|
|
28
35
|
|
|
29
36
|
this.singleChecks() // checks that are run only one time, at script load
|
|
30
37
|
this.eachSessionChecks() // the start of every time user engages with page
|
|
31
|
-
|
|
32
|
-
this.ee.on(`drain-${this.featureName}`, () => {
|
|
33
|
-
// *cli, Mar 23 - Per NR-94597, this feature should only harvest ONCE at the (potential) EoL time of the page.
|
|
34
|
-
scheduler = new HarvestScheduler('jserrors', { onUnload: () => this.unload() }, this)
|
|
35
|
-
scheduler.harvest.on('jserrors', () => ({ body: this.aggregator.take(['cm', 'sm']) }))
|
|
36
|
-
}) // this is needed to ensure EoL is "on" and sent
|
|
37
|
-
|
|
38
|
-
this.drain()
|
|
39
38
|
}
|
|
40
39
|
|
|
41
40
|
storeSupportabilityMetrics (name, value) {
|
|
@@ -55,6 +54,8 @@ export class Aggregate extends AggregateBase {
|
|
|
55
54
|
singleChecks () {
|
|
56
55
|
// report loaderType
|
|
57
56
|
const { distMethod, loaderType } = getRuntime(this.agentIdentifier)
|
|
57
|
+
const { proxy, privacy, page_view_timing } = getConfiguration(this.agentIdentifier)
|
|
58
|
+
|
|
58
59
|
if (loaderType) this.storeSupportabilityMetrics(`Generic/LoaderType/${loaderType}/Detected`)
|
|
59
60
|
if (distMethod) this.storeSupportabilityMetrics(`Generic/DistMethod/${distMethod}/Detected`)
|
|
60
61
|
|
|
@@ -72,6 +73,9 @@ export class Aggregate extends AggregateBase {
|
|
|
72
73
|
this.storeSupportabilityMetrics('Framework/' + framework + '/Detected')
|
|
73
74
|
})
|
|
74
75
|
})
|
|
76
|
+
|
|
77
|
+
if (!privacy.cookies_enabled) this.storeSupportabilityMetrics('Config/SessionTracking/Disabled')
|
|
78
|
+
if (page_view_timing.long_task) this.storeSupportabilityMetrics('Config/LongTask/Enabled')
|
|
75
79
|
} else if (isWorkerScope) {
|
|
76
80
|
this.storeSupportabilityMetrics('Generic/Runtime/Worker/Detected')
|
|
77
81
|
} else {
|
|
@@ -90,11 +94,8 @@ export class Aggregate extends AggregateBase {
|
|
|
90
94
|
if (rules.length > 0 && !validateRules(rules)) this.storeSupportabilityMetrics('Generic/Obfuscate/Invalid')
|
|
91
95
|
|
|
92
96
|
// Check if proxy for either chunks or beacon is being used
|
|
93
|
-
const { proxy, privacy } = getConfiguration(this.agentIdentifier)
|
|
94
97
|
if (proxy.assets) this.storeSupportabilityMetrics('Config/AssetsUrl/Changed')
|
|
95
98
|
if (proxy.beacon) this.storeSupportabilityMetrics('Config/BeaconUrl/Changed')
|
|
96
|
-
|
|
97
|
-
if (!(isBrowserScope && privacy.cookies_enabled)) this.storeSupportabilityMetrics('Config/SessionTracking/Disabled')
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
eachSessionChecks () {
|
|
@@ -12,6 +12,7 @@ import { getConfigurationValue, getInfo, getRuntime } from '../../../common/conf
|
|
|
12
12
|
import { FEATURE_NAME } from '../constants'
|
|
13
13
|
import { isBrowserScope } from '../../../common/constants/runtime'
|
|
14
14
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
15
|
+
import { deregisterDrain } from '../../../common/drain/drain'
|
|
15
16
|
|
|
16
17
|
export class Aggregate extends AggregateBase {
|
|
17
18
|
static featureName = FEATURE_NAME
|
|
@@ -31,17 +32,17 @@ export class Aggregate extends AggregateBase {
|
|
|
31
32
|
|
|
32
33
|
register('api-addPageAction', (...args) => this.addPageAction(...args), this.featureName, this.ee)
|
|
33
34
|
|
|
34
|
-
this.waitForFlags(['ins']).then(([
|
|
35
|
-
if (
|
|
35
|
+
this.waitForFlags(['ins']).then(([insFlag]) => {
|
|
36
|
+
if (insFlag) {
|
|
36
37
|
const scheduler = new HarvestScheduler('ins', { onFinished: (...args) => this.onHarvestFinished(...args) }, this)
|
|
37
38
|
scheduler.harvest.on('ins', (...args) => this.onHarvestStarted(...args))
|
|
38
39
|
scheduler.startTimer(this.harvestTimeSeconds, 0)
|
|
40
|
+
this.drain()
|
|
39
41
|
} else {
|
|
40
|
-
this.blocked = true
|
|
42
|
+
this.blocked = true // if rum response determines that customer lacks entitlements for ins endpoint, this feature shouldn't harvest
|
|
43
|
+
deregisterDrain(this.agentIdentifier, this.featureName)
|
|
41
44
|
}
|
|
42
45
|
})
|
|
43
|
-
|
|
44
|
-
this.drain()
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
onHarvestStarted (options) {
|
|
@@ -11,6 +11,10 @@ import { AggregateBase } from '../../utils/aggregate-base'
|
|
|
11
11
|
import { firstContentfulPaint } from '../../../common/vitals/first-contentful-paint'
|
|
12
12
|
import { firstPaint } from '../../../common/vitals/first-paint'
|
|
13
13
|
import { timeToFirstByte } from '../../../common/vitals/time-to-first-byte'
|
|
14
|
+
import { drain } from '../../../common/drain/drain'
|
|
15
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
16
|
+
import { handle } from '../../../common/event-emitter/handle'
|
|
17
|
+
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
14
18
|
|
|
15
19
|
export class Aggregate extends AggregateBase {
|
|
16
20
|
static featureName = CONSTANTS.FEATURE_NAME
|
|
@@ -100,7 +104,7 @@ export class Aggregate extends AggregateBase {
|
|
|
100
104
|
endpoint: 'rum',
|
|
101
105
|
payload: { qs: queryParameters, body },
|
|
102
106
|
opts: { needResponse: true, sendEmptyBody: true },
|
|
103
|
-
cbFinished: ({ status, responseText }) => {
|
|
107
|
+
cbFinished: ({ status, responseText, xhr, fullUrl }) => {
|
|
104
108
|
if (status >= 400 || status === 0) {
|
|
105
109
|
// Adding retry logic for the rum call will be a separate change
|
|
106
110
|
this.ee.abort()
|
|
@@ -108,7 +112,19 @@ export class Aggregate extends AggregateBase {
|
|
|
108
112
|
}
|
|
109
113
|
|
|
110
114
|
try {
|
|
111
|
-
|
|
115
|
+
this.timeKeeper.processRumRequest(xhr, fullUrl)
|
|
116
|
+
} catch (error) {
|
|
117
|
+
handle(SUPPORTABILITY_METRIC_CHANNEL, ['PVE/NRTime/Calculation/Failed'], undefined, FEATURE_NAMES.metrics, this.ee)
|
|
118
|
+
drain(this.agentIdentifier, FEATURE_NAMES.metrics, true)
|
|
119
|
+
this.ee.abort()
|
|
120
|
+
warn('Could not calculate New Relic server time. Agent shutting down.')
|
|
121
|
+
return
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const { app, ...flags } = JSON.parse(responseText)
|
|
126
|
+
agentRuntime.appMetadata = app
|
|
127
|
+
activateFeatures(flags, this.agentIdentifier)
|
|
112
128
|
this.drain()
|
|
113
129
|
} catch (err) {
|
|
114
130
|
this.ee.abort()
|