@newrelic/browser-agent 1.232.0 → 1.233.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/cdn/polyfills.js +5 -2
- package/dist/cjs/common/config/state/configurable.js +15 -26
- package/dist/cjs/common/config/state/info.js +1 -1
- package/dist/cjs/common/config/state/init.js +101 -56
- package/dist/cjs/common/config/state/loader-config.js +1 -1
- package/dist/cjs/common/config/state/runtime.js +1 -5
- 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 +1 -1
- package/dist/cjs/common/harvest/harvest-scheduler.js +30 -10
- package/dist/cjs/common/harvest/harvest.js +119 -55
- package/dist/cjs/common/session/session-entity.js +35 -22
- package/dist/cjs/common/session/session-entity.test.js +73 -49
- package/dist/cjs/common/timer/interaction-timer.js +9 -12
- package/dist/cjs/common/url/canonicalize-url.js +32 -0
- package/dist/cjs/common/url/canonicalize-url.test.js +42 -0
- package/dist/cjs/common/url/clean-url.js +10 -3
- package/dist/cjs/common/url/protocol.test.js +0 -1
- package/dist/cjs/common/util/feature-flags.js +2 -1
- package/dist/cjs/common/util/global-scope.js +4 -2
- package/dist/cjs/common/util/submit-data.js +57 -18
- package/dist/cjs/common/wrap/wrap-fetch.js +1 -3
- package/dist/cjs/common/wrap/wrap-function.js +1 -3
- package/dist/cjs/common/wrap/wrap-promise.js +1 -1
- package/dist/cjs/features/ajax/aggregate/index.js +2 -2
- package/dist/cjs/features/ajax/instrument/index.js +1 -1
- package/dist/cjs/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +93 -10
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +164 -38
- package/dist/cjs/features/jserrors/aggregate/index.js +29 -48
- package/dist/cjs/features/jserrors/instrument/index.js +0 -2
- package/dist/cjs/features/metrics/aggregate/framework-detection.js +67 -0
- package/dist/cjs/features/metrics/aggregate/framework-detection.test.js +137 -0
- package/dist/cjs/features/metrics/aggregate/index.js +7 -3
- package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.js +14 -0
- package/dist/cjs/features/metrics/aggregate/polyfill-detection.es5.test.js +17 -0
- package/dist/cjs/features/metrics/aggregate/polyfill-detection.js +53 -0
- package/dist/cjs/features/metrics/aggregate/polyfill-detection.test.js +165 -0
- package/dist/cjs/features/page_action/aggregate/index.js +2 -2
- package/dist/cjs/features/page_view_event/aggregate/index.js +6 -3
- package/dist/cjs/features/page_view_timing/aggregate/index.js +2 -2
- package/dist/cjs/features/session_replay/aggregate/index.js +333 -0
- package/dist/cjs/features/session_replay/constants.js +9 -0
- package/dist/cjs/features/session_replay/index.js +12 -0
- package/dist/cjs/features/session_replay/instrument/index.js +29 -0
- package/dist/cjs/features/session_trace/aggregate/index.js +163 -164
- package/dist/cjs/features/session_trace/constants.js +2 -9
- package/dist/cjs/features/session_trace/instrument/index.js +24 -66
- package/dist/cjs/features/spa/aggregate/index.js +2 -2
- package/dist/cjs/features/utils/agent-session.js +1 -2
- package/dist/cjs/features/utils/aggregate-base.js +64 -0
- package/dist/cjs/features/utils/feature-base.js +0 -31
- package/dist/cjs/features/utils/handler-cache.js +3 -4
- package/dist/cjs/features/utils/instrument-base.js +42 -10
- package/dist/cjs/features/utils/{lazy-loader.js → lazy-feature-loader.js} +4 -2
- package/dist/cjs/loaders/agent.js +1 -1
- package/dist/cjs/loaders/api/apiAsync.js +3 -1
- package/dist/cjs/loaders/configure/configure.js +3 -3
- package/dist/cjs/loaders/features/featureDependencies.js +0 -12
- package/dist/cjs/loaders/features/features.js +3 -1
- package/dist/cjs/loaders/micro-agent.js +6 -6
- package/dist/esm/cdn/polyfills.js +5 -2
- package/dist/esm/common/config/state/configurable.js +14 -24
- package/dist/esm/common/config/state/info.js +2 -2
- package/dist/esm/common/config/state/init.js +102 -57
- package/dist/esm/common/config/state/loader-config.js +2 -2
- package/dist/esm/common/config/state/runtime.js +2 -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/drain/drain.js +1 -1
- package/dist/esm/common/harvest/harvest-scheduler.js +30 -10
- package/dist/esm/common/harvest/harvest.js +121 -56
- package/dist/esm/common/session/session-entity.js +35 -22
- package/dist/esm/common/session/session-entity.test.js +73 -49
- package/dist/esm/common/timer/interaction-timer.js +9 -12
- package/dist/esm/common/url/canonicalize-url.js +27 -0
- package/dist/esm/common/url/canonicalize-url.test.js +38 -0
- package/dist/esm/common/url/clean-url.js +10 -3
- package/dist/esm/common/url/protocol.test.js +0 -1
- package/dist/esm/common/util/feature-flags.js +2 -1
- package/dist/esm/common/util/global-scope.js +1 -0
- package/dist/esm/common/util/submit-data.js +57 -18
- package/dist/esm/common/wrap/wrap-fetch.js +1 -2
- package/dist/esm/common/wrap/wrap-function.js +1 -2
- package/dist/esm/common/wrap/wrap-promise.js +1 -1
- package/dist/esm/features/ajax/aggregate/index.js +2 -2
- package/dist/esm/features/ajax/instrument/index.js +1 -1
- package/dist/esm/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +93 -10
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +149 -25
- package/dist/esm/features/jserrors/aggregate/index.js +30 -48
- package/dist/esm/features/jserrors/instrument/index.js +0 -1
- package/dist/esm/features/metrics/aggregate/framework-detection.js +61 -0
- package/dist/esm/features/metrics/aggregate/framework-detection.test.js +133 -0
- package/dist/esm/features/metrics/aggregate/index.js +7 -3
- package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.js +8 -0
- package/dist/esm/features/metrics/aggregate/polyfill-detection.es5.test.js +15 -0
- package/dist/esm/features/metrics/aggregate/polyfill-detection.js +47 -0
- package/dist/esm/features/metrics/aggregate/polyfill-detection.test.js +163 -0
- package/dist/esm/features/page_action/aggregate/index.js +2 -2
- package/dist/esm/features/page_view_event/aggregate/index.js +6 -3
- package/dist/esm/features/page_view_timing/aggregate/index.js +2 -2
- package/dist/esm/features/session_replay/aggregate/index.js +327 -0
- package/dist/esm/features/session_replay/constants.js +2 -0
- package/dist/esm/features/session_replay/index.js +12 -0
- package/dist/esm/features/session_replay/instrument/index.js +21 -0
- package/dist/esm/features/session_trace/aggregate/index.js +163 -163
- package/dist/esm/features/session_trace/constants.js +1 -5
- package/dist/esm/features/session_trace/instrument/index.js +24 -66
- package/dist/esm/features/spa/aggregate/index.js +2 -2
- package/dist/esm/features/utils/agent-session.js +1 -2
- package/dist/esm/features/utils/aggregate-base.js +57 -0
- package/dist/esm/features/utils/feature-base.js +1 -32
- package/dist/esm/features/utils/handler-cache.js +3 -4
- package/dist/esm/features/utils/instrument-base.js +42 -10
- package/dist/esm/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
- package/dist/esm/loaders/agent.js +1 -1
- package/dist/esm/loaders/api/apiAsync.js +3 -1
- package/dist/esm/loaders/configure/configure.js +3 -3
- package/dist/esm/loaders/features/featureDependencies.js +0 -11
- package/dist/esm/loaders/features/features.js +3 -1
- package/dist/esm/loaders/micro-agent.js +6 -6
- package/dist/types/common/config/state/configurable.d.ts +1 -3
- package/dist/types/common/config/state/configurable.d.ts.map +1 -1
- package/dist/types/common/config/state/init.d.ts.map +1 -1
- package/dist/types/common/config/state/runtime.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest-scheduler.d.ts.map +1 -1
- package/dist/types/common/harvest/harvest.d.ts +37 -34
- package/dist/types/common/harvest/harvest.d.ts.map +1 -1
- package/dist/types/common/session/session-entity.d.ts +6 -3
- package/dist/types/common/session/session-entity.d.ts.map +1 -1
- package/dist/types/common/timer/interaction-timer.d.ts +2 -1
- package/dist/types/common/timer/interaction-timer.d.ts.map +1 -1
- package/dist/types/common/url/canonicalize-url.d.ts +9 -0
- package/dist/types/common/url/canonicalize-url.d.ts.map +1 -0
- package/dist/types/common/url/clean-url.d.ts +7 -1
- package/dist/types/common/url/clean-url.d.ts.map +1 -1
- package/dist/types/common/util/feature-flags.d.ts.map +1 -1
- package/dist/types/common/util/global-scope.d.ts +1 -0
- package/dist/types/common/util/global-scope.d.ts.map +1 -1
- package/dist/types/common/util/submit-data.d.ts +40 -14
- package/dist/types/common/util/submit-data.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.map +1 -1
- package/dist/types/features/ajax/aggregate/index.d.ts +2 -2
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts +8 -1
- package/dist/types/features/jserrors/aggregate/canonical-function-name.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts +48 -19
- package/dist/types/features/jserrors/aggregate/compute-stack-trace.d.ts.map +1 -1
- package/dist/types/features/jserrors/aggregate/index.d.ts +14 -5
- package/dist/types/features/jserrors/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/jserrors/instrument/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/framework-detection.d.ts.map +1 -0
- package/dist/types/features/metrics/aggregate/index.d.ts +2 -2
- package/dist/types/features/metrics/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts +6 -0
- package/dist/types/features/metrics/aggregate/polyfill-detection.d.ts.map +1 -0
- package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts +7 -0
- package/dist/types/features/metrics/aggregate/polyfill-detection.es5.d.ts.map +1 -0
- package/dist/types/features/page_action/aggregate/index.d.ts +3 -3
- package/dist/types/features/page_action/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/page_view_event/aggregate/index.d.ts +2 -2
- 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 +2 -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 +96 -0
- package/dist/types/features/session_replay/aggregate/index.d.ts.map +1 -0
- package/dist/types/features/session_replay/constants.d.ts +2 -0
- package/dist/types/features/session_replay/constants.d.ts.map +1 -0
- package/dist/types/features/session_replay/index.d.ts +2 -0
- package/dist/types/features/session_replay/index.d.ts.map +1 -0
- package/dist/types/features/session_replay/instrument/index.d.ts +6 -0
- package/dist/types/features/session_replay/instrument/index.d.ts.map +1 -0
- package/dist/types/features/session_trace/aggregate/index.d.ts +8 -57
- package/dist/types/features/session_trace/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/session_trace/constants.d.ts +0 -3
- package/dist/types/features/session_trace/constants.d.ts.map +1 -1
- package/dist/types/features/session_trace/instrument/index.d.ts +1 -3
- package/dist/types/features/session_trace/instrument/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/index.d.ts +2 -2
- package/dist/types/features/spa/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/utils/agent-session.d.ts.map +1 -1
- package/dist/types/features/utils/aggregate-base.d.ts +11 -0
- package/dist/types/features/utils/aggregate-base.d.ts.map +1 -0
- package/dist/types/features/utils/feature-base.d.ts +0 -5
- package/dist/types/features/utils/feature-base.d.ts.map +1 -1
- package/dist/types/features/utils/handler-cache.d.ts.map +1 -1
- package/dist/types/features/utils/instrument-base.d.ts +3 -1
- package/dist/types/features/utils/instrument-base.d.ts.map +1 -1
- package/dist/types/features/utils/{lazy-loader.d.ts → lazy-feature-loader.d.ts} +2 -2
- package/dist/types/features/utils/lazy-feature-loader.d.ts.map +1 -0
- package/dist/types/loaders/configure/configure.d.ts.map +1 -1
- package/dist/types/loaders/features/featureDependencies.d.ts +0 -1
- package/dist/types/loaders/features/featureDependencies.d.ts.map +1 -1
- package/dist/types/loaders/features/features.d.ts +1 -0
- package/dist/types/loaders/features/features.d.ts.map +1 -1
- package/package.json +31 -22
- package/src/cdn/polyfills.js +4 -1
- package/src/common/config/state/configurable.js +18 -24
- package/src/common/config/state/info.js +2 -2
- package/src/common/config/state/init.js +62 -28
- package/src/common/config/state/loader-config.js +2 -2
- package/src/common/config/state/runtime.js +2 -4
- package/src/common/drain/drain.js +1 -1
- package/src/common/harvest/harvest-scheduler.js +35 -10
- package/src/common/harvest/harvest.js +73 -50
- package/src/common/session/session-entity.js +34 -23
- package/src/common/session/session-entity.test.js +57 -51
- package/src/common/timer/interaction-timer.js +9 -12
- package/src/common/url/canonicalize-url.js +28 -0
- package/src/common/url/canonicalize-url.test.js +34 -0
- package/src/common/url/clean-url.js +10 -3
- package/src/common/url/protocol.test.js +0 -1
- package/src/common/util/feature-flags.js +2 -2
- package/src/common/util/global-scope.js +2 -0
- package/src/common/util/submit-data.js +28 -17
- package/src/common/wrap/wrap-fetch.js +1 -2
- package/src/common/wrap/wrap-function.js +1 -2
- package/src/common/wrap/wrap-promise.js +1 -1
- package/src/features/ajax/aggregate/index.js +2 -2
- package/src/features/ajax/instrument/index.js +1 -1
- package/src/features/jserrors/aggregate/canonical-function-name.js +12 -4
- package/src/features/jserrors/aggregate/compute-stack-trace.js +85 -11
- package/src/features/jserrors/aggregate/compute-stack-trace.test.js +141 -24
- package/src/features/jserrors/aggregate/index.js +28 -52
- package/src/features/jserrors/instrument/index.js +0 -1
- package/src/features/metrics/aggregate/framework-detection.js +73 -0
- package/src/features/metrics/aggregate/framework-detection.test.js +201 -0
- package/src/features/metrics/aggregate/index.js +8 -3
- package/src/features/metrics/aggregate/polyfill-detection.es5.js +9 -0
- package/src/features/metrics/aggregate/polyfill-detection.es5.test.js +16 -0
- package/src/features/metrics/aggregate/polyfill-detection.js +48 -0
- package/src/features/metrics/aggregate/polyfill-detection.test.js +163 -0
- package/src/features/page_action/aggregate/index.js +2 -2
- package/src/features/page_view_event/aggregate/index.js +5 -5
- package/src/features/page_view_timing/aggregate/index.js +2 -2
- package/src/features/session_replay/aggregate/index.js +314 -0
- package/src/features/session_replay/constants.js +3 -0
- package/src/features/session_replay/index.js +12 -0
- package/src/features/session_replay/instrument/index.js +22 -0
- package/src/features/session_trace/aggregate/index.js +148 -188
- package/src/features/session_trace/constants.js +0 -4
- package/src/features/session_trace/instrument/index.js +17 -69
- package/src/features/spa/aggregate/index.js +2 -2
- package/src/features/utils/agent-session.js +1 -2
- package/src/features/utils/aggregate-base.js +51 -0
- package/src/features/utils/feature-base.js +1 -31
- package/src/features/utils/handler-cache.js +3 -4
- package/src/features/utils/instrument-base.js +40 -8
- package/src/features/utils/{lazy-loader.js → lazy-feature-loader.js} +3 -1
- package/src/loaders/agent.js +1 -1
- package/src/loaders/api/apiAsync.js +1 -1
- package/src/loaders/configure/configure.js +4 -3
- package/src/loaders/features/featureDependencies.js +0 -12
- package/src/loaders/features/features.js +3 -1
- package/src/loaders/micro-agent.js +4 -4
- package/dist/cjs/common/metrics/framework-detection.js +0 -72
- package/dist/cjs/common/util/user-agent.js +0 -57
- package/dist/cjs/common/window/supports-performance-observer.js +0 -15
- package/dist/esm/common/metrics/framework-detection.js +0 -66
- package/dist/esm/common/util/user-agent.js +0 -48
- package/dist/esm/common/window/supports-performance-observer.js +0 -9
- package/dist/types/common/metrics/framework-detection.d.ts.map +0 -1
- package/dist/types/common/util/user-agent.d.ts +0 -5
- package/dist/types/common/util/user-agent.d.ts.map +0 -1
- package/dist/types/common/window/supports-performance-observer.d.ts +0 -2
- package/dist/types/common/window/supports-performance-observer.d.ts.map +0 -1
- package/dist/types/features/utils/lazy-loader.d.ts.map +0 -1
- package/src/common/metrics/framework-detection.js +0 -71
- package/src/common/util/user-agent.js +0 -56
- package/src/common/window/supports-performance-observer.js +0 -10
- /package/dist/types/{common/metrics → features/metrics/aggregate}/framework-detection.d.ts +0 -0
|
@@ -68,22 +68,47 @@ export class HarvestScheduler extends SharedContext {
|
|
|
68
68
|
if (this.aborted) return
|
|
69
69
|
var scheduler = this
|
|
70
70
|
|
|
71
|
-
|
|
72
|
-
|
|
71
|
+
let harvests = []
|
|
72
|
+
let submitMethod
|
|
73
|
+
|
|
74
|
+
if (this.opts.getPayload) { // Ajax & PVT & SR
|
|
75
|
+
submitMethod = getSubmitMethod(this.endpoint, opts)
|
|
73
76
|
if (!submitMethod) return false
|
|
74
77
|
|
|
75
|
-
|
|
78
|
+
const retry = submitMethod.method === submitData.xhr
|
|
76
79
|
var payload = this.opts.getPayload({ retry: retry })
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
80
|
+
|
|
81
|
+
if (!payload) return
|
|
82
|
+
|
|
83
|
+
payload = Object.prototype.toString.call(payload) === '[object Array]' ? payload : [payload]
|
|
84
|
+
harvests.push(...payload)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** sendX is used for features that do not supply a preformatted payload via "getPayload" */
|
|
88
|
+
let send = args => this.harvest.sendX(args)
|
|
89
|
+
if (harvests.length) {
|
|
90
|
+
/** _send is the underlying method for sending in the harvest, if sending raw we can bypass the other helpers completely which format the payloads */
|
|
91
|
+
if (this.opts.raw) send = args => this.harvest._send(args)
|
|
92
|
+
/** send is used to formated the payloads from "getPayload" and obfuscate before sending */
|
|
93
|
+
else send = args => this.harvest.send(args)
|
|
83
94
|
} else {
|
|
84
|
-
|
|
95
|
+
// force it to run at least once in sendX mode
|
|
96
|
+
harvests.push(undefined)
|
|
85
97
|
}
|
|
86
98
|
|
|
99
|
+
harvests.forEach(payload => {
|
|
100
|
+
send({
|
|
101
|
+
endpoint: this.endpoint,
|
|
102
|
+
payload,
|
|
103
|
+
opts,
|
|
104
|
+
submitMethod,
|
|
105
|
+
cbFinished: onHarvestFinished,
|
|
106
|
+
includeBaseParams: this.opts.includeBaseParams,
|
|
107
|
+
customUrl: this.opts.customUrl,
|
|
108
|
+
gzip: this.opts.gzip
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
|
|
87
112
|
if (this.started) {
|
|
88
113
|
this.scheduleHarvest()
|
|
89
114
|
}
|
|
@@ -8,7 +8,7 @@ import { obj as encodeObj, param as encodeParam } from '../url/encode'
|
|
|
8
8
|
import { stringify } from '../util/stringify'
|
|
9
9
|
import { submitData } from '../util/submit-data'
|
|
10
10
|
import { getLocation } from '../url/location'
|
|
11
|
-
import { getInfo, getConfigurationValue, getRuntime
|
|
11
|
+
import { getInfo, getConfigurationValue, getRuntime } from '../config/config'
|
|
12
12
|
import { cleanURL } from '../url/clean-url'
|
|
13
13
|
import { now } from '../timing/now'
|
|
14
14
|
import { eventListenerOpts } from '../event-listener/event-listener-opts'
|
|
@@ -18,6 +18,23 @@ import { SharedContext } from '../context/shared-context'
|
|
|
18
18
|
import { VERSION } from '../constants/env'
|
|
19
19
|
import { isBrowserScope, isWorkerScope } from '../util/global-scope'
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {object} NetworkSendSpec
|
|
23
|
+
* @param {string} endpoint The endpoint to use (jserrors, events, resources etc.)
|
|
24
|
+
* @param {object} payload Object representing payload.
|
|
25
|
+
* @param {object} payload.qs Map of values that should be sent as part of the request query string.
|
|
26
|
+
* @param {string} payload.body String that should be sent as the body of the request.
|
|
27
|
+
* @param {string} payload.body.e Special case of body used for browser interactions.
|
|
28
|
+
* @param {object} opts Additional options for sending data
|
|
29
|
+
* @param {boolean} opts.needResponse Specify whether the caller expects a response data.
|
|
30
|
+
* @param {boolean} opts.unload Specify whether the call is a final harvest during page unload.
|
|
31
|
+
* @param {boolean} opts.sendEmptyBody Specify whether the call should be made even if the body is empty. Useful for rum calls.
|
|
32
|
+
* @param {function} submitMethod The submit method to use {@link ../util/submit-data}
|
|
33
|
+
* @param {string} customUrl Override the beacon url the data is sent to; must include protocol if defined
|
|
34
|
+
* @param {boolean} gzip Enabled gzip compression on the body of the request before it is sent
|
|
35
|
+
* @param {boolean} includeBaseParams Enables the use of base query parameters in the beacon url {@see Harvest.baseQueryString}
|
|
36
|
+
*/
|
|
37
|
+
|
|
21
38
|
const haveSendBeacon = !!navigator.sendBeacon // only the web window obj has sendBeacon at this time, so 'false' for other envs
|
|
22
39
|
|
|
23
40
|
export class Harvest extends SharedContext {
|
|
@@ -34,55 +51,48 @@ export class Harvest extends SharedContext {
|
|
|
34
51
|
/**
|
|
35
52
|
* Initiate a harvest from multiple sources. An event that corresponds to the endpoint
|
|
36
53
|
* name is emitted, which gives any listeners the opportunity to provide payload data.
|
|
37
|
-
*
|
|
38
|
-
* @param {string} endpoint - The endpoint of the harvest (jserrors, events, resources etc.)
|
|
39
|
-
*
|
|
40
|
-
* @param {object} opts
|
|
41
|
-
* @param {bool} opts.needResponse - Specify whether the caller expects a response data.
|
|
42
|
-
* @param {bool} opts.unload - Specify whether the call is a final harvest during page unload.
|
|
54
|
+
* @param {NetworkSendSpec} spec Specification for sending data
|
|
43
55
|
*/
|
|
44
|
-
sendX (
|
|
56
|
+
sendX (spec) {
|
|
57
|
+
const { endpoint, opts } = spec
|
|
45
58
|
var submitMethod = getSubmitMethod(endpoint, opts)
|
|
46
59
|
if (!submitMethod) return false
|
|
47
60
|
var options = {
|
|
48
61
|
retry: submitMethod.method === submitData.xhr
|
|
49
62
|
}
|
|
50
|
-
|
|
63
|
+
const payload = this.createPayload(endpoint, options)
|
|
64
|
+
var caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this)
|
|
65
|
+
return caller({ ...spec, payload, submitMethod })
|
|
51
66
|
}
|
|
52
67
|
|
|
53
68
|
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
* @param {object} singlePayload - Object representing payload.
|
|
60
|
-
* @param {object} singlePayload.qs - Map of values that should be sent as part of the request query string.
|
|
61
|
-
* @param {string} singlePayload.body - String that should be sent as the body of the request.
|
|
62
|
-
* @param {string} singlePayload.body.e - Special case of body used for browser interactions.
|
|
63
|
-
*
|
|
64
|
-
* @param {object} opts
|
|
65
|
-
* @param {bool} opts.needResponse - Specify whether the caller expects a response data.
|
|
66
|
-
* @param {bool} opts.unload - Specify whether the call is a final harvest during page unload.
|
|
67
|
-
*/
|
|
68
|
-
send (endpoint, singlePayload, opts, submitMethod, cbFinished) {
|
|
69
|
+
* Initiate a harvest call.
|
|
70
|
+
* @param {NetworkSendSpec} spec Specification for sending data
|
|
71
|
+
*/
|
|
72
|
+
send (spec) {
|
|
73
|
+
const { payload = {} } = spec
|
|
69
74
|
var makeBody = createAccumulator()
|
|
70
75
|
var makeQueryString = createAccumulator()
|
|
71
|
-
if (
|
|
72
|
-
if (
|
|
76
|
+
if (payload.body) mapOwn(payload.body, makeBody)
|
|
77
|
+
if (payload.qs) mapOwn(payload.qs, makeQueryString)
|
|
73
78
|
|
|
74
|
-
var
|
|
75
|
-
var caller = this.obfuscator.shouldObfuscate() ?
|
|
79
|
+
var newPayload = { body: makeBody(), qs: makeQueryString() }
|
|
80
|
+
var caller = this.obfuscator.shouldObfuscate() ? this.obfuscateAndSend.bind(this) : this._send.bind(this)
|
|
76
81
|
|
|
77
|
-
return caller(
|
|
82
|
+
return caller({ ...spec, payload: newPayload })
|
|
78
83
|
}
|
|
79
84
|
|
|
80
|
-
|
|
85
|
+
/**
|
|
86
|
+
* Apply obfuscation rules to the payload and then initial the harvest network call.
|
|
87
|
+
* @param {NetworkSendSpec} spec Specification for sending data
|
|
88
|
+
*/
|
|
89
|
+
obfuscateAndSend (spec) {
|
|
90
|
+
const { payload = {} } = spec
|
|
81
91
|
applyFnToProps(payload, (...args) => this.obfuscator.obfuscateString(...args), 'string', ['e'])
|
|
82
|
-
return this._send(
|
|
92
|
+
return this._send({ ...spec, payload })
|
|
83
93
|
}
|
|
84
94
|
|
|
85
|
-
_send (endpoint, payload, opts, submitMethod, cbFinished) {
|
|
95
|
+
_send ({ endpoint, payload = {}, opts = {}, submitMethod, cbFinished, customUrl, gzip, includeBaseParams = true }) {
|
|
86
96
|
var info = getInfo(this.sharedContext.agentIdentifier)
|
|
87
97
|
if (!info.errorBeacon) return false
|
|
88
98
|
|
|
@@ -95,11 +105,10 @@ export class Harvest extends SharedContext {
|
|
|
95
105
|
return false
|
|
96
106
|
}
|
|
97
107
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
var url = this.getScheme() + '://' + info.errorBeacon + '/' + endpoint + '/1/' + info.licenseKey + this.baseQueryString()
|
|
101
|
-
if (payload.qs) url += encodeObj(payload.qs, agentRuntime.maxBytes)
|
|
108
|
+
var url = customUrl || this.getScheme() + '://' + info.errorBeacon + '/' + endpoint + '/1/' + info.licenseKey + '?'
|
|
102
109
|
|
|
110
|
+
var baseParams = includeBaseParams ? this.baseQueryString() : ''
|
|
111
|
+
var params = payload.qs ? encodeObj(payload.qs, agentRuntime.maxBytes) : ''
|
|
103
112
|
if (!submitMethod) {
|
|
104
113
|
submitMethod = getSubmitMethod(endpoint, opts)
|
|
105
114
|
}
|
|
@@ -107,29 +116,43 @@ export class Harvest extends SharedContext {
|
|
|
107
116
|
var useBody = submitMethod.useBody
|
|
108
117
|
|
|
109
118
|
var body
|
|
110
|
-
var fullUrl = url
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
119
|
+
var fullUrl = url + baseParams + params
|
|
120
|
+
|
|
121
|
+
if (!gzip) {
|
|
122
|
+
if (useBody && endpoint === 'events') {
|
|
123
|
+
body = payload.body.e
|
|
124
|
+
} else if (useBody) {
|
|
125
|
+
body = stringify(payload.body)
|
|
126
|
+
} else {
|
|
127
|
+
fullUrl = fullUrl + encodeObj(payload.body, agentRuntime.maxBytes)
|
|
128
|
+
}
|
|
129
|
+
} else body = payload.body
|
|
118
130
|
|
|
119
131
|
// Get bytes harvested per endpoint as a supportability metric. See metrics aggregator (on unload).
|
|
120
132
|
agentRuntime.bytesSent[endpoint] = (agentRuntime.bytesSent[endpoint] || 0) + body?.length || 0
|
|
121
133
|
// Get query bytes harvested per endpoint as a supportability metric. See metrics aggregator (on unload).
|
|
122
134
|
agentRuntime.queryBytesSent[endpoint] = (agentRuntime.queryBytesSent[endpoint] || 0) + fullUrl.split('?').slice(-1)[0]?.length || 0
|
|
123
135
|
|
|
136
|
+
const headers = []
|
|
137
|
+
|
|
138
|
+
if (gzip) {
|
|
139
|
+
headers.push({ key: 'content-type', value: 'application/json' })
|
|
140
|
+
headers.push({ key: 'X-Browser-Monitoring-Key', value: info.licenseKey })
|
|
141
|
+
headers.push({ key: 'Content-Encoding', value: 'gzip' })
|
|
142
|
+
} else {
|
|
143
|
+
headers.push({ key: 'content-type', value: 'text/plain' })
|
|
144
|
+
}
|
|
145
|
+
|
|
124
146
|
/* Since workers don't support sendBeacon right now, or Image(), they can only use XHR method.
|
|
125
147
|
Because they still do permit synch XHR, the idea is that at final harvest time (worker is closing),
|
|
126
148
|
we just make a BLOCKING request--trivial impact--with the remaining data as a temp fill-in for sendBeacon. */
|
|
127
|
-
|
|
149
|
+
|
|
150
|
+
var result = method({ url: fullUrl, body, sync: opts.unload && isWorkerScope, headers })
|
|
128
151
|
|
|
129
152
|
if (cbFinished && method === submitData.xhr) {
|
|
130
153
|
var xhr = result
|
|
131
154
|
xhr.addEventListener('load', function () {
|
|
132
|
-
var result = { sent: true }
|
|
155
|
+
var result = { sent: true, status: this.status }
|
|
133
156
|
if (this.status === 429) {
|
|
134
157
|
result.retry = true
|
|
135
158
|
result.delay = this.tooManyRequestsDelay
|
|
@@ -147,7 +170,7 @@ export class Harvest extends SharedContext {
|
|
|
147
170
|
// if beacon request failed, retry with an alternative method -- will not happen for workers
|
|
148
171
|
if (!result && method === submitData.beacon) {
|
|
149
172
|
method = submitData.img
|
|
150
|
-
result = method(url + encodeObj(payload.body, agentRuntime.maxBytes))
|
|
173
|
+
result = method({ url: fullUrl + encodeObj(payload.body, agentRuntime.maxBytes) })
|
|
151
174
|
}
|
|
152
175
|
|
|
153
176
|
return result
|
|
@@ -162,14 +185,14 @@ export class Harvest extends SharedContext {
|
|
|
162
185
|
var ref = this.obfuscator.shouldObfuscate() ? this.obfuscator.obfuscateString(location) : location
|
|
163
186
|
|
|
164
187
|
return ([
|
|
165
|
-
'
|
|
188
|
+
'a=' + info.applicationID,
|
|
166
189
|
encodeParam('sa', (info.sa ? '' + info.sa : '')),
|
|
167
190
|
encodeParam('v', VERSION),
|
|
168
191
|
transactionNameParam(info),
|
|
169
192
|
encodeParam('ct', runtime.customTransaction),
|
|
170
193
|
'&rst=' + now(),
|
|
171
194
|
'&ck=0', // ck param DEPRECATED - still expected by backend
|
|
172
|
-
'&s=' + (runtime.session?.value || '0'), // the 0 id encaps all untrackable and default traffic
|
|
195
|
+
'&s=' + (runtime.session?.state.value || '0'), // the 0 id encaps all untrackable and default traffic
|
|
173
196
|
encodeParam('ref', ref),
|
|
174
197
|
encodeParam('ptid', (runtime.ptid ? '' + runtime.ptid : ''))
|
|
175
198
|
].join(''))
|
|
@@ -241,7 +264,7 @@ function createAccumulator () {
|
|
|
241
264
|
var accumulator = {}
|
|
242
265
|
var hasData = false
|
|
243
266
|
return function (key, val) {
|
|
244
|
-
if (val && val.length) {
|
|
267
|
+
if (val !== null && val !== undefined && val.length) {
|
|
245
268
|
accumulator[key] = val
|
|
246
269
|
hasData = true
|
|
247
270
|
}
|
|
@@ -8,21 +8,29 @@ import { DEFAULT_EXPIRES_MS, DEFAULT_INACTIVE_MS, PREFIX } from './constants'
|
|
|
8
8
|
import { LocalMemory } from '../storage/local-memory'
|
|
9
9
|
import { InteractionTimer } from '../timer/interaction-timer'
|
|
10
10
|
import { wrapEvents } from '../wrap'
|
|
11
|
-
import {
|
|
11
|
+
import { getModeledObject } from '../config/state/configurable'
|
|
12
12
|
import { handle } from '../event-emitter/handle'
|
|
13
13
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../features/metrics/constants'
|
|
14
14
|
import { FEATURE_NAMES } from '../../loaders/features/features'
|
|
15
15
|
|
|
16
|
+
// this is what can be stored in local storage (not enforced but probably should be)
|
|
17
|
+
// these values should sync between local storage and the parent class props
|
|
16
18
|
const model = {
|
|
17
19
|
value: '',
|
|
18
20
|
inactiveAt: 0,
|
|
19
21
|
expiresAt: 0,
|
|
20
22
|
updatedAt: Date.now(),
|
|
21
|
-
|
|
23
|
+
sessionReplay: 0,
|
|
22
24
|
sessionTraceActive: false,
|
|
23
25
|
custom: {}
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
export const SESSION_EVENTS = {
|
|
29
|
+
PAUSE: 'session-pause',
|
|
30
|
+
RESET: 'session-reset',
|
|
31
|
+
RESUME: 'session-resume'
|
|
32
|
+
}
|
|
33
|
+
|
|
26
34
|
export class SessionEntity {
|
|
27
35
|
/**
|
|
28
36
|
* Create a self-managing Session Entity. This entity is scoped to the agent identifier which triggered it, allowing for multiple simultaneous session objects to exist.
|
|
@@ -39,14 +47,15 @@ export class SessionEntity {
|
|
|
39
47
|
if (!isBrowserScope) this.storage = new LocalMemory()
|
|
40
48
|
else this.storage = storageAPI
|
|
41
49
|
|
|
50
|
+
this.state = {}
|
|
51
|
+
|
|
42
52
|
this.sync(model)
|
|
43
53
|
|
|
44
54
|
this.agentIdentifier = agentIdentifier
|
|
45
|
-
|
|
46
55
|
// key is intended to act as the k=v pair
|
|
47
56
|
this.key = key
|
|
48
57
|
// value is intended to act as the primary value of the k=v pair
|
|
49
|
-
this.value = value
|
|
58
|
+
this.state.value = value
|
|
50
59
|
|
|
51
60
|
this.expiresMs = expiresMs
|
|
52
61
|
this.inactiveMs = inactiveMs
|
|
@@ -66,7 +75,7 @@ export class SessionEntity {
|
|
|
66
75
|
// the set-up of the timer used to expire the session "naturally" at a certain time
|
|
67
76
|
// this gets ignored if the value is falsy, allowing for session entities that do not expire
|
|
68
77
|
if (expiresMs) {
|
|
69
|
-
this.expiresAt = initialRead?.expiresAt || this.getFutureTimestamp(expiresMs)
|
|
78
|
+
this.state.expiresAt = initialRead?.expiresAt || this.getFutureTimestamp(expiresMs)
|
|
70
79
|
this.expiresTimer = new Timer({
|
|
71
80
|
// When the inactive timer ends, collect a SM and reset the session
|
|
72
81
|
onEnd: () => {
|
|
@@ -74,16 +83,16 @@ export class SessionEntity {
|
|
|
74
83
|
this.collectSM('duration', this)
|
|
75
84
|
this.reset()
|
|
76
85
|
}
|
|
77
|
-
}, this.expiresAt - Date.now())
|
|
86
|
+
}, this.state.expiresAt - Date.now())
|
|
78
87
|
} else {
|
|
79
|
-
this.expiresAt = Infinity
|
|
88
|
+
this.state.expiresAt = Infinity
|
|
80
89
|
}
|
|
81
90
|
|
|
82
91
|
// the set-up of the timer used to expire the session due to "inactivity" at a certain time
|
|
83
92
|
// this gets ignored if the value is falsy, allowing for session entities that do not expire
|
|
84
93
|
// this gets "refreshed" when "activity" is observed
|
|
85
94
|
if (inactiveMs) {
|
|
86
|
-
this.inactiveAt = initialRead?.inactiveAt || this.getFutureTimestamp(inactiveMs)
|
|
95
|
+
this.state.inactiveAt = initialRead?.inactiveAt || this.getFutureTimestamp(inactiveMs)
|
|
87
96
|
this.inactiveTimer = new InteractionTimer({
|
|
88
97
|
// When the inactive timer ends, collect a SM and reset the session
|
|
89
98
|
onEnd: () => {
|
|
@@ -93,21 +102,25 @@ export class SessionEntity {
|
|
|
93
102
|
},
|
|
94
103
|
// When the inactive timer refreshes, it will update the storage values with an update timestamp
|
|
95
104
|
onRefresh: this.refresh.bind(this),
|
|
105
|
+
onResume: () => { this.ee.emit(SESSION_EVENTS.RESUME) },
|
|
96
106
|
// When the inactive timer pauses, update the storage values with an update timestamp
|
|
97
|
-
onPause: () =>
|
|
107
|
+
onPause: () => {
|
|
108
|
+
if (this.initialized) this.ee.emit(SESSION_EVENTS.PAUSE)
|
|
109
|
+
this.write(getModeledObject(this.state, model))
|
|
110
|
+
},
|
|
98
111
|
ee: this.ee,
|
|
99
112
|
refreshEvents: ['click', 'keydown', 'scroll']
|
|
100
|
-
}, this.inactiveAt - Date.now())
|
|
113
|
+
}, this.state.inactiveAt - Date.now())
|
|
101
114
|
} else {
|
|
102
|
-
this.inactiveAt = Infinity
|
|
115
|
+
this.state.inactiveAt = Infinity
|
|
103
116
|
}
|
|
104
117
|
|
|
105
118
|
// The fact that the session is "new" or pre-existing is used in some places in the agent. Session Replay and Trace
|
|
106
119
|
// can use this info to inform whether to trust a new sampling decision vs continue a previous tracking effort.
|
|
107
|
-
this.isNew = !Object.keys(initialRead).length
|
|
120
|
+
if (this.isNew === undefined) this.isNew = !Object.keys(initialRead).length
|
|
108
121
|
// if its a "new" session, we write to storage API with the default values. These values may change over the lifespan of the agent run.
|
|
109
|
-
// we can use
|
|
110
|
-
if (this.isNew) this.write(
|
|
122
|
+
// we can use a modeled object here to help us know and manage what values are being used. -- see "model" above
|
|
123
|
+
if (this.isNew) this.write(getModeledObject(this.state, model), true)
|
|
111
124
|
else this.sync(initialRead)
|
|
112
125
|
|
|
113
126
|
this.initialized = true
|
|
@@ -119,7 +132,7 @@ export class SessionEntity {
|
|
|
119
132
|
}
|
|
120
133
|
|
|
121
134
|
sync (data) {
|
|
122
|
-
Object.assign(this, data)
|
|
135
|
+
Object.assign(this.state, data)
|
|
123
136
|
}
|
|
124
137
|
|
|
125
138
|
/**
|
|
@@ -167,7 +180,8 @@ export class SessionEntity {
|
|
|
167
180
|
if (!data || typeof data !== 'object') return
|
|
168
181
|
// everytime we update, we can update a timestamp for sanity
|
|
169
182
|
data.updatedAt = Date.now()
|
|
170
|
-
this.sync(data)
|
|
183
|
+
this.sync(data) // update the parent class "state" properties with the local storage values
|
|
184
|
+
//
|
|
171
185
|
// TODO - compression would need happen here if we decide to do it
|
|
172
186
|
this.storage.set(this.lookupKey, stringify(data))
|
|
173
187
|
return data
|
|
@@ -184,13 +198,11 @@ export class SessionEntity {
|
|
|
184
198
|
// * stop recording (stn and sr)...
|
|
185
199
|
// * delete the session and start over
|
|
186
200
|
try {
|
|
187
|
-
if (this.initialized) this.ee.emit(
|
|
188
|
-
|
|
201
|
+
if (this.initialized) this.ee.emit(SESSION_EVENTS.RESET)
|
|
189
202
|
this.storage.remove(this.lookupKey)
|
|
190
203
|
this.inactiveTimer?.abort?.()
|
|
191
204
|
this.expiresTimer?.clear?.()
|
|
192
|
-
delete this.
|
|
193
|
-
delete this.value
|
|
205
|
+
delete this.isNew
|
|
194
206
|
|
|
195
207
|
this.setup({
|
|
196
208
|
agentIdentifier: this.agentIdentifier,
|
|
@@ -211,8 +223,7 @@ export class SessionEntity {
|
|
|
211
223
|
refresh () {
|
|
212
224
|
// read here & invalidate
|
|
213
225
|
const existingData = this.read()
|
|
214
|
-
this.inactiveAt
|
|
215
|
-
this.write({ ...existingData, inactiveAt: this.inactiveAt })
|
|
226
|
+
this.write({ ...existingData, inactiveAt: this.getFutureTimestamp(this.inactiveMs) })
|
|
216
227
|
}
|
|
217
228
|
|
|
218
229
|
/**
|
|
@@ -228,7 +239,7 @@ export class SessionEntity {
|
|
|
228
239
|
* @returns {boolean}
|
|
229
240
|
*/
|
|
230
241
|
isInvalid (data) {
|
|
231
|
-
const requiredKeys =
|
|
242
|
+
const requiredKeys = Object.keys(model)
|
|
232
243
|
return !requiredKeys.every(x => Object.keys(data).includes(x))
|
|
233
244
|
}
|
|
234
245
|
|