@newrelic/browser-agent 0.0.9 → 0.1.229
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/README.md +84 -207
- package/dist/cjs/cdn/lite.js +14 -0
- package/dist/cjs/cdn/polyfills/lite.js +4 -0
- package/dist/cjs/cdn/polyfills/pro.js +4 -0
- package/dist/cjs/cdn/polyfills/spa.js +4 -0
- package/dist/cjs/cdn/polyfills.js +14 -0
- package/dist/cjs/cdn/pro.js +19 -0
- package/dist/cjs/cdn/spa.js +19 -0
- package/dist/cjs/cdn/worker.js +16 -0
- package/dist/cjs/common/aggregate/aggregator.js +168 -0
- package/dist/cjs/common/browser-version/firefox-version.js +17 -0
- package/dist/cjs/common/browser-version/ios-version.js +18 -0
- package/dist/cjs/common/config/config.js +76 -0
- package/dist/cjs/common/config/state/configurable.js +32 -0
- package/dist/cjs/common/config/state/info.js +50 -0
- package/dist/cjs/common/config/state/init.js +86 -0
- package/dist/cjs/common/config/state/loader-config.js +28 -0
- package/dist/cjs/common/config/state/originals.js +9 -0
- package/dist/cjs/common/config/state/runtime.js +50 -0
- package/dist/cjs/common/constants/environment-variables.js +20 -0
- package/dist/cjs/common/context/shared-context.js +25 -0
- package/dist/cjs/common/deny-list/deny-list.js +108 -0
- package/dist/cjs/common/drain/drain.js +126 -0
- package/dist/cjs/common/event-emitter/contextual-ee.js +149 -0
- package/dist/cjs/common/event-emitter/handle.js +24 -0
- package/dist/cjs/common/event-emitter/register-handler.js +24 -0
- package/dist/cjs/common/event-listener/event-listener-opts.js +46 -0
- package/dist/cjs/common/harvest/harvest-scheduler.js +111 -0
- package/dist/cjs/common/harvest/harvest.js +236 -0
- package/dist/cjs/common/ids/id.js +30 -0
- package/dist/cjs/common/ids/unique-id.js +84 -0
- package/dist/cjs/common/metrics/framework-detection.js +72 -0
- package/dist/cjs/common/metrics/paint-metrics.js +13 -0
- package/dist/cjs/common/serialize/bel-serializer.js +89 -0
- package/dist/cjs/common/timing/nav-timing.js +77 -0
- package/dist/cjs/common/timing/now.js +15 -0
- package/dist/cjs/common/unload/eol.js +69 -0
- package/dist/cjs/common/url/clean-url.js +16 -0
- package/dist/cjs/common/url/encode.js +79 -0
- package/dist/cjs/common/url/location.js +14 -0
- package/dist/cjs/common/url/parse-url.js +66 -0
- package/dist/cjs/common/url/protocol.js +25 -0
- package/dist/cjs/common/util/console.js +17 -0
- package/dist/cjs/common/util/data-size.js +25 -0
- package/dist/cjs/common/util/feature-flags.js +42 -0
- package/dist/cjs/common/util/get-or-set.js +39 -0
- package/dist/cjs/common/util/global-scope.js +56 -0
- package/dist/cjs/common/util/map-own.js +24 -0
- package/dist/cjs/common/util/obfuscate.js +76 -0
- package/dist/cjs/common/util/reduce.js +22 -0
- package/dist/cjs/common/util/s-hash.js +19 -0
- package/dist/cjs/common/util/single.js +23 -0
- package/dist/cjs/common/util/stringify.js +47 -0
- package/dist/cjs/common/util/submit-data.js +99 -0
- package/dist/cjs/common/util/traverse.js +41 -0
- package/dist/cjs/common/util/user-agent.js +57 -0
- package/dist/cjs/common/window/load.js +19 -0
- package/dist/cjs/common/window/nreum.js +107 -0
- package/dist/cjs/common/window/page-visibility.js +28 -0
- package/dist/cjs/common/window/session-storage.js +42 -0
- package/dist/cjs/common/window/supports-performance-observer.js +15 -0
- package/dist/cjs/common/window/top-level-callers.js +23 -0
- package/dist/cjs/common/wrap/index.js +68 -0
- package/dist/cjs/common/wrap/wrap-events.js +105 -0
- package/dist/cjs/common/wrap/wrap-fetch.js +114 -0
- package/dist/cjs/common/wrap/wrap-function.js +269 -0
- package/dist/cjs/common/wrap/wrap-history.js +56 -0
- package/dist/cjs/common/wrap/wrap-jsonp.js +129 -0
- package/dist/cjs/common/wrap/wrap-mutation.js +61 -0
- package/dist/cjs/common/wrap/wrap-promise.js +160 -0
- package/dist/cjs/common/wrap/wrap-raf.js +55 -0
- package/dist/cjs/common/wrap/wrap-timer.js +70 -0
- package/dist/cjs/common/wrap/wrap-xhr.js +206 -0
- package/dist/cjs/features/ajax/aggregate/index.js +226 -0
- package/dist/cjs/features/ajax/constants.js +9 -0
- package/dist/cjs/features/ajax/index.js +12 -0
- package/dist/cjs/features/ajax/instrument/distributed-tracing.js +145 -0
- package/dist/cjs/features/ajax/instrument/index.js +338 -0
- package/dist/cjs/features/ajax/instrument/response-size.js +26 -0
- package/dist/cjs/features/jserrors/aggregate/canonical-function-name.js +18 -0
- package/dist/cjs/features/jserrors/aggregate/canonical-function-name.test.js +30 -0
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.js +216 -0
- package/dist/cjs/features/jserrors/aggregate/compute-stack-trace.test.js +257 -0
- package/dist/cjs/features/jserrors/aggregate/format-stack-trace.js +36 -0
- package/dist/cjs/features/jserrors/aggregate/format-stack-trace.test.js +39 -0
- package/dist/cjs/features/jserrors/aggregate/index.js +267 -0
- package/dist/cjs/features/jserrors/aggregate/string-hash-code.js +23 -0
- package/dist/cjs/features/jserrors/aggregate/string-hash-code.test.js +26 -0
- package/dist/cjs/features/jserrors/constants.js +11 -0
- package/dist/cjs/features/jserrors/index.js +12 -0
- package/dist/cjs/features/jserrors/instrument/debug.js +40 -0
- package/dist/cjs/features/jserrors/instrument/index.js +158 -0
- package/dist/cjs/features/metrics/aggregate/index.js +136 -0
- package/dist/cjs/features/metrics/constants.js +17 -0
- package/dist/cjs/features/metrics/index.js +12 -0
- package/dist/cjs/features/metrics/instrument/index.js +20 -0
- package/dist/cjs/features/metrics/instrument/workers-helper.js +121 -0
- package/dist/cjs/features/page_action/aggregate/index.js +112 -0
- package/dist/cjs/features/page_action/constants.js +9 -0
- package/dist/cjs/features/page_action/index.js +12 -0
- package/dist/cjs/features/page_action/instrument/index.js +21 -0
- package/dist/cjs/features/page_view_event/aggregate/index.js +133 -0
- package/dist/cjs/features/page_view_event/aggregate/initialized-features.js +39 -0
- package/dist/cjs/features/page_view_event/constants.js +15 -0
- package/dist/cjs/features/page_view_event/index.js +12 -0
- package/dist/cjs/features/page_view_event/instrument/index.js +38 -0
- package/dist/cjs/features/page_view_timing/aggregate/index.js +265 -0
- package/dist/cjs/features/page_view_timing/constants.js +9 -0
- package/dist/cjs/features/page_view_timing/first-paint.js +50 -0
- package/dist/cjs/features/page_view_timing/index.js +12 -0
- package/dist/cjs/features/page_view_timing/instrument/index.js +36 -0
- package/dist/cjs/features/page_view_timing/long-tasks.js +75 -0
- package/dist/cjs/features/session_trace/aggregate/index.js +375 -0
- package/dist/cjs/features/session_trace/constants.js +32 -0
- package/dist/cjs/features/session_trace/index.js +12 -0
- package/dist/cjs/features/session_trace/instrument/index.js +133 -0
- package/dist/cjs/features/spa/aggregate/index.js +684 -0
- package/dist/cjs/features/spa/aggregate/interaction-node.js +84 -0
- package/dist/cjs/features/spa/aggregate/interaction-node.test.js +16 -0
- package/dist/cjs/features/spa/aggregate/interaction.js +98 -0
- package/dist/cjs/features/spa/aggregate/serializer.js +147 -0
- package/dist/cjs/features/spa/constants.js +53 -0
- package/dist/cjs/features/spa/index.js +12 -0
- package/dist/cjs/features/spa/instrument/index.js +114 -0
- package/dist/cjs/features/utils/aggregate-base.js +13 -0
- package/dist/cjs/features/utils/feature-base.js +58 -0
- package/dist/cjs/features/utils/handler-cache.js +64 -0
- package/dist/cjs/features/utils/instrument-base.js +71 -0
- package/dist/cjs/features/utils/lazy-loader.js +44 -0
- package/dist/cjs/index.js +81 -58
- package/dist/cjs/loaders/agent.js +86 -0
- package/dist/cjs/loaders/api/api.js +109 -0
- package/dist/cjs/loaders/api/apiAsync.js +94 -0
- package/dist/cjs/loaders/browser-agent.js +29 -0
- package/dist/cjs/loaders/configure/configure.js +47 -0
- package/dist/cjs/loaders/features/enabled-features.js +19 -0
- package/dist/cjs/loaders/features/featureDependencies.js +32 -0
- package/dist/cjs/loaders/features/features.js +33 -0
- package/dist/cjs/loaders/micro-agent.js +93 -0
- package/dist/cjs/loaders/worker-agent.js +24 -0
- package/dist/esm/cdn/lite.js +12 -0
- package/dist/esm/cdn/polyfills/lite.js +7 -0
- package/dist/esm/cdn/polyfills/pro.js +7 -0
- package/dist/esm/cdn/polyfills/spa.js +7 -0
- package/dist/esm/cdn/polyfills.js +17 -0
- package/dist/esm/cdn/pro.js +17 -0
- package/dist/esm/cdn/spa.js +17 -0
- package/dist/esm/cdn/worker.js +14 -0
- package/dist/esm/common/aggregate/aggregator.js +161 -0
- package/dist/esm/common/browser-version/firefox-version.js +10 -0
- package/dist/esm/common/browser-version/ios-version.js +10 -0
- package/dist/esm/common/config/config.js +11 -0
- package/dist/esm/common/config/state/configurable.js +25 -0
- package/dist/esm/common/config/state/info.js +42 -0
- package/dist/esm/common/config/state/init.js +78 -0
- package/dist/esm/common/config/state/loader-config.js +21 -0
- package/dist/esm/common/config/state/originals.js +2 -0
- package/dist/esm/common/config/state/runtime.js +41 -0
- package/dist/esm/common/constants/environment-variables.js +11 -0
- package/dist/esm/common/context/shared-context.js +18 -0
- package/dist/esm/common/deny-list/deny-list.js +101 -0
- package/dist/esm/common/drain/drain.js +119 -0
- package/dist/esm/common/event-emitter/contextual-ee.js +142 -0
- package/dist/esm/common/event-emitter/handle.js +16 -0
- package/dist/esm/common/event-emitter/register-handler.js +19 -0
- package/dist/esm/common/event-listener/event-listener-opts.js +39 -0
- package/dist/esm/common/harvest/harvest-scheduler.js +105 -0
- package/dist/esm/common/harvest/harvest.js +228 -0
- package/dist/esm/common/ids/id.js +23 -0
- package/dist/esm/common/ids/unique-id.js +75 -0
- package/dist/esm/common/metrics/framework-detection.js +66 -0
- package/dist/esm/common/metrics/paint-metrics.js +6 -0
- package/dist/esm/common/serialize/bel-serializer.js +80 -0
- package/dist/esm/common/timing/nav-timing.js +67 -0
- package/dist/esm/common/timing/now.js +9 -0
- package/dist/esm/common/unload/eol.js +62 -0
- package/dist/esm/common/url/clean-url.js +10 -0
- package/dist/esm/common/url/encode.js +71 -0
- package/dist/esm/common/url/location.js +8 -0
- package/dist/esm/common/url/parse-url.js +60 -0
- package/dist/esm/common/url/protocol.js +17 -0
- package/dist/esm/common/util/console.js +11 -0
- package/dist/esm/common/util/data-size.js +19 -0
- package/dist/esm/common/util/feature-flags.js +33 -0
- package/dist/esm/common/util/get-or-set.js +33 -0
- package/dist/esm/common/util/global-scope.js +44 -0
- package/dist/esm/common/util/map-own.js +18 -0
- package/dist/esm/common/util/obfuscate.js +67 -0
- package/dist/esm/common/util/reduce.js +16 -0
- package/dist/esm/common/util/s-hash.js +13 -0
- package/dist/esm/common/util/single.js +16 -0
- package/dist/esm/common/util/stringify.js +42 -0
- package/dist/esm/common/util/submit-data.js +91 -0
- package/dist/esm/common/util/traverse.js +35 -0
- package/dist/esm/common/util/user-agent.js +48 -0
- package/dist/esm/common/window/load.js +12 -0
- package/dist/esm/common/window/nreum.js +91 -0
- package/dist/esm/common/window/page-visibility.js +23 -0
- package/dist/esm/common/window/session-storage.js +36 -0
- package/dist/esm/common/window/supports-performance-observer.js +9 -0
- package/dist/esm/common/window/top-level-callers.js +17 -0
- package/dist/esm/common/wrap/index.js +14 -0
- package/dist/esm/common/wrap/wrap-events.js +97 -0
- package/dist/esm/common/wrap/wrap-fetch.js +105 -0
- package/dist/esm/common/wrap/wrap-function.js +257 -0
- package/dist/esm/common/wrap/wrap-history.js +48 -0
- package/dist/esm/common/wrap/wrap-jsonp.js +122 -0
- package/dist/esm/common/wrap/wrap-mutation.js +54 -0
- package/dist/esm/common/wrap/wrap-promise.js +153 -0
- package/dist/esm/common/wrap/wrap-raf.js +48 -0
- package/dist/esm/common/wrap/wrap-timer.js +63 -0
- package/dist/esm/common/wrap/wrap-xhr.js +199 -0
- package/dist/esm/features/ajax/aggregate/index.js +218 -0
- package/dist/esm/features/ajax/constants.js +2 -0
- package/dist/esm/features/ajax/index.js +1 -0
- package/dist/esm/features/ajax/instrument/distributed-tracing.js +137 -0
- package/dist/esm/features/ajax/instrument/index.js +330 -0
- package/dist/esm/features/ajax/instrument/response-size.js +19 -0
- package/dist/esm/features/jserrors/aggregate/canonical-function-name.js +12 -0
- package/dist/esm/features/jserrors/aggregate/canonical-function-name.test.js +28 -0
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.js +209 -0
- package/dist/esm/features/jserrors/aggregate/compute-stack-trace.test.js +255 -0
- package/dist/esm/features/jserrors/aggregate/format-stack-trace.js +29 -0
- package/dist/esm/features/jserrors/aggregate/format-stack-trace.test.js +37 -0
- package/dist/esm/features/jserrors/aggregate/index.js +260 -0
- package/dist/esm/features/jserrors/aggregate/string-hash-code.js +17 -0
- package/dist/esm/features/jserrors/aggregate/string-hash-code.test.js +24 -0
- package/dist/esm/features/jserrors/constants.js +3 -0
- package/dist/esm/features/jserrors/index.js +1 -0
- package/dist/esm/features/jserrors/instrument/debug.js +38 -0
- package/dist/esm/features/jserrors/instrument/index.js +150 -0
- package/dist/esm/features/metrics/aggregate/index.js +129 -0
- package/dist/esm/features/metrics/constants.js +6 -0
- package/dist/esm/features/metrics/index.js +1 -0
- package/dist/esm/features/metrics/instrument/index.js +13 -0
- package/dist/esm/features/metrics/instrument/workers-helper.js +116 -0
- package/dist/esm/features/page_action/aggregate/index.js +105 -0
- package/dist/esm/features/page_action/constants.js +2 -0
- package/dist/esm/features/page_action/index.js +1 -0
- package/dist/esm/features/page_action/instrument/index.js +14 -0
- package/dist/esm/features/page_view_event/aggregate/index.js +124 -0
- package/dist/esm/features/page_view_event/aggregate/initialized-features.js +34 -0
- package/dist/esm/features/page_view_event/constants.js +5 -0
- package/dist/esm/features/page_view_event/index.js +1 -0
- package/dist/esm/features/page_view_event/instrument/index.js +29 -0
- package/dist/esm/features/page_view_timing/aggregate/index.js +258 -0
- package/dist/esm/features/page_view_timing/constants.js +2 -0
- package/dist/esm/features/page_view_timing/first-paint.js +43 -0
- package/dist/esm/features/page_view_timing/index.js +1 -0
- package/dist/esm/features/page_view_timing/instrument/index.js +28 -0
- package/dist/esm/features/page_view_timing/long-tasks.js +69 -0
- package/dist/esm/features/session_trace/aggregate/index.js +366 -0
- package/dist/esm/features/session_trace/constants.js +14 -0
- package/dist/esm/features/session_trace/index.js +1 -0
- package/dist/esm/features/session_trace/instrument/index.js +123 -0
- package/dist/esm/features/spa/aggregate/index.js +674 -0
- package/dist/esm/features/spa/aggregate/interaction-node.js +78 -0
- package/dist/esm/features/spa/aggregate/interaction-node.test.js +14 -0
- package/dist/esm/features/spa/aggregate/interaction.js +92 -0
- package/dist/esm/features/spa/aggregate/serializer.js +139 -0
- package/dist/esm/features/spa/constants.js +25 -0
- package/dist/esm/features/spa/index.js +1 -0
- package/dist/esm/features/spa/instrument/index.js +104 -0
- package/dist/esm/features/utils/aggregate-base.js +6 -0
- package/dist/esm/features/utils/feature-base.js +51 -0
- package/dist/esm/features/utils/handler-cache.js +57 -0
- package/dist/esm/features/utils/instrument-base.js +69 -0
- package/dist/esm/features/utils/lazy-loader.js +37 -0
- package/dist/esm/index.js +15 -0
- package/dist/esm/loaders/agent.js +77 -0
- package/dist/esm/loaders/api/api.js +104 -0
- package/dist/esm/loaders/api/apiAsync.js +88 -0
- package/dist/esm/loaders/browser-agent.js +23 -0
- package/dist/esm/loaders/configure/configure.js +41 -0
- package/dist/esm/loaders/features/enabled-features.js +13 -0
- package/dist/esm/loaders/features/featureDependencies.js +25 -0
- package/dist/esm/loaders/features/features.js +25 -0
- package/dist/esm/loaders/micro-agent.js +86 -0
- package/dist/esm/loaders/worker-agent.js +18 -0
- package/package.json +204 -71
- package/types.ts +221 -0
- package/dist/bundled/es5/index.js +0 -2
- package/dist/bundled/es5/index.js.map +0 -1
- package/dist/bundled/es6/index.js +0 -2
- package/dist/bundled/es6/index.js.map +0 -1
- package/dist/cjs/index.d.ts +0 -19
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/types.d.ts +0 -94
- package/dist/cjs/types.js +0 -28
- package/dist/cjs/types.js.map +0 -1
- package/dist/cjs/utils/api/api.d.ts +0 -10
- package/dist/cjs/utils/api/api.js +0 -40
- package/dist/cjs/utils/api/api.js.map +0 -1
- package/dist/cjs/utils/config/build-configs.d.ts +0 -6
- package/dist/cjs/utils/config/build-configs.js +0 -68
- package/dist/cjs/utils/config/build-configs.js.map +0 -1
- package/dist/cjs/utils/features/features.d.ts +0 -5
- package/dist/cjs/utils/features/features.js +0 -14
- package/dist/cjs/utils/features/features.js.map +0 -1
- package/dist/cjs/utils/features/initialize.d.ts +0 -5
- package/dist/cjs/utils/features/initialize.js +0 -51
- package/dist/cjs/utils/features/initialize.js.map +0 -1
- package/dist/es/index.d.ts +0 -19
- package/dist/es/index.js +0 -55
- package/dist/es/index.js.map +0 -1
- package/dist/es/types.d.ts +0 -94
- package/dist/es/types.js +0 -24
- package/dist/es/types.js.map +0 -1
- package/dist/es/utils/api/api.d.ts +0 -10
- package/dist/es/utils/api/api.js +0 -36
- package/dist/es/utils/api/api.js.map +0 -1
- package/dist/es/utils/config/build-configs.d.ts +0 -6
- package/dist/es/utils/config/build-configs.js +0 -64
- package/dist/es/utils/config/build-configs.js.map +0 -1
- package/dist/es/utils/features/features.d.ts +0 -5
- package/dist/es/utils/features/features.js +0 -10
- package/dist/es/utils/features/features.js.map +0 -1
- package/dist/es/utils/features/initialize.d.ts +0 -5
- package/dist/es/utils/features/initialize.js +0 -24
- package/dist/es/utils/features/initialize.js.map +0 -1
- package/dist/umd/index.d.ts +0 -19
- package/dist/umd/index.js +0 -69
- package/dist/umd/index.js.map +0 -1
- package/dist/umd/types.d.ts +0 -94
- package/dist/umd/types.js +0 -38
- package/dist/umd/types.js.map +0 -1
- package/dist/umd/utils/api/api.d.ts +0 -10
- package/dist/umd/utils/api/api.js +0 -50
- package/dist/umd/utils/api/api.js.map +0 -1
- package/dist/umd/utils/config/build-configs.d.ts +0 -6
- package/dist/umd/utils/config/build-configs.js +0 -78
- package/dist/umd/utils/config/build-configs.js.map +0 -1
- package/dist/umd/utils/features/features.d.ts +0 -5
- package/dist/umd/utils/features/features.js +0 -24
- package/dist/umd/utils/features/features.js.map +0 -1
- package/dist/umd/utils/features/initialize.d.ts +0 -5
- package/dist/umd/utils/features/initialize.js +0 -63
- package/dist/umd/utils/features/initialize.js.map +0 -1
- package/dist/webpack-analysis.html +0 -38
|
@@ -0,0 +1,674 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
3
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
4
|
+
*/
|
|
5
|
+
/*eslint no-undef: "error"*/
|
|
6
|
+
import { registerHandler as register } from '../../../common/event-emitter/register-handler';
|
|
7
|
+
import { parseUrl } from '../../../common/url/parse-url';
|
|
8
|
+
import { shouldCollectEvent } from '../../../common/deny-list/deny-list';
|
|
9
|
+
import { mapOwn } from '../../../common/util/map-own';
|
|
10
|
+
import { navTimingValues as navTiming } from '../../../common/timing/nav-timing';
|
|
11
|
+
import { generateUuid } from '../../../common/ids/unique-id';
|
|
12
|
+
import { paintMetrics } from '../../../common/metrics/paint-metrics';
|
|
13
|
+
import { Interaction } from './interaction';
|
|
14
|
+
import { getConfigurationValue, getRuntime } from '../../../common/config/config';
|
|
15
|
+
import { eventListenerOpts } from '../../../common/event-listener/event-listener-opts';
|
|
16
|
+
import { AggregateBase } from '../../utils/aggregate-base';
|
|
17
|
+
import { HarvestScheduler } from '../../../common/harvest/harvest-scheduler';
|
|
18
|
+
import { Serializer } from './serializer';
|
|
19
|
+
import { ee } from '../../../common/event-emitter/contextual-ee';
|
|
20
|
+
import * as CONSTANTS from '../constants';
|
|
21
|
+
import { drain } from '../../../common/drain/drain';
|
|
22
|
+
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
23
|
+
const {
|
|
24
|
+
FEATURE_NAME,
|
|
25
|
+
INTERACTION_EVENTS,
|
|
26
|
+
MAX_TIMER_BUDGET,
|
|
27
|
+
FN_START,
|
|
28
|
+
FN_END,
|
|
29
|
+
CB_START,
|
|
30
|
+
INTERACTION_API,
|
|
31
|
+
REMAINING,
|
|
32
|
+
INTERACTION,
|
|
33
|
+
SPA_NODE,
|
|
34
|
+
JSONP_NODE,
|
|
35
|
+
FETCH_START,
|
|
36
|
+
FETCH_DONE,
|
|
37
|
+
FETCH_BODY,
|
|
38
|
+
JSONP_END,
|
|
39
|
+
originalSetTimeout
|
|
40
|
+
} = CONSTANTS;
|
|
41
|
+
export class Aggregate extends AggregateBase {
|
|
42
|
+
static featureName = FEATURE_NAME;
|
|
43
|
+
constructor(agentIdentifier, aggregator) {
|
|
44
|
+
super(agentIdentifier, aggregator, FEATURE_NAME);
|
|
45
|
+
this.state = {
|
|
46
|
+
initialPageURL: getRuntime(agentIdentifier).origin,
|
|
47
|
+
lastSeenUrl: getRuntime(agentIdentifier).origin,
|
|
48
|
+
lastSeenRouteName: null,
|
|
49
|
+
timerMap: {},
|
|
50
|
+
timerBudget: MAX_TIMER_BUDGET,
|
|
51
|
+
currentNode: null,
|
|
52
|
+
prevNode: null,
|
|
53
|
+
nodeOnLastHashUpdate: null,
|
|
54
|
+
initialPageLoad: null,
|
|
55
|
+
pageLoaded: false,
|
|
56
|
+
childTime: 0,
|
|
57
|
+
depth: 0,
|
|
58
|
+
harvestTimeSeconds: getConfigurationValue(agentIdentifier, 'spa.harvestTimeSeconds') || 10,
|
|
59
|
+
interactionsToHarvest: [],
|
|
60
|
+
interactionsSent: []
|
|
61
|
+
};
|
|
62
|
+
this.serializer = new Serializer(this);
|
|
63
|
+
const {
|
|
64
|
+
state,
|
|
65
|
+
serializer
|
|
66
|
+
} = this;
|
|
67
|
+
let {
|
|
68
|
+
blocked
|
|
69
|
+
} = this;
|
|
70
|
+
const baseEE = ee.get(agentIdentifier); // <-- parent baseEE
|
|
71
|
+
const mutationEE = baseEE.get('mutation');
|
|
72
|
+
const promiseEE = baseEE.get('promise');
|
|
73
|
+
const historyEE = baseEE.get('history');
|
|
74
|
+
const eventsEE = baseEE.get('events'); // ajax --> ee(123).emit() ee()
|
|
75
|
+
const timerEE = baseEE.get('timer');
|
|
76
|
+
const fetchEE = baseEE.get('fetch');
|
|
77
|
+
const jsonpEE = baseEE.get('jsonp');
|
|
78
|
+
const xhrEE = baseEE.get('xhr');
|
|
79
|
+
const tracerEE = baseEE.get('tracer');
|
|
80
|
+
const scheduler = new HarvestScheduler('events', {
|
|
81
|
+
onFinished: onHarvestFinished,
|
|
82
|
+
retryDelay: state.harvestTimeSeconds
|
|
83
|
+
}, {
|
|
84
|
+
agentIdentifier
|
|
85
|
+
});
|
|
86
|
+
scheduler.harvest.on('events', onHarvestStarted);
|
|
87
|
+
|
|
88
|
+
// childTime is used when calculating exclusive time for a cb duration.
|
|
89
|
+
//
|
|
90
|
+
// Exclusive time will be different than the total time for either callbacks
|
|
91
|
+
// which synchronously invoke a customTracer callback or, trigger a synchronous
|
|
92
|
+
// event (eg. onreadystate=1 or popstate).
|
|
93
|
+
//
|
|
94
|
+
// At fn-end, childTime will contain the total time of all timed callbacks and
|
|
95
|
+
// event handlers which executed as a child of the current callback. At the
|
|
96
|
+
// begining of every callback, childTime is saved to the event context (which at
|
|
97
|
+
// that time contains the sum of its preceeding siblings) and is reset to 0. The
|
|
98
|
+
// callback is then executed, and its children may increase childTime. At the
|
|
99
|
+
// end of the callback, it reports its exclusive time as its
|
|
100
|
+
// execution time - exlcuded. childTime is then reset to its previous
|
|
101
|
+
// value, and the totalTime of the callback that just finished executing is
|
|
102
|
+
// added to the childTime time.
|
|
103
|
+
// | clock | childTime | ctx.ct | totalTime | exclusive |
|
|
104
|
+
// click fn-start | 0 | 0 | 0 | | |
|
|
105
|
+
// | click begining: | 5 | 0 | 0 | | |
|
|
106
|
+
// | | custom-1 fn-start | 10 | 0 | 0 | | |
|
|
107
|
+
// | | | custom-1 begining | 15 | 0 | 0 | | |
|
|
108
|
+
// | | | | custom-2 fn-start | 20 | 0 | 0 | | |
|
|
109
|
+
// | | | | | custom-2 | 25 | 0 | 0 | | |
|
|
110
|
+
// | | | | custom-2 fn-end | 30 | 10 | 0 | 10 | 10 |
|
|
111
|
+
// | | | custom-1 middle | 35 | 10 | 0 | | |
|
|
112
|
+
// | | | | custom-3 fn-start | 40 | 0 | 10 | | |
|
|
113
|
+
// | | | | | custom-3 | 45 | 0 | 10 | | |
|
|
114
|
+
// | | | | custom-3 fn-end | 50 | 20 | 0 | 10 | 10 |
|
|
115
|
+
// | | | custom-1 ending | 55 | 20 | 0 | | |
|
|
116
|
+
// | custom-1 fn-end | 60 | 50 | 0 | 50 | 30 |
|
|
117
|
+
// | click ending: | 65 | 50 | | | |
|
|
118
|
+
// click fn-end | 70 | 0 | 0 | 70 | 20 |
|
|
119
|
+
|
|
120
|
+
// if rum response determines that customer lacks entitlements for spa endpoint, block it
|
|
121
|
+
register('block-spa', () => {
|
|
122
|
+
blocked = true;
|
|
123
|
+
scheduler.stopTimer(true);
|
|
124
|
+
}, this.featureName, baseEE);
|
|
125
|
+
if (!isEnabled()) return;
|
|
126
|
+
state.initialPageLoad = new Interaction('initialPageLoad', 0, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentIdentifier);
|
|
127
|
+
state.initialPageLoad.save = true;
|
|
128
|
+
state.prevInteraction = state.initialPageLoad;
|
|
129
|
+
state.currentNode = state.initialPageLoad.root; // hint
|
|
130
|
+
// ensure that checkFinish calls are safe during initialPageLoad
|
|
131
|
+
state.initialPageLoad[REMAINING]++;
|
|
132
|
+
register(FN_START, callbackStart, this.featureName, baseEE);
|
|
133
|
+
register(CB_START, callbackStart, this.featureName, promiseEE);
|
|
134
|
+
|
|
135
|
+
// register plugins
|
|
136
|
+
var pluginApi = {
|
|
137
|
+
getCurrentNode: getCurrentNode,
|
|
138
|
+
setCurrentNode: setCurrentNode
|
|
139
|
+
};
|
|
140
|
+
register('spa-register', function (init) {
|
|
141
|
+
if (typeof init === 'function') {
|
|
142
|
+
init(pluginApi);
|
|
143
|
+
}
|
|
144
|
+
}, FEATURE_NAMES.spa, baseEE);
|
|
145
|
+
function callbackStart() {
|
|
146
|
+
state.depth++;
|
|
147
|
+
this.prevNode = state.currentNode;
|
|
148
|
+
this.ct = state.childTime;
|
|
149
|
+
state.childTime = 0;
|
|
150
|
+
state.timerBudget = MAX_TIMER_BUDGET;
|
|
151
|
+
}
|
|
152
|
+
register(FN_END, callbackEnd, this.featureName, baseEE);
|
|
153
|
+
register('cb-end', callbackEnd, this.featureName, promiseEE);
|
|
154
|
+
function callbackEnd() {
|
|
155
|
+
state.depth--;
|
|
156
|
+
var totalTime = this.jsTime || 0;
|
|
157
|
+
var exclusiveTime = totalTime - state.childTime;
|
|
158
|
+
state.childTime = this.ct + totalTime;
|
|
159
|
+
if (state.currentNode) {
|
|
160
|
+
// transfer accumulated callback time to the active interaction node
|
|
161
|
+
// run even if jsTime is 0 to update jsEnd
|
|
162
|
+
state.currentNode.callback(exclusiveTime, this[FN_END]);
|
|
163
|
+
if (this.isTraced) {
|
|
164
|
+
state.currentNode.attrs.tracedTime = exclusiveTime;
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
this.jsTime = state.currentNode ? 0 : exclusiveTime;
|
|
168
|
+
setCurrentNode(this.prevNode);
|
|
169
|
+
this.prevNode = null;
|
|
170
|
+
state.timerBudget = MAX_TIMER_BUDGET;
|
|
171
|
+
}
|
|
172
|
+
register(FN_START, function (args, eventSource) {
|
|
173
|
+
var ev = args[0];
|
|
174
|
+
var evName = ev.type;
|
|
175
|
+
var eventNode = ev.__nrNode;
|
|
176
|
+
if (!state.pageLoaded && evName === 'load' && eventSource === window) {
|
|
177
|
+
state.pageLoaded = true;
|
|
178
|
+
// set to null so prevNode is set correctly
|
|
179
|
+
this.prevNode = state.currentNode = null;
|
|
180
|
+
if (state.initialPageLoad) {
|
|
181
|
+
eventNode = state.initialPageLoad.root;
|
|
182
|
+
|
|
183
|
+
// Even if initialPageLoad has remaining callbacks, force the initialPageLoad
|
|
184
|
+
// interaction to complete when the page load event occurs.
|
|
185
|
+
state.initialPageLoad[REMAINING] = 0;
|
|
186
|
+
originalSetTimeout(function () {
|
|
187
|
+
INTERACTION_EVENTS.push('popstate');
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
if (eventNode) {
|
|
192
|
+
// If we've already seen a previous handler for this specific event object,
|
|
193
|
+
// just restore that. We want multiple handlers for the same event to share
|
|
194
|
+
// a node.
|
|
195
|
+
setCurrentNode(eventNode);
|
|
196
|
+
} else if (evName === 'hashchange') {
|
|
197
|
+
setCurrentNode(state.nodeOnLastHashUpdate);
|
|
198
|
+
state.nodeOnLastHashUpdate = null;
|
|
199
|
+
} else if (eventSource instanceof XMLHttpRequest) {
|
|
200
|
+
// If this event was emitted by an XHR, restore the node ID associated with
|
|
201
|
+
// that XHR.
|
|
202
|
+
setCurrentNode(baseEE.context(eventSource).spaNode);
|
|
203
|
+
} else if (!state.currentNode) {
|
|
204
|
+
// Otherwise, if no interaction is currently active, create a new node ID,
|
|
205
|
+
// and let the aggregator know that we entered a new event handler callback
|
|
206
|
+
// so that it has a chance to possibly start an interaction.
|
|
207
|
+
if (INTERACTION_EVENTS.indexOf(evName) !== -1) {
|
|
208
|
+
var ixn = new Interaction(evName, this[FN_START], state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentIdentifier);
|
|
209
|
+
|
|
210
|
+
// Store the interaction as prevInteraction in case it is prematurely discarded
|
|
211
|
+
state.prevInteraction = ixn;
|
|
212
|
+
setCurrentNode(ixn.root);
|
|
213
|
+
if (evName === 'click') {
|
|
214
|
+
var value = getActionText(ev.target);
|
|
215
|
+
if (value) {
|
|
216
|
+
state.currentNode.attrs.custom['actionText'] = value;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
ev.__nrNode = state.currentNode;
|
|
222
|
+
}, this.featureName, eventsEE);
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* *** TIMERS ***
|
|
226
|
+
* setTimeout call needs to keep the interaction active in case a node is started
|
|
227
|
+
* in its callback.
|
|
228
|
+
*/
|
|
229
|
+
|
|
230
|
+
// The context supplied to this callback will be shared with the fn-start/fn-end
|
|
231
|
+
// callbacks that fire around the callback passed to setTimeout originally.
|
|
232
|
+
register('setTimeout-end', function saveId(args, obj, timerId) {
|
|
233
|
+
if (!state.currentNode || state.timerBudget - this.timerDuration < 0) return;
|
|
234
|
+
if (args && !(args[0] instanceof Function)) return;
|
|
235
|
+
state.currentNode[INTERACTION][REMAINING]++;
|
|
236
|
+
this.timerId = timerId;
|
|
237
|
+
state.timerMap[timerId] = state.currentNode;
|
|
238
|
+
this.timerBudget = state.timerBudget - 50;
|
|
239
|
+
}, this.featureName, timerEE);
|
|
240
|
+
register('clearTimeout-start', function clear(args) {
|
|
241
|
+
var timerId = args[0];
|
|
242
|
+
var node = state.timerMap[timerId];
|
|
243
|
+
if (node) {
|
|
244
|
+
var interaction = node[INTERACTION];
|
|
245
|
+
interaction[REMAINING]--;
|
|
246
|
+
interaction.checkFinish();
|
|
247
|
+
delete state.timerMap[timerId];
|
|
248
|
+
}
|
|
249
|
+
}, this.featureName, timerEE);
|
|
250
|
+
register(FN_START, function () {
|
|
251
|
+
state.timerBudget = this.timerBudget || MAX_TIMER_BUDGET;
|
|
252
|
+
var id = this.timerId;
|
|
253
|
+
var node = state.timerMap[id];
|
|
254
|
+
setCurrentNode(node);
|
|
255
|
+
delete state.timerMap[id];
|
|
256
|
+
if (node) node[INTERACTION][REMAINING]--;
|
|
257
|
+
}, this.featureName, timerEE);
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* *** XHR ***
|
|
261
|
+
* - `new-xhr` event is fired when new instance of XHR is created. Here we create
|
|
262
|
+
* a new node and store it on the XHR object.
|
|
263
|
+
* - When the send method is called (`send-xhr-start` event), we tell the interaction
|
|
264
|
+
* to wait for this XHR to complete.
|
|
265
|
+
* - When any direct event handlers are invoked (`fn-start` on the `xhr` emitter),
|
|
266
|
+
* we restore the node in case other child nodes are started here.
|
|
267
|
+
* - Callbacks attached using `addEventListener` are handled using `fn-start` on the
|
|
268
|
+
* `events` emitter.
|
|
269
|
+
* - When `xhr-resolved` is emitted, we end the node. The node.finish() call also
|
|
270
|
+
* instructs the interaction to stop waiting for this node.
|
|
271
|
+
*/
|
|
272
|
+
|
|
273
|
+
// context is shared with new-xhr event, and is stored on the xhr iteself.
|
|
274
|
+
register(FN_START, function () {
|
|
275
|
+
setCurrentNode(this[SPA_NODE]);
|
|
276
|
+
}, this.featureName, xhrEE);
|
|
277
|
+
|
|
278
|
+
// context is stored on the xhr and is shared with all callbacks associated
|
|
279
|
+
// with the new xhr
|
|
280
|
+
register('new-xhr', function () {
|
|
281
|
+
if (!state.currentNode && state.prevInteraction && !state.prevInteraction.ignored) {
|
|
282
|
+
/*
|
|
283
|
+
* The previous interaction was discarded before a route change. Restore the interaction
|
|
284
|
+
* in case this XHR is associated with a route change.
|
|
285
|
+
*/
|
|
286
|
+
const interaction = state.prevInteraction;
|
|
287
|
+
state.currentNode = interaction.root;
|
|
288
|
+
interaction.root.end = null;
|
|
289
|
+
}
|
|
290
|
+
if (state.currentNode) {
|
|
291
|
+
this[SPA_NODE] = state.currentNode.child('ajax', null, null, true);
|
|
292
|
+
}
|
|
293
|
+
}, this.featureName, xhrEE);
|
|
294
|
+
register('send-xhr-start', function () {
|
|
295
|
+
var node = this[SPA_NODE];
|
|
296
|
+
if (node && !this.sent) {
|
|
297
|
+
this.sent = true;
|
|
298
|
+
node.dt = this.dt;
|
|
299
|
+
node.jsEnd = node.start = this.startTime;
|
|
300
|
+
node[INTERACTION][REMAINING]++;
|
|
301
|
+
}
|
|
302
|
+
}, this.featureName, xhrEE);
|
|
303
|
+
register('xhr-resolved', function () {
|
|
304
|
+
var node = this[SPA_NODE];
|
|
305
|
+
if (node) {
|
|
306
|
+
if (!shouldCollectEvent(this.params)) {
|
|
307
|
+
node.cancel();
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
var attrs = node.attrs;
|
|
311
|
+
attrs.params = this.params;
|
|
312
|
+
attrs.metrics = this.metrics;
|
|
313
|
+
node.finish(this.endTime);
|
|
314
|
+
if (!!this.currentNode && !!this.currentNode.interaction) this.currentNode.interaction.checkFinish();
|
|
315
|
+
}
|
|
316
|
+
}, this.featureName, baseEE);
|
|
317
|
+
|
|
318
|
+
/**
|
|
319
|
+
* *** JSONP ***
|
|
320
|
+
*
|
|
321
|
+
*/
|
|
322
|
+
|
|
323
|
+
register('new-jsonp', function (url) {
|
|
324
|
+
if (state.currentNode) {
|
|
325
|
+
var node = this[JSONP_NODE] = state.currentNode.child('ajax', this[FETCH_START]);
|
|
326
|
+
node.start = this['new-jsonp'];
|
|
327
|
+
this.url = url;
|
|
328
|
+
this.status = null;
|
|
329
|
+
}
|
|
330
|
+
}, this.featureName, jsonpEE);
|
|
331
|
+
register('cb-start', function (args) {
|
|
332
|
+
var node = this[JSONP_NODE];
|
|
333
|
+
if (node) {
|
|
334
|
+
setCurrentNode(node);
|
|
335
|
+
this.status = 200;
|
|
336
|
+
}
|
|
337
|
+
}, this.featureName, jsonpEE);
|
|
338
|
+
register('jsonp-error', function () {
|
|
339
|
+
var node = this[JSONP_NODE];
|
|
340
|
+
if (node) {
|
|
341
|
+
setCurrentNode(node);
|
|
342
|
+
this.status = 0;
|
|
343
|
+
}
|
|
344
|
+
}, this.featureName, jsonpEE);
|
|
345
|
+
register(JSONP_END, function () {
|
|
346
|
+
var node = this[JSONP_NODE];
|
|
347
|
+
if (node) {
|
|
348
|
+
// if no status is set then cb never fired - so it's not a valid JSONP
|
|
349
|
+
if (this.status === null) {
|
|
350
|
+
node.cancel();
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
var attrs = node.attrs;
|
|
354
|
+
var params = attrs.params = {};
|
|
355
|
+
var parsed = parseUrl(this.url);
|
|
356
|
+
params.method = 'GET';
|
|
357
|
+
params.pathname = parsed.pathname;
|
|
358
|
+
params.host = parsed.hostname + ':' + parsed.port;
|
|
359
|
+
params.status = this.status;
|
|
360
|
+
attrs.metrics = {
|
|
361
|
+
txSize: 0,
|
|
362
|
+
rxSize: 0
|
|
363
|
+
};
|
|
364
|
+
attrs.isJSONP = true;
|
|
365
|
+
node.jsEnd = this[JSONP_END];
|
|
366
|
+
node.jsTime = this[CB_START] ? this[JSONP_END] - this[CB_START] : 0;
|
|
367
|
+
node.finish(node.jsEnd);
|
|
368
|
+
}
|
|
369
|
+
}, this.featureName, jsonpEE);
|
|
370
|
+
register(FETCH_START, function (fetchArguments, dtPayload) {
|
|
371
|
+
if (fetchArguments) {
|
|
372
|
+
if (!state.currentNode && state.prevInteraction && !state.prevInteraction.ignored) {
|
|
373
|
+
/*
|
|
374
|
+
* The previous interaction was discarded before a route change. Restore the interaction
|
|
375
|
+
* in case this XHR is associated with a route change.
|
|
376
|
+
*/
|
|
377
|
+
const interaction = state.prevInteraction;
|
|
378
|
+
state.currentNode = interaction.root;
|
|
379
|
+
interaction.root.end = null;
|
|
380
|
+
}
|
|
381
|
+
if (state.currentNode) {
|
|
382
|
+
this[SPA_NODE] = state.currentNode.child('ajax', this[FETCH_START]);
|
|
383
|
+
if (dtPayload && this[SPA_NODE]) this[SPA_NODE].dt = dtPayload;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
}, this.featureName, fetchEE);
|
|
387
|
+
register(FETCH_BODY + 'start', function (args) {
|
|
388
|
+
if (state.currentNode) {
|
|
389
|
+
this[SPA_NODE] = state.currentNode;
|
|
390
|
+
state.currentNode[INTERACTION][REMAINING]++;
|
|
391
|
+
}
|
|
392
|
+
}, this.featureName, fetchEE);
|
|
393
|
+
register(FETCH_BODY + 'end', function (args, ctx, bodyPromise) {
|
|
394
|
+
var node = this[SPA_NODE];
|
|
395
|
+
if (node) node[INTERACTION][REMAINING]--;
|
|
396
|
+
}, this.featureName, fetchEE);
|
|
397
|
+
register(FETCH_DONE, function (err, res) {
|
|
398
|
+
var node = this[SPA_NODE];
|
|
399
|
+
if (node) {
|
|
400
|
+
if (err) {
|
|
401
|
+
node.cancel();
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
var attrs = node.attrs;
|
|
405
|
+
attrs.params = this.params;
|
|
406
|
+
attrs.metrics = {
|
|
407
|
+
txSize: this.txSize,
|
|
408
|
+
rxSize: this.rxSize
|
|
409
|
+
};
|
|
410
|
+
attrs.isFetch = true;
|
|
411
|
+
node.finish(this[FETCH_DONE]);
|
|
412
|
+
}
|
|
413
|
+
}, this.featureName, fetchEE);
|
|
414
|
+
register('newURL', function (url, hashChangedDuringCb) {
|
|
415
|
+
if (state.currentNode) {
|
|
416
|
+
state.currentNode[INTERACTION].setNewURL(url);
|
|
417
|
+
} else if (state.prevInteraction && !state.prevInteraction.ignored) {
|
|
418
|
+
/*
|
|
419
|
+
* The previous interaction was discarded before the route was changed. This can happen in SPA
|
|
420
|
+
* frameworks when using lazy loading. We have also seen this in version 11+ of Nextjs where
|
|
421
|
+
* some route changes re-use cached resolved promises.
|
|
422
|
+
*/
|
|
423
|
+
const interaction = state.prevInteraction;
|
|
424
|
+
interaction.setNewURL(url);
|
|
425
|
+
interaction.root.end = null;
|
|
426
|
+
setCurrentNode(interaction.root);
|
|
427
|
+
}
|
|
428
|
+
if (state.currentNode) {
|
|
429
|
+
if (state.lastSeenUrl !== url) {
|
|
430
|
+
state.currentNode[INTERACTION].routeChange = true;
|
|
431
|
+
}
|
|
432
|
+
if (hashChangedDuringCb) {
|
|
433
|
+
state.nodeOnLastHashUpdate = state.currentNode;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
state.lastSeenUrl = url;
|
|
437
|
+
}, this.featureName, historyEE);
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* SCRIPTS
|
|
441
|
+
* This is only needed to keep the interaction open while external scripts are being loaded.
|
|
442
|
+
* The script that is loaded could continue the interaction by making additional AJAX
|
|
443
|
+
* calls or changing the URL. The interaction context (currentNode) needs to be
|
|
444
|
+
* restored somehow, but this differs based on the specific customer code. In some cases, we
|
|
445
|
+
* could wrap a JSONP callback, in other cases we could wrap a higher-level API, and in
|
|
446
|
+
* some cases we may not be able to restore context automatically (customer would need
|
|
447
|
+
* to instrument their code manually).
|
|
448
|
+
*
|
|
449
|
+
* - We do not restore the original context in the load/error callbacks. This would not
|
|
450
|
+
* work for the scripts themselves because by the time the load event fires, the
|
|
451
|
+
* script content has already been executed.
|
|
452
|
+
*/
|
|
453
|
+
|
|
454
|
+
// dom-start is emitted when appendChild or replaceChild are called. If the element being
|
|
455
|
+
// inserted is script and we are inside an interaction, we will keep the interaction open
|
|
456
|
+
// until the script is loaded.
|
|
457
|
+
jsonpEE.on('dom-start', function (args) {
|
|
458
|
+
if (!state.currentNode) return;
|
|
459
|
+
var el = args[0];
|
|
460
|
+
var isScript = el && el.nodeName === 'SCRIPT' && el.src !== '';
|
|
461
|
+
var interaction = state.currentNode.interaction;
|
|
462
|
+
if (isScript) {
|
|
463
|
+
// increase remaining count to keep the interaction open
|
|
464
|
+
interaction[REMAINING]++;
|
|
465
|
+
el.addEventListener('load', onload, eventListenerOpts(false));
|
|
466
|
+
el.addEventListener('error', onerror, eventListenerOpts(false));
|
|
467
|
+
}
|
|
468
|
+
function onload() {
|
|
469
|
+
// decrease remaining to allow interaction to finish
|
|
470
|
+
interaction[REMAINING]--;
|
|
471
|
+
|
|
472
|
+
// checkFinish is what initiates closing interaction, but is only called
|
|
473
|
+
// when setCurrentNode is called. Since we are not restoring a node here,
|
|
474
|
+
// we need to initiate the check manually.
|
|
475
|
+
// The reason we are not restoring the node here is because 1) this is not
|
|
476
|
+
// where the code of the external script runs (by the time the load event
|
|
477
|
+
// fires, it has already executed), and 2) it would require storing the context
|
|
478
|
+
// probably on the DOM node and restoring in all callbacks, which is a different
|
|
479
|
+
// use case than lazy loading.
|
|
480
|
+
interaction.checkFinish();
|
|
481
|
+
}
|
|
482
|
+
function onerror() {
|
|
483
|
+
interaction[REMAINING]--;
|
|
484
|
+
interaction.checkFinish();
|
|
485
|
+
}
|
|
486
|
+
});
|
|
487
|
+
register(FN_START, function () {
|
|
488
|
+
setCurrentNode(state.prevNode);
|
|
489
|
+
}, this.featureName, mutationEE);
|
|
490
|
+
register('resolve-start', resolvePromise, this.featureName, promiseEE);
|
|
491
|
+
register('executor-err', resolvePromise, this.featureName, promiseEE);
|
|
492
|
+
register('propagate', saveNode, this.featureName, promiseEE);
|
|
493
|
+
register(CB_START, function () {
|
|
494
|
+
var ctx = this.getCtx ? this.getCtx() : this;
|
|
495
|
+
setCurrentNode(ctx[SPA_NODE]);
|
|
496
|
+
}, this.featureName, promiseEE);
|
|
497
|
+
register(INTERACTION_API + 'get', function (t) {
|
|
498
|
+
var interaction;
|
|
499
|
+
if (state?.currentNode?.[INTERACTION]) interaction = this.ixn = state.currentNode[INTERACTION];else if (state?.prevNode?.end === null && state?.prevNode?.[INTERACTION]?.root?.[INTERACTION]?.eventName != 'initialPageLoad') interaction = this.ixn = state.prevNode[INTERACTION];else interaction = this.ixn = new Interaction('api', t, state.lastSeenUrl, state.lastSeenRouteName, onInteractionFinished, agentIdentifier);
|
|
500
|
+
if (!state.currentNode) {
|
|
501
|
+
interaction.checkFinish();
|
|
502
|
+
if (state.depth) setCurrentNode(interaction.root);
|
|
503
|
+
}
|
|
504
|
+
}, this.featureName, baseEE);
|
|
505
|
+
register(INTERACTION_API + 'actionText', function (t, actionText) {
|
|
506
|
+
var customAttrs = this.ixn.root.attrs.custom;
|
|
507
|
+
if (actionText) customAttrs.actionText = actionText;
|
|
508
|
+
}, this.featureName, baseEE);
|
|
509
|
+
register(INTERACTION_API + 'setName', function (t, name, trigger) {
|
|
510
|
+
var attrs = this.ixn.root.attrs;
|
|
511
|
+
if (name) attrs.customName = name;
|
|
512
|
+
if (trigger) attrs.trigger = trigger;
|
|
513
|
+
}, this.featureName, baseEE);
|
|
514
|
+
register(INTERACTION_API + 'setAttribute', function (t, name, value) {
|
|
515
|
+
this.ixn.root.attrs.custom[name] = value;
|
|
516
|
+
}, this.featureName, baseEE);
|
|
517
|
+
register(INTERACTION_API + 'end', function (timestamp) {
|
|
518
|
+
var interaction = this.ixn;
|
|
519
|
+
var node = activeNodeFor(interaction);
|
|
520
|
+
setCurrentNode(null);
|
|
521
|
+
node.child('customEnd', timestamp).finish(timestamp);
|
|
522
|
+
interaction.finish();
|
|
523
|
+
}, this.featureName, baseEE);
|
|
524
|
+
register(INTERACTION_API + 'ignore', function (t) {
|
|
525
|
+
this.ixn.ignored = true;
|
|
526
|
+
}, this.featureName, baseEE);
|
|
527
|
+
register(INTERACTION_API + 'save', function (t) {
|
|
528
|
+
this.ixn.save = true;
|
|
529
|
+
}, this.featureName, baseEE);
|
|
530
|
+
register(INTERACTION_API + 'tracer', function (timestamp, name, store) {
|
|
531
|
+
var interaction = this.ixn;
|
|
532
|
+
var parent = activeNodeFor(interaction);
|
|
533
|
+
var ctx = baseEE.context(store);
|
|
534
|
+
if (!name) {
|
|
535
|
+
ctx.inc = ++interaction[REMAINING];
|
|
536
|
+
return ctx[SPA_NODE] = parent;
|
|
537
|
+
}
|
|
538
|
+
ctx[SPA_NODE] = parent.child('customTracer', timestamp, name);
|
|
539
|
+
}, this.featureName, baseEE);
|
|
540
|
+
register(FN_START, tracerDone, this.featureName, tracerEE);
|
|
541
|
+
register('no-' + FN_START, tracerDone, this.featureName, tracerEE);
|
|
542
|
+
function tracerDone(timestamp, interactionContext, hasCb) {
|
|
543
|
+
var node = this[SPA_NODE];
|
|
544
|
+
if (!node) return;
|
|
545
|
+
var interaction = node[INTERACTION];
|
|
546
|
+
var inc = this.inc;
|
|
547
|
+
this.isTraced = true;
|
|
548
|
+
if (inc) {
|
|
549
|
+
interaction[REMAINING]--;
|
|
550
|
+
} else if (node) {
|
|
551
|
+
node.finish(timestamp);
|
|
552
|
+
}
|
|
553
|
+
hasCb ? setCurrentNode(node) : interaction.checkFinish();
|
|
554
|
+
}
|
|
555
|
+
register(INTERACTION_API + 'getContext', function (t, cb) {
|
|
556
|
+
var store = this.ixn.root.attrs.store;
|
|
557
|
+
setTimeout(function () {
|
|
558
|
+
cb(store);
|
|
559
|
+
}, 0);
|
|
560
|
+
}, this.featureName, baseEE);
|
|
561
|
+
register(INTERACTION_API + 'onEnd', function (t, cb) {
|
|
562
|
+
this.ixn.handlers.push(cb);
|
|
563
|
+
}, this.featureName, baseEE);
|
|
564
|
+
register('api-routeName', function (t, currentRouteName) {
|
|
565
|
+
state.lastSeenRouteName = currentRouteName;
|
|
566
|
+
if (state.currentNode) state.currentNode[INTERACTION].setNewRoute(currentRouteName);
|
|
567
|
+
}, this.featureName, baseEE);
|
|
568
|
+
function activeNodeFor(interaction) {
|
|
569
|
+
return state.currentNode && state.currentNode[INTERACTION] === interaction ? state.currentNode : interaction.root;
|
|
570
|
+
}
|
|
571
|
+
function saveNode(val, overwrite) {
|
|
572
|
+
if (overwrite || !this[SPA_NODE]) this[SPA_NODE] = state.currentNode;
|
|
573
|
+
}
|
|
574
|
+
function resolvePromise() {
|
|
575
|
+
if (!this.resolved) {
|
|
576
|
+
this.resolved = true;
|
|
577
|
+
this[SPA_NODE] = state.currentNode;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
function getCurrentNode() {
|
|
581
|
+
return state.currentNode;
|
|
582
|
+
}
|
|
583
|
+
function setCurrentNode(newNode) {
|
|
584
|
+
if (!state.pageLoaded && !newNode && state.initialPageLoad) newNode = state.initialPageLoad.root;
|
|
585
|
+
if (state.currentNode) {
|
|
586
|
+
state.currentNode[INTERACTION].checkFinish();
|
|
587
|
+
}
|
|
588
|
+
state.prevNode = state.currentNode;
|
|
589
|
+
state.currentNode = newNode && !newNode[INTERACTION].root.end ? newNode : null;
|
|
590
|
+
}
|
|
591
|
+
function onInteractionFinished(interaction) {
|
|
592
|
+
if (interaction === state.initialPageLoad) state.initialPageLoad = null;
|
|
593
|
+
var root = interaction.root;
|
|
594
|
+
var attrs = root.attrs;
|
|
595
|
+
|
|
596
|
+
// make sure that newrelic[INTERACTION]() works in end handler
|
|
597
|
+
state.currentNode = root;
|
|
598
|
+
mapOwn(interaction.handlers, function (i, cb) {
|
|
599
|
+
cb(attrs.store);
|
|
600
|
+
});
|
|
601
|
+
setCurrentNode(null);
|
|
602
|
+
}
|
|
603
|
+
function onHarvestStarted(options) {
|
|
604
|
+
if (state.interactionsToHarvest.length === 0 || blocked) return {};
|
|
605
|
+
var payload = serializer.serializeMultiple(state.interactionsToHarvest, 0, navTiming);
|
|
606
|
+
if (options.retry) {
|
|
607
|
+
state.interactionsToHarvest.forEach(function (interaction) {
|
|
608
|
+
state.interactionsSent.push(interaction);
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
state.interactionsToHarvest = [];
|
|
612
|
+
return {
|
|
613
|
+
body: {
|
|
614
|
+
e: payload
|
|
615
|
+
}
|
|
616
|
+
};
|
|
617
|
+
}
|
|
618
|
+
function onHarvestFinished(result) {
|
|
619
|
+
if (result.sent && result.retry && state.interactionsSent.length > 0) {
|
|
620
|
+
state.interactionsSent.forEach(function (interaction) {
|
|
621
|
+
state.interactionsToHarvest.push(interaction);
|
|
622
|
+
});
|
|
623
|
+
state.interactionsSent = [];
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
baseEE.on('errorAgg', function (type, name, params, metrics) {
|
|
627
|
+
if (!state.currentNode) return;
|
|
628
|
+
params._interactionId = state.currentNode.interaction.id;
|
|
629
|
+
// do not capture parentNodeId when in root node
|
|
630
|
+
if (state.currentNode.type && state.currentNode.type !== 'interaction') {
|
|
631
|
+
params._interactionNodeId = state.currentNode.id;
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
baseEE.on('interaction', saveInteraction);
|
|
635
|
+
function getActionText(node) {
|
|
636
|
+
var nodeType = node.tagName.toLowerCase();
|
|
637
|
+
var goodNodeTypes = ['a', 'button', 'input'];
|
|
638
|
+
var isGoodNode = goodNodeTypes.indexOf(nodeType) !== -1;
|
|
639
|
+
if (isGoodNode) {
|
|
640
|
+
return node.title || node.value || node.innerText;
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
function saveInteraction(interaction) {
|
|
644
|
+
if (interaction.ignored || !interaction.save && !interaction.routeChange) {
|
|
645
|
+
baseEE.emit('interactionDiscarded', [interaction]);
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
if (state.prevInteraction === interaction) {
|
|
649
|
+
// If the interaction is being saved, remove it from prevInteraction variable
|
|
650
|
+
// to prevent the interaction from possibly being sent twice or causing an internal
|
|
651
|
+
// recursive loop issue.
|
|
652
|
+
state.prevInteraction = null;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// assign unique id, this is serialized and used to link interactions with errors
|
|
656
|
+
interaction.root.attrs.id = generateUuid();
|
|
657
|
+
if (interaction.root.attrs.trigger === 'initialPageLoad') {
|
|
658
|
+
interaction.root.attrs.firstPaint = paintMetrics['first-paint'];
|
|
659
|
+
interaction.root.attrs.firstContentfulPaint = paintMetrics['first-contentful-paint'];
|
|
660
|
+
}
|
|
661
|
+
baseEE.emit('interactionSaved', [interaction]);
|
|
662
|
+
state.interactionsToHarvest.push(interaction);
|
|
663
|
+
scheduler.scheduleHarvest(0);
|
|
664
|
+
}
|
|
665
|
+
function isEnabled() {
|
|
666
|
+
var enabled = getConfigurationValue(agentIdentifier, 'spa.enabled');
|
|
667
|
+
if (enabled === false) {
|
|
668
|
+
return false;
|
|
669
|
+
}
|
|
670
|
+
return true;
|
|
671
|
+
}
|
|
672
|
+
drain(this.agentIdentifier, this.featureName);
|
|
673
|
+
}
|
|
674
|
+
}
|