@newrelic/browser-agent 1.244.0 → 1.245.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 +9 -0
- package/dist/cjs/cdn/polyfills.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/url/parse-url.js +9 -8
- package/dist/cjs/common/util/type-check.js +14 -0
- package/dist/cjs/features/ajax/aggregate/gql.js +94 -0
- package/dist/cjs/features/ajax/aggregate/index.js +12 -1
- package/dist/cjs/features/ajax/instrument/index.js +2 -0
- package/dist/cjs/features/spa/aggregate/serializer.js +7 -0
- package/dist/cjs/index.js +0 -7
- package/dist/cjs/loaders/api/api.js +2 -2
- package/dist/esm/cdn/polyfills.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/url/parse-url.js +9 -8
- package/dist/esm/common/util/type-check.js +8 -0
- package/dist/esm/features/ajax/aggregate/gql.js +89 -0
- package/dist/esm/features/ajax/aggregate/index.js +12 -1
- package/dist/esm/features/ajax/instrument/index.js +2 -0
- package/dist/esm/features/spa/aggregate/serializer.js +7 -0
- package/dist/esm/index.js +0 -1
- package/dist/esm/loaders/api/api.js +2 -2
- package/dist/types/common/url/parse-url.d.ts.map +1 -1
- package/dist/types/common/util/type-check.d.ts +7 -0
- package/dist/types/common/util/type-check.d.ts.map +1 -0
- package/dist/types/features/ajax/aggregate/gql.d.ts +29 -0
- package/dist/types/features/ajax/aggregate/gql.d.ts.map +1 -0
- package/dist/types/features/ajax/aggregate/index.d.ts.map +1 -1
- package/dist/types/features/spa/aggregate/serializer.d.ts.map +1 -1
- package/dist/types/index.d.ts +0 -1
- package/package.json +1 -9
- package/src/cdn/polyfills.js +3 -0
- package/src/common/url/parse-url.js +9 -7
- package/src/common/util/type-check.js +8 -0
- package/src/features/ajax/aggregate/gql.js +95 -0
- package/src/features/ajax/aggregate/index.js +9 -1
- package/src/features/ajax/instrument/index.js +3 -0
- package/src/features/spa/aggregate/serializer.js +7 -1
- package/src/index.js +0 -1
- package/src/loaders/api/api.js +2 -2
- package/dist/cjs/cdn/worker.js +0 -16
- package/dist/cjs/loaders/worker-agent.js +0 -24
- package/dist/esm/cdn/worker.js +0 -14
- package/dist/esm/loaders/worker-agent.js +0 -18
- package/dist/types/cdn/worker.d.ts +0 -2
- package/dist/types/cdn/worker.d.ts.map +0 -1
- package/dist/types/loaders/worker-agent.d.ts +0 -8
- package/dist/types/loaders/worker-agent.d.ts.map +0 -1
- package/src/cdn/worker.js +0 -21
- package/src/loaders/worker-agent.js +0 -24
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,15 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [1.245.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.244.0...v1.245.0) (2023-10-18)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* Allow boolean values in setCustomAttribute ([#776](https://github.com/newrelic/newrelic-browser-agent/issues/776)) ([d44f033](https://github.com/newrelic/newrelic-browser-agent/commit/d44f03384655f47c5f8a63db02f7eaac58585a86))
|
|
12
|
+
* Detect GraphQL operation names and types in AJAX calls ([#764](https://github.com/newrelic/newrelic-browser-agent/issues/764)) ([8587afc](https://github.com/newrelic/newrelic-browser-agent/commit/8587afc9dbc18a52048f467c77e5ededc225eb2a))
|
|
13
|
+
* Removing worker build ([#762](https://github.com/newrelic/newrelic-browser-agent/issues/762)) ([15f801b](https://github.com/newrelic/newrelic-browser-agent/commit/15f801b1a48c6e60f8f50f349aa382c77a073480))
|
|
14
|
+
|
|
6
15
|
## [1.244.0](https://github.com/newrelic/newrelic-browser-agent/compare/v1.243.1...v1.244.0) (2023-10-10)
|
|
7
16
|
|
|
8
17
|
|
|
@@ -10,8 +10,11 @@ require("core-js/stable/array/some");
|
|
|
10
10
|
require("core-js/stable/object/assign");
|
|
11
11
|
require("core-js/stable/object/entries");
|
|
12
12
|
require("core-js/stable/object/values");
|
|
13
|
+
require("core-js/stable/object/from-entries");
|
|
13
14
|
require("core-js/stable/map");
|
|
14
15
|
require("core-js/stable/reflect");
|
|
15
16
|
require("core-js/stable/set");
|
|
16
17
|
require("core-js/stable/weak-set");
|
|
17
|
-
require("core-js/stable/object/get-own-property-descriptors");
|
|
18
|
+
require("core-js/stable/object/get-own-property-descriptors");
|
|
19
|
+
require("core-js/stable/url");
|
|
20
|
+
require("core-js/stable/url-search-params");
|
|
@@ -25,18 +25,19 @@ function parseUrl(url) {
|
|
|
25
25
|
let urlEl;
|
|
26
26
|
var location = _runtime.globalScope?.location;
|
|
27
27
|
var ret = {};
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
urlEl =
|
|
35
|
-
}
|
|
28
|
+
try {
|
|
29
|
+
urlEl = new URL(url, location.href);
|
|
30
|
+
} catch (err) {
|
|
31
|
+
if (_runtime.isBrowserScope) {
|
|
32
|
+
// Use an anchor dom element to resolve the url natively.
|
|
33
|
+
urlEl = document.createElement('a');
|
|
34
|
+
urlEl.href = url;
|
|
35
|
+
} else {
|
|
36
36
|
return ret;
|
|
37
37
|
}
|
|
38
38
|
}
|
|
39
39
|
ret.port = urlEl.port;
|
|
40
|
+
ret.search = urlEl.search;
|
|
40
41
|
var firstSplit = urlEl.href.split('://');
|
|
41
42
|
if (!ret.port && firstSplit[1]) {
|
|
42
43
|
ret.port = firstSplit[1].split('/')[0].split('@').pop().split(':')[1];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isPureObject = isPureObject;
|
|
7
|
+
/**
|
|
8
|
+
* Tests a passed object to see if it is a pure object or not. All non-primatives in JS
|
|
9
|
+
* are technically objects and would pass a `typeof` check.
|
|
10
|
+
* @param {*} obj Input object to be tested
|
|
11
|
+
**/
|
|
12
|
+
function isPureObject(obj) {
|
|
13
|
+
return obj?.constructor === {}.constructor;
|
|
14
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.parseGQL = parseGQL;
|
|
7
|
+
var _typeCheck = require("../../../common/util/type-check");
|
|
8
|
+
/**
|
|
9
|
+
* @typedef {object} GQLMetadata
|
|
10
|
+
* @property {string} operationName Name of the operation
|
|
11
|
+
* @property {string} operationType Type of the operation
|
|
12
|
+
* @property {string} operationFramework Framework responsible for the operation
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parses and returns the graphql metadata from a network request. If the network
|
|
17
|
+
* request is not a graphql call, undefined will be returned.
|
|
18
|
+
* @param {object|string} body Ajax request body
|
|
19
|
+
* @param {string} query Ajax request query param string
|
|
20
|
+
* @returns {GQLMetadata | undefined}
|
|
21
|
+
*/
|
|
22
|
+
function parseGQL() {
|
|
23
|
+
let {
|
|
24
|
+
body,
|
|
25
|
+
query
|
|
26
|
+
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
27
|
+
if (!body && !query) return;
|
|
28
|
+
try {
|
|
29
|
+
const gqlBody = parseBatchGQL(parseGQLContents(body));
|
|
30
|
+
if (gqlBody) return gqlBody;
|
|
31
|
+
const gqlQuery = parseSingleGQL(parseGQLQueryString(query));
|
|
32
|
+
if (gqlQuery) return gqlQuery;
|
|
33
|
+
} catch (err) {
|
|
34
|
+
// parsing failed, return undefined
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* @param {string|Object} gql The GraphQL object body sent to a GQL server
|
|
40
|
+
* @returns {GQLMetadata}
|
|
41
|
+
*/
|
|
42
|
+
function parseSingleGQL(contents) {
|
|
43
|
+
if (typeof contents !== 'object' || !contents.query || typeof contents.query !== 'string') return;
|
|
44
|
+
|
|
45
|
+
/** parses gql query string and returns [fullmatch, type match, name match] */
|
|
46
|
+
const matches = contents.query.trim().match(/^(query|mutation|subscription)\s?(\w*)/);
|
|
47
|
+
const operationType = matches?.[1];
|
|
48
|
+
if (!operationType) return;
|
|
49
|
+
const operationName = contents.operationName || matches?.[2] || 'Anonymous';
|
|
50
|
+
return {
|
|
51
|
+
operationName,
|
|
52
|
+
// the operation name of the indiv query
|
|
53
|
+
operationType,
|
|
54
|
+
// query, mutation, or subscription,
|
|
55
|
+
operationFramework: 'GraphQL'
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function parseBatchGQL(contents) {
|
|
59
|
+
if (!contents) return;
|
|
60
|
+
if (!Array.isArray(contents)) contents = [contents];
|
|
61
|
+
const opNames = [];
|
|
62
|
+
const opTypes = [];
|
|
63
|
+
for (let content of contents) {
|
|
64
|
+
const operation = parseSingleGQL(content);
|
|
65
|
+
if (!operation) continue;
|
|
66
|
+
opNames.push(operation.operationName);
|
|
67
|
+
opTypes.push(operation.operationType);
|
|
68
|
+
}
|
|
69
|
+
if (!opTypes.length) return;
|
|
70
|
+
return {
|
|
71
|
+
operationName: opNames.join(','),
|
|
72
|
+
// the operation name of the indiv query -- joined by ',' for batched results
|
|
73
|
+
operationType: opTypes.join(','),
|
|
74
|
+
// query, mutation, or subscription -- joined by ',' for batched results
|
|
75
|
+
operationFramework: 'GraphQL'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function parseGQLContents(gqlContents) {
|
|
79
|
+
let contents;
|
|
80
|
+
if (!gqlContents || typeof gqlContents !== 'string' && typeof gqlContents !== 'object') return;else if (typeof gqlContents === 'string') contents = JSON.parse(gqlContents);else contents = gqlContents;
|
|
81
|
+
if (!(0, _typeCheck.isPureObject)(contents) && !Array.isArray(contents)) return;
|
|
82
|
+
let isValid = false;
|
|
83
|
+
if (Array.isArray(contents)) isValid = contents.some(x => validateGQLObject(x));else isValid = validateGQLObject(contents);
|
|
84
|
+
if (!isValid) return;
|
|
85
|
+
return contents;
|
|
86
|
+
}
|
|
87
|
+
function parseGQLQueryString(gqlQueryString) {
|
|
88
|
+
if (!gqlQueryString || typeof gqlQueryString !== 'string') return;
|
|
89
|
+
const params = new URLSearchParams(gqlQueryString);
|
|
90
|
+
return parseGQLContents(Object.fromEntries(params));
|
|
91
|
+
}
|
|
92
|
+
function validateGQLObject(obj) {
|
|
93
|
+
return !(typeof obj !== 'object' || !obj.query || typeof obj.query !== 'string');
|
|
94
|
+
}
|
|
@@ -15,6 +15,7 @@ var _constants = require("../constants");
|
|
|
15
15
|
var _features = require("../../../loaders/features/features");
|
|
16
16
|
var _constants2 = require("../../metrics/constants");
|
|
17
17
|
var _aggregateBase = require("../../utils/aggregate-base");
|
|
18
|
+
var _gql = require("./gql");
|
|
18
19
|
/*
|
|
19
20
|
* Copyright 2020 New Relic Corporation. All rights reserved.
|
|
20
21
|
* SPDX-License-Identifier: Apache-2.0
|
|
@@ -116,6 +117,12 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
116
117
|
event.spanTimestamp = xhrContext.dt.timestamp;
|
|
117
118
|
}
|
|
118
119
|
|
|
120
|
+
// parsed from the AJAX body, looking for operationName param & parsing query for operationType
|
|
121
|
+
event.gql = params.gql = (0, _gql.parseGQL)({
|
|
122
|
+
body: this.body,
|
|
123
|
+
query: this?.parsedOrigin?.search
|
|
124
|
+
});
|
|
125
|
+
|
|
119
126
|
// if the ajax happened inside an interaction, hold it until the interaction finishes
|
|
120
127
|
if (this.spaNode) {
|
|
121
128
|
var interactionId = this.spaNode.interaction.id;
|
|
@@ -205,7 +212,11 @@ class Aggregate extends _aggregateBase.AggregateBase {
|
|
|
205
212
|
var insert = '2,';
|
|
206
213
|
|
|
207
214
|
// add custom attributes
|
|
208
|
-
|
|
215
|
+
// gql decorators are added as custom attributes to alleviate need for new BEL schema
|
|
216
|
+
var attrParts = (0, _belSerializer.addCustomAttributes)({
|
|
217
|
+
...((0, _config.getInfo)(agentIdentifier).jsAttributes || {}),
|
|
218
|
+
...(event.gql || {})
|
|
219
|
+
}, this.addString);
|
|
209
220
|
fields.unshift((0, _belSerializer.numeric)(attrParts.length));
|
|
210
221
|
insert += fields.join(',');
|
|
211
222
|
if (attrParts && attrParts.length > 0) {
|
|
@@ -161,6 +161,7 @@ function subscribeToEvents(agentIdentifier, ee, handler, dt) {
|
|
|
161
161
|
if (size) metrics.txSize = size;
|
|
162
162
|
}
|
|
163
163
|
this.startTime = (0, _now.now)();
|
|
164
|
+
this.body = data;
|
|
164
165
|
this.listener = function (evt) {
|
|
165
166
|
try {
|
|
166
167
|
if (evt.type === 'abort' && !context.loadCaptureCalled) {
|
|
@@ -308,6 +309,7 @@ function subscribeToEvents(agentIdentifier, ee, handler, dt) {
|
|
|
308
309
|
addUrl(this, url);
|
|
309
310
|
var method = ('' + (target && target instanceof origRequest && target.method || opts.method || 'GET')).toUpperCase();
|
|
310
311
|
this.params.method = method;
|
|
312
|
+
this.body = opts.body;
|
|
311
313
|
this.txSize = (0, _dataSize.dataSize)(opts.body) || 0;
|
|
312
314
|
}
|
|
313
315
|
|
|
@@ -91,6 +91,13 @@ class Serializer extends _sharedContext.SharedContext {
|
|
|
91
91
|
break;
|
|
92
92
|
case 2:
|
|
93
93
|
fields.push(addString(params.method), (0, _belSerializer.numeric)(params.status), addString(params.host), addString(params.pathname), (0, _belSerializer.numeric)(metrics.txSize), (0, _belSerializer.numeric)(metrics.rxSize), attrs.isFetch ? 1 : attrs.isJSONP ? 2 : '', addString(node.id), (0, _belSerializer.nullable)(node.dt && node.dt.spanId, addString, true) + (0, _belSerializer.nullable)(node.dt && node.dt.traceId, addString, true) + (0, _belSerializer.nullable)(node.dt && node.dt.timestamp, _belSerializer.numeric, false));
|
|
94
|
+
|
|
95
|
+
// add params.gql here
|
|
96
|
+
if (Object.keys(params?.gql || {}).length) {
|
|
97
|
+
var ajaxAttrParts = (0, _belSerializer.addCustomAttributes)(params.gql, addString);
|
|
98
|
+
children = children.concat(ajaxAttrParts);
|
|
99
|
+
attrCount = ajaxAttrParts.length;
|
|
100
|
+
}
|
|
94
101
|
break;
|
|
95
102
|
case 4:
|
|
96
103
|
var tracedTime = attrs.tracedTime;
|
package/dist/cjs/index.js
CHANGED
|
@@ -69,15 +69,8 @@ Object.defineProperty(exports, "Spa", {
|
|
|
69
69
|
return _spa.Spa;
|
|
70
70
|
}
|
|
71
71
|
});
|
|
72
|
-
Object.defineProperty(exports, "WorkerAgent", {
|
|
73
|
-
enumerable: true,
|
|
74
|
-
get: function () {
|
|
75
|
-
return _workerAgent.WorkerAgent;
|
|
76
|
-
}
|
|
77
|
-
});
|
|
78
72
|
var _agent = require("./loaders/agent");
|
|
79
73
|
var _browserAgent = require("./loaders/browser-agent");
|
|
80
|
-
var _workerAgent = require("./loaders/worker-agent");
|
|
81
74
|
var _microAgent = require("./loaders/micro-agent");
|
|
82
75
|
var _ajax = require("./features/ajax");
|
|
83
76
|
var _jserrors = require("./features/jserrors");
|
|
@@ -99,8 +99,8 @@ function setAPI(agentIdentifier, forceDrain) {
|
|
|
99
99
|
(0, _console.warn)("Failed to execute setCustomAttribute.\nName must be a string type, but a type of <".concat(typeof name, "> was provided."));
|
|
100
100
|
return;
|
|
101
101
|
}
|
|
102
|
-
if (!(['string', 'number'].includes(typeof value) || value === null)) {
|
|
103
|
-
(0, _console.warn)("Failed to execute setCustomAttribute.\nNon-null value must be a string or
|
|
102
|
+
if (!(['string', 'number', 'boolean'].includes(typeof value) || value === null)) {
|
|
103
|
+
(0, _console.warn)("Failed to execute setCustomAttribute.\nNon-null value must be a string, number or boolean type, but a type of <".concat(typeof value, "> was provided."));
|
|
104
104
|
return;
|
|
105
105
|
}
|
|
106
106
|
return appendJsAttribute(name, value, 'setCustomAttribute', persistAttribute);
|
|
@@ -13,8 +13,11 @@ import 'core-js/stable/array/some';
|
|
|
13
13
|
import 'core-js/stable/object/assign';
|
|
14
14
|
import 'core-js/stable/object/entries';
|
|
15
15
|
import 'core-js/stable/object/values';
|
|
16
|
+
import 'core-js/stable/object/from-entries';
|
|
16
17
|
import 'core-js/stable/map';
|
|
17
18
|
import 'core-js/stable/reflect';
|
|
18
19
|
import 'core-js/stable/set';
|
|
19
20
|
import 'core-js/stable/weak-set';
|
|
20
|
-
import 'core-js/stable/object/get-own-property-descriptors';
|
|
21
|
+
import 'core-js/stable/object/get-own-property-descriptors';
|
|
22
|
+
import 'core-js/stable/url';
|
|
23
|
+
import 'core-js/stable/url-search-params';
|
|
@@ -19,18 +19,19 @@ export function parseUrl(url) {
|
|
|
19
19
|
let urlEl;
|
|
20
20
|
var location = globalScope?.location;
|
|
21
21
|
var ret = {};
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
urlEl =
|
|
29
|
-
}
|
|
22
|
+
try {
|
|
23
|
+
urlEl = new URL(url, location.href);
|
|
24
|
+
} catch (err) {
|
|
25
|
+
if (isBrowserScope) {
|
|
26
|
+
// Use an anchor dom element to resolve the url natively.
|
|
27
|
+
urlEl = document.createElement('a');
|
|
28
|
+
urlEl.href = url;
|
|
29
|
+
} else {
|
|
30
30
|
return ret;
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
ret.port = urlEl.port;
|
|
34
|
+
ret.search = urlEl.search;
|
|
34
35
|
var firstSplit = urlEl.href.split('://');
|
|
35
36
|
if (!ret.port && firstSplit[1]) {
|
|
36
37
|
ret.port = firstSplit[1].split('/')[0].split('@').pop().split(':')[1];
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests a passed object to see if it is a pure object or not. All non-primatives in JS
|
|
3
|
+
* are technically objects and would pass a `typeof` check.
|
|
4
|
+
* @param {*} obj Input object to be tested
|
|
5
|
+
**/
|
|
6
|
+
export function isPureObject(obj) {
|
|
7
|
+
return obj?.constructor === {}.constructor;
|
|
8
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { isPureObject } from '../../../common/util/type-check';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} GQLMetadata
|
|
5
|
+
* @property {string} operationName Name of the operation
|
|
6
|
+
* @property {string} operationType Type of the operation
|
|
7
|
+
* @property {string} operationFramework Framework responsible for the operation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parses and returns the graphql metadata from a network request. If the network
|
|
12
|
+
* request is not a graphql call, undefined will be returned.
|
|
13
|
+
* @param {object|string} body Ajax request body
|
|
14
|
+
* @param {string} query Ajax request query param string
|
|
15
|
+
* @returns {GQLMetadata | undefined}
|
|
16
|
+
*/
|
|
17
|
+
export function parseGQL() {
|
|
18
|
+
let {
|
|
19
|
+
body,
|
|
20
|
+
query
|
|
21
|
+
} = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
22
|
+
if (!body && !query) return;
|
|
23
|
+
try {
|
|
24
|
+
const gqlBody = parseBatchGQL(parseGQLContents(body));
|
|
25
|
+
if (gqlBody) return gqlBody;
|
|
26
|
+
const gqlQuery = parseSingleGQL(parseGQLQueryString(query));
|
|
27
|
+
if (gqlQuery) return gqlQuery;
|
|
28
|
+
} catch (err) {
|
|
29
|
+
// parsing failed, return undefined
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @param {string|Object} gql The GraphQL object body sent to a GQL server
|
|
35
|
+
* @returns {GQLMetadata}
|
|
36
|
+
*/
|
|
37
|
+
function parseSingleGQL(contents) {
|
|
38
|
+
if (typeof contents !== 'object' || !contents.query || typeof contents.query !== 'string') return;
|
|
39
|
+
|
|
40
|
+
/** parses gql query string and returns [fullmatch, type match, name match] */
|
|
41
|
+
const matches = contents.query.trim().match(/^(query|mutation|subscription)\s?(\w*)/);
|
|
42
|
+
const operationType = matches?.[1];
|
|
43
|
+
if (!operationType) return;
|
|
44
|
+
const operationName = contents.operationName || matches?.[2] || 'Anonymous';
|
|
45
|
+
return {
|
|
46
|
+
operationName,
|
|
47
|
+
// the operation name of the indiv query
|
|
48
|
+
operationType,
|
|
49
|
+
// query, mutation, or subscription,
|
|
50
|
+
operationFramework: 'GraphQL'
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
function parseBatchGQL(contents) {
|
|
54
|
+
if (!contents) return;
|
|
55
|
+
if (!Array.isArray(contents)) contents = [contents];
|
|
56
|
+
const opNames = [];
|
|
57
|
+
const opTypes = [];
|
|
58
|
+
for (let content of contents) {
|
|
59
|
+
const operation = parseSingleGQL(content);
|
|
60
|
+
if (!operation) continue;
|
|
61
|
+
opNames.push(operation.operationName);
|
|
62
|
+
opTypes.push(operation.operationType);
|
|
63
|
+
}
|
|
64
|
+
if (!opTypes.length) return;
|
|
65
|
+
return {
|
|
66
|
+
operationName: opNames.join(','),
|
|
67
|
+
// the operation name of the indiv query -- joined by ',' for batched results
|
|
68
|
+
operationType: opTypes.join(','),
|
|
69
|
+
// query, mutation, or subscription -- joined by ',' for batched results
|
|
70
|
+
operationFramework: 'GraphQL'
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function parseGQLContents(gqlContents) {
|
|
74
|
+
let contents;
|
|
75
|
+
if (!gqlContents || typeof gqlContents !== 'string' && typeof gqlContents !== 'object') return;else if (typeof gqlContents === 'string') contents = JSON.parse(gqlContents);else contents = gqlContents;
|
|
76
|
+
if (!isPureObject(contents) && !Array.isArray(contents)) return;
|
|
77
|
+
let isValid = false;
|
|
78
|
+
if (Array.isArray(contents)) isValid = contents.some(x => validateGQLObject(x));else isValid = validateGQLObject(contents);
|
|
79
|
+
if (!isValid) return;
|
|
80
|
+
return contents;
|
|
81
|
+
}
|
|
82
|
+
function parseGQLQueryString(gqlQueryString) {
|
|
83
|
+
if (!gqlQueryString || typeof gqlQueryString !== 'string') return;
|
|
84
|
+
const params = new URLSearchParams(gqlQueryString);
|
|
85
|
+
return parseGQLContents(Object.fromEntries(params));
|
|
86
|
+
}
|
|
87
|
+
function validateGQLObject(obj) {
|
|
88
|
+
return !(typeof obj !== 'object' || !obj.query || typeof obj.query !== 'string');
|
|
89
|
+
}
|
|
@@ -13,6 +13,7 @@ import { FEATURE_NAME } from '../constants';
|
|
|
13
13
|
import { FEATURE_NAMES } from '../../../loaders/features/features';
|
|
14
14
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants';
|
|
15
15
|
import { AggregateBase } from '../../utils/aggregate-base';
|
|
16
|
+
import { parseGQL } from './gql';
|
|
16
17
|
export class Aggregate extends AggregateBase {
|
|
17
18
|
static featureName = FEATURE_NAME;
|
|
18
19
|
constructor(agentIdentifier, aggregator) {
|
|
@@ -109,6 +110,12 @@ export class Aggregate extends AggregateBase {
|
|
|
109
110
|
event.spanTimestamp = xhrContext.dt.timestamp;
|
|
110
111
|
}
|
|
111
112
|
|
|
113
|
+
// parsed from the AJAX body, looking for operationName param & parsing query for operationType
|
|
114
|
+
event.gql = params.gql = parseGQL({
|
|
115
|
+
body: this.body,
|
|
116
|
+
query: this?.parsedOrigin?.search
|
|
117
|
+
});
|
|
118
|
+
|
|
112
119
|
// if the ajax happened inside an interaction, hold it until the interaction finishes
|
|
113
120
|
if (this.spaNode) {
|
|
114
121
|
var interactionId = this.spaNode.interaction.id;
|
|
@@ -198,7 +205,11 @@ export class Aggregate extends AggregateBase {
|
|
|
198
205
|
var insert = '2,';
|
|
199
206
|
|
|
200
207
|
// add custom attributes
|
|
201
|
-
|
|
208
|
+
// gql decorators are added as custom attributes to alleviate need for new BEL schema
|
|
209
|
+
var attrParts = addCustomAttributes({
|
|
210
|
+
...(getInfo(agentIdentifier).jsAttributes || {}),
|
|
211
|
+
...(event.gql || {})
|
|
212
|
+
}, this.addString);
|
|
202
213
|
fields.unshift(numeric(attrParts.length));
|
|
203
214
|
insert += fields.join(',');
|
|
204
215
|
if (attrParts && attrParts.length > 0) {
|
|
@@ -153,6 +153,7 @@ function subscribeToEvents(agentIdentifier, ee, handler, dt) {
|
|
|
153
153
|
if (size) metrics.txSize = size;
|
|
154
154
|
}
|
|
155
155
|
this.startTime = now();
|
|
156
|
+
this.body = data;
|
|
156
157
|
this.listener = function (evt) {
|
|
157
158
|
try {
|
|
158
159
|
if (evt.type === 'abort' && !context.loadCaptureCalled) {
|
|
@@ -300,6 +301,7 @@ function subscribeToEvents(agentIdentifier, ee, handler, dt) {
|
|
|
300
301
|
addUrl(this, url);
|
|
301
302
|
var method = ('' + (target && target instanceof origRequest && target.method || opts.method || 'GET')).toUpperCase();
|
|
302
303
|
this.params.method = method;
|
|
304
|
+
this.body = opts.body;
|
|
303
305
|
this.txSize = dataSize(opts.body) || 0;
|
|
304
306
|
}
|
|
305
307
|
|
|
@@ -84,6 +84,13 @@ export class Serializer extends SharedContext {
|
|
|
84
84
|
break;
|
|
85
85
|
case 2:
|
|
86
86
|
fields.push(addString(params.method), numeric(params.status), addString(params.host), addString(params.pathname), numeric(metrics.txSize), numeric(metrics.rxSize), attrs.isFetch ? 1 : attrs.isJSONP ? 2 : '', addString(node.id), nullable(node.dt && node.dt.spanId, addString, true) + nullable(node.dt && node.dt.traceId, addString, true) + nullable(node.dt && node.dt.timestamp, numeric, false));
|
|
87
|
+
|
|
88
|
+
// add params.gql here
|
|
89
|
+
if (Object.keys(params?.gql || {}).length) {
|
|
90
|
+
var ajaxAttrParts = addCustomAttributes(params.gql, addString);
|
|
91
|
+
children = children.concat(ajaxAttrParts);
|
|
92
|
+
attrCount = ajaxAttrParts.length;
|
|
93
|
+
}
|
|
87
94
|
break;
|
|
88
95
|
case 4:
|
|
89
96
|
var tracedTime = attrs.tracedTime;
|
package/dist/esm/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { Agent } from './loaders/agent';
|
|
2
2
|
export { BrowserAgent } from './loaders/browser-agent';
|
|
3
|
-
export { WorkerAgent } from './loaders/worker-agent';
|
|
4
3
|
export { MicroAgent } from './loaders/micro-agent';
|
|
5
4
|
export { Ajax } from './features/ajax';
|
|
6
5
|
export { JSErrors } from './features/jserrors';
|
|
@@ -90,8 +90,8 @@ export function setAPI(agentIdentifier, forceDrain) {
|
|
|
90
90
|
warn("Failed to execute setCustomAttribute.\nName must be a string type, but a type of <".concat(typeof name, "> was provided."));
|
|
91
91
|
return;
|
|
92
92
|
}
|
|
93
|
-
if (!(['string', 'number'].includes(typeof value) || value === null)) {
|
|
94
|
-
warn("Failed to execute setCustomAttribute.\nNon-null value must be a string or
|
|
93
|
+
if (!(['string', 'number', 'boolean'].includes(typeof value) || value === null)) {
|
|
94
|
+
warn("Failed to execute setCustomAttribute.\nNon-null value must be a string, number or boolean type, but a type of <".concat(typeof value, "> was provided."));
|
|
95
95
|
return;
|
|
96
96
|
}
|
|
97
97
|
return appendJsAttribute(name, value, 'setCustomAttribute', persistAttribute);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"parse-url.d.ts","sourceRoot":"","sources":["../../../../src/common/url/parse-url.js"],"names":[],"mappings":"AASA,
|
|
1
|
+
{"version":3,"file":"parse-url.d.ts","sourceRoot":"","sources":["../../../../src/common/url/parse-url.js"],"names":[],"mappings":"AASA,wCA8DC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests a passed object to see if it is a pure object or not. All non-primatives in JS
|
|
3
|
+
* are technically objects and would pass a `typeof` check.
|
|
4
|
+
* @param {*} obj Input object to be tested
|
|
5
|
+
**/
|
|
6
|
+
export function isPureObject(obj: any): boolean;
|
|
7
|
+
//# sourceMappingURL=type-check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"type-check.d.ts","sourceRoot":"","sources":["../../../../src/common/util/type-check.js"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,gDAEC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {object} GQLMetadata
|
|
3
|
+
* @property {string} operationName Name of the operation
|
|
4
|
+
* @property {string} operationType Type of the operation
|
|
5
|
+
* @property {string} operationFramework Framework responsible for the operation
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Parses and returns the graphql metadata from a network request. If the network
|
|
9
|
+
* request is not a graphql call, undefined will be returned.
|
|
10
|
+
* @param {object|string} body Ajax request body
|
|
11
|
+
* @param {string} query Ajax request query param string
|
|
12
|
+
* @returns {GQLMetadata | undefined}
|
|
13
|
+
*/
|
|
14
|
+
export function parseGQL({ body, query }?: object | string): GQLMetadata | undefined;
|
|
15
|
+
export type GQLMetadata = {
|
|
16
|
+
/**
|
|
17
|
+
* Name of the operation
|
|
18
|
+
*/
|
|
19
|
+
operationName: string;
|
|
20
|
+
/**
|
|
21
|
+
* Type of the operation
|
|
22
|
+
*/
|
|
23
|
+
operationType: string;
|
|
24
|
+
/**
|
|
25
|
+
* Framework responsible for the operation
|
|
26
|
+
*/
|
|
27
|
+
operationFramework: string;
|
|
28
|
+
};
|
|
29
|
+
//# sourceMappingURL=gql.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gql.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/gql.js"],"names":[],"mappings":"AAEA;;;;;GAKG;AAEH;;;;;;GAMG;AACH,2CAJW,MAAM,GAAC,MAAM,GAEX,WAAW,GAAG,SAAS,CAYnC;;;;;mBAtBa,MAAM;;;;mBACN,MAAM;;;;wBACN,MAAM"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/index.js"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/features/ajax/aggregate/index.js"],"names":[],"mappings":"AAiBA;IACE,2BAAiC;IACjC,mDAuOC;IAhNC,qGAAwB;IACxB;;;;4BAAoC;IACpC;;;mBAA2E;CA+M9E;8BA7O6B,4BAA4B"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../../../../src/features/spa/aggregate/serializer.js"],"names":[],"mappings":"AAUA;IAII;;;;;;OAMG;IACH,gBAFU,MAAM,GAAC,SAAS,CAEK;IAGjC,0EASC;IAED,oFAMC;IAED,
|
|
1
|
+
{"version":3,"file":"serializer.d.ts","sourceRoot":"","sources":["../../../../../src/features/spa/aggregate/serializer.js"],"names":[],"mappings":"AAUA;IAII;;;;;;OAMG;IACH,gBAFU,MAAM,GAAC,SAAS,CAEK;IAGjC,0EASC;IAED,oFAMC;IAED,iHA+JC;CACF;8BApM6B,wCAAwC"}
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
export { Agent } from "./loaders/agent";
|
|
2
2
|
export { BrowserAgent } from "./loaders/browser-agent";
|
|
3
|
-
export { WorkerAgent } from "./loaders/worker-agent";
|
|
4
3
|
export { MicroAgent } from "./loaders/micro-agent";
|
|
5
4
|
export { Ajax } from "./features/ajax";
|
|
6
5
|
export { JSErrors } from "./features/jserrors";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@newrelic/browser-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.245.0",
|
|
4
4
|
"private": false,
|
|
5
5
|
"author": "New Relic Browser Agent Team <browser-agent@newrelic.com>",
|
|
6
6
|
"description": "New Relic Browser Agent",
|
|
@@ -26,9 +26,6 @@
|
|
|
26
26
|
"loaders/micro-agent": [
|
|
27
27
|
"dist/types/loaders/micro-agent.d.ts"
|
|
28
28
|
],
|
|
29
|
-
"loaders/worker-agent": [
|
|
30
|
-
"dist/types/loaders/worker-agent.d.ts"
|
|
31
|
-
],
|
|
32
29
|
"features/ajax": [
|
|
33
30
|
"dist/types/features/ajax/index.d.ts"
|
|
34
31
|
],
|
|
@@ -81,11 +78,6 @@
|
|
|
81
78
|
"require": "./dist/cjs/loaders/micro-agent.js",
|
|
82
79
|
"default": "./dist/esm/loaders/micro-agent.js"
|
|
83
80
|
},
|
|
84
|
-
"./loaders/worker-agent": {
|
|
85
|
-
"types": "./dist/types/loaders/worker-agent.d.ts",
|
|
86
|
-
"require": "./dist/cjs/loaders/worker-agent.js",
|
|
87
|
-
"default": "./dist/esm/loaders/worker-agent.js"
|
|
88
|
-
},
|
|
89
81
|
"./features/ajax": {
|
|
90
82
|
"types": "./dist/types/features/ajax/index.d.ts",
|
|
91
83
|
"require": "./dist/cjs/features/ajax/index.js",
|
package/src/cdn/polyfills.js
CHANGED
|
@@ -13,8 +13,11 @@ import 'core-js/stable/array/some'
|
|
|
13
13
|
import 'core-js/stable/object/assign'
|
|
14
14
|
import 'core-js/stable/object/entries'
|
|
15
15
|
import 'core-js/stable/object/values'
|
|
16
|
+
import 'core-js/stable/object/from-entries'
|
|
16
17
|
import 'core-js/stable/map'
|
|
17
18
|
import 'core-js/stable/reflect'
|
|
18
19
|
import 'core-js/stable/set'
|
|
19
20
|
import 'core-js/stable/weak-set'
|
|
20
21
|
import 'core-js/stable/object/get-own-property-descriptors'
|
|
22
|
+
import 'core-js/stable/url'
|
|
23
|
+
import 'core-js/stable/url-search-params'
|
|
@@ -23,20 +23,22 @@ export function parseUrl (url) {
|
|
|
23
23
|
var location = globalScope?.location
|
|
24
24
|
var ret = {}
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
try {
|
|
27
|
+
urlEl = new URL(url, location.href)
|
|
28
|
+
} catch (err) {
|
|
29
|
+
if (isBrowserScope) {
|
|
27
30
|
// Use an anchor dom element to resolve the url natively.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
try {
|
|
32
|
-
urlEl = new URL(url, location.href)
|
|
33
|
-
} catch (err) {
|
|
31
|
+
urlEl = document.createElement('a')
|
|
32
|
+
urlEl.href = url
|
|
33
|
+
} else {
|
|
34
34
|
return ret
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
ret.port = urlEl.port
|
|
39
39
|
|
|
40
|
+
ret.search = urlEl.search
|
|
41
|
+
|
|
40
42
|
var firstSplit = urlEl.href.split('://')
|
|
41
43
|
|
|
42
44
|
if (!ret.port && firstSplit[1]) {
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests a passed object to see if it is a pure object or not. All non-primatives in JS
|
|
3
|
+
* are technically objects and would pass a `typeof` check.
|
|
4
|
+
* @param {*} obj Input object to be tested
|
|
5
|
+
**/
|
|
6
|
+
export function isPureObject (obj) {
|
|
7
|
+
return obj?.constructor === ({}).constructor
|
|
8
|
+
}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { isPureObject } from '../../../common/util/type-check'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @typedef {object} GQLMetadata
|
|
5
|
+
* @property {string} operationName Name of the operation
|
|
6
|
+
* @property {string} operationType Type of the operation
|
|
7
|
+
* @property {string} operationFramework Framework responsible for the operation
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Parses and returns the graphql metadata from a network request. If the network
|
|
12
|
+
* request is not a graphql call, undefined will be returned.
|
|
13
|
+
* @param {object|string} body Ajax request body
|
|
14
|
+
* @param {string} query Ajax request query param string
|
|
15
|
+
* @returns {GQLMetadata | undefined}
|
|
16
|
+
*/
|
|
17
|
+
export function parseGQL ({ body, query } = {}) {
|
|
18
|
+
if (!body && !query) return
|
|
19
|
+
try {
|
|
20
|
+
const gqlBody = parseBatchGQL(parseGQLContents(body))
|
|
21
|
+
if (gqlBody) return gqlBody
|
|
22
|
+
const gqlQuery = parseSingleGQL(parseGQLQueryString(query))
|
|
23
|
+
if (gqlQuery) return gqlQuery
|
|
24
|
+
} catch (err) {
|
|
25
|
+
// parsing failed, return undefined
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* @param {string|Object} gql The GraphQL object body sent to a GQL server
|
|
31
|
+
* @returns {GQLMetadata}
|
|
32
|
+
*/
|
|
33
|
+
function parseSingleGQL (contents) {
|
|
34
|
+
if (typeof contents !== 'object' || !contents.query || typeof contents.query !== 'string') return
|
|
35
|
+
|
|
36
|
+
/** parses gql query string and returns [fullmatch, type match, name match] */
|
|
37
|
+
const matches = contents.query.trim().match(/^(query|mutation|subscription)\s?(\w*)/)
|
|
38
|
+
const operationType = matches?.[1]
|
|
39
|
+
if (!operationType) return
|
|
40
|
+
const operationName = contents.operationName || matches?.[2] || 'Anonymous'
|
|
41
|
+
return {
|
|
42
|
+
operationName, // the operation name of the indiv query
|
|
43
|
+
operationType, // query, mutation, or subscription,
|
|
44
|
+
operationFramework: 'GraphQL'
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
function parseBatchGQL (contents) {
|
|
49
|
+
if (!contents) return
|
|
50
|
+
if (!Array.isArray(contents)) contents = [contents]
|
|
51
|
+
|
|
52
|
+
const opNames = []
|
|
53
|
+
const opTypes = []
|
|
54
|
+
for (let content of contents) {
|
|
55
|
+
const operation = parseSingleGQL(content)
|
|
56
|
+
if (!operation) continue
|
|
57
|
+
|
|
58
|
+
opNames.push(operation.operationName)
|
|
59
|
+
opTypes.push(operation.operationType)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (!opTypes.length) return
|
|
63
|
+
return {
|
|
64
|
+
operationName: opNames.join(','), // the operation name of the indiv query -- joined by ',' for batched results
|
|
65
|
+
operationType: opTypes.join(','), // query, mutation, or subscription -- joined by ',' for batched results
|
|
66
|
+
operationFramework: 'GraphQL'
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function parseGQLContents (gqlContents) {
|
|
71
|
+
let contents
|
|
72
|
+
|
|
73
|
+
if (!gqlContents || (typeof gqlContents !== 'string' && typeof gqlContents !== 'object')) return
|
|
74
|
+
else if (typeof gqlContents === 'string') contents = JSON.parse(gqlContents)
|
|
75
|
+
else contents = gqlContents
|
|
76
|
+
|
|
77
|
+
if (!isPureObject(contents) && !Array.isArray(contents)) return
|
|
78
|
+
|
|
79
|
+
let isValid = false
|
|
80
|
+
if (Array.isArray(contents)) isValid = contents.some(x => validateGQLObject(x))
|
|
81
|
+
else isValid = validateGQLObject(contents)
|
|
82
|
+
|
|
83
|
+
if (!isValid) return
|
|
84
|
+
return contents
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function parseGQLQueryString (gqlQueryString) {
|
|
88
|
+
if (!gqlQueryString || typeof gqlQueryString !== 'string') return
|
|
89
|
+
const params = new URLSearchParams(gqlQueryString)
|
|
90
|
+
return parseGQLContents(Object.fromEntries(params))
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function validateGQLObject (obj) {
|
|
94
|
+
return !(typeof obj !== 'object' || !obj.query || typeof obj.query !== 'string')
|
|
95
|
+
}
|
|
@@ -13,6 +13,7 @@ import { FEATURE_NAME } from '../constants'
|
|
|
13
13
|
import { FEATURE_NAMES } from '../../../loaders/features/features'
|
|
14
14
|
import { SUPPORTABILITY_METRIC_CHANNEL } from '../../metrics/constants'
|
|
15
15
|
import { AggregateBase } from '../../utils/aggregate-base'
|
|
16
|
+
import { parseGQL } from './gql'
|
|
16
17
|
|
|
17
18
|
export class Aggregate extends AggregateBase {
|
|
18
19
|
static featureName = FEATURE_NAME
|
|
@@ -119,6 +120,12 @@ export class Aggregate extends AggregateBase {
|
|
|
119
120
|
event.spanTimestamp = xhrContext.dt.timestamp
|
|
120
121
|
}
|
|
121
122
|
|
|
123
|
+
// parsed from the AJAX body, looking for operationName param & parsing query for operationType
|
|
124
|
+
event.gql = params.gql = parseGQL({
|
|
125
|
+
body: this.body,
|
|
126
|
+
query: this?.parsedOrigin?.search
|
|
127
|
+
})
|
|
128
|
+
|
|
122
129
|
// if the ajax happened inside an interaction, hold it until the interaction finishes
|
|
123
130
|
if (this.spaNode) {
|
|
124
131
|
var interactionId = this.spaNode.interaction.id
|
|
@@ -221,7 +228,8 @@ export class Aggregate extends AggregateBase {
|
|
|
221
228
|
var insert = '2,'
|
|
222
229
|
|
|
223
230
|
// add custom attributes
|
|
224
|
-
|
|
231
|
+
// gql decorators are added as custom attributes to alleviate need for new BEL schema
|
|
232
|
+
var attrParts = addCustomAttributes({ ...(getInfo(agentIdentifier).jsAttributes || {}), ...(event.gql || {}) }, this.addString)
|
|
225
233
|
fields.unshift(numeric(attrParts.length))
|
|
226
234
|
|
|
227
235
|
insert += fields.join(',')
|
|
@@ -157,6 +157,8 @@ function subscribeToEvents (agentIdentifier, ee, handler, dt) {
|
|
|
157
157
|
|
|
158
158
|
this.startTime = now()
|
|
159
159
|
|
|
160
|
+
this.body = data
|
|
161
|
+
|
|
160
162
|
this.listener = function (evt) {
|
|
161
163
|
try {
|
|
162
164
|
if (evt.type === 'abort' && !(context.loadCaptureCalled)) {
|
|
@@ -329,6 +331,7 @@ function subscribeToEvents (agentIdentifier, ee, handler, dt) {
|
|
|
329
331
|
var method = ('' + ((target && target instanceof origRequest && target.method) ||
|
|
330
332
|
opts.method || 'GET')).toUpperCase()
|
|
331
333
|
this.params.method = method
|
|
334
|
+
this.body = opts.body
|
|
332
335
|
|
|
333
336
|
this.txSize = dataSize(opts.body) || 0
|
|
334
337
|
}
|
|
@@ -102,7 +102,6 @@ export class Serializer extends SharedContext {
|
|
|
102
102
|
nullable(attrs.firstPaint, numeric, true) +
|
|
103
103
|
nullable(attrs.firstContentfulPaint, numeric, false)
|
|
104
104
|
)
|
|
105
|
-
|
|
106
105
|
var attrParts = addCustomAttributes(attrs.custom, addString)
|
|
107
106
|
children = children.concat(attrParts)
|
|
108
107
|
attrCount = attrParts.length
|
|
@@ -128,6 +127,13 @@ export class Serializer extends SharedContext {
|
|
|
128
127
|
nullable(node.dt && node.dt.traceId, addString, true) +
|
|
129
128
|
nullable(node.dt && node.dt.timestamp, numeric, false)
|
|
130
129
|
)
|
|
130
|
+
|
|
131
|
+
// add params.gql here
|
|
132
|
+
if (Object.keys(params?.gql || {}).length) {
|
|
133
|
+
var ajaxAttrParts = addCustomAttributes(params.gql, addString)
|
|
134
|
+
children = children.concat(ajaxAttrParts)
|
|
135
|
+
attrCount = ajaxAttrParts.length
|
|
136
|
+
}
|
|
131
137
|
break
|
|
132
138
|
|
|
133
139
|
case 4:
|
package/src/index.js
CHANGED
package/src/loaders/api/api.js
CHANGED
|
@@ -89,8 +89,8 @@ export function setAPI (agentIdentifier, forceDrain) {
|
|
|
89
89
|
warn(`Failed to execute setCustomAttribute.\nName must be a string type, but a type of <${typeof name}> was provided.`)
|
|
90
90
|
return
|
|
91
91
|
}
|
|
92
|
-
if (!(['string', 'number'].includes(typeof value) || value === null)) {
|
|
93
|
-
warn(`Failed to execute setCustomAttribute.\nNon-null value must be a string or
|
|
92
|
+
if (!(['string', 'number', 'boolean'].includes(typeof value) || value === null)) {
|
|
93
|
+
warn(`Failed to execute setCustomAttribute.\nNon-null value must be a string, number or boolean type, but a type of <${typeof value}> was provided.`)
|
|
94
94
|
return
|
|
95
95
|
}
|
|
96
96
|
return appendJsAttribute(name, value, 'setCustomAttribute', persistAttribute)
|
package/dist/cjs/cdn/worker.js
DELETED
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
var _agent = require("../loaders/agent");
|
|
4
|
-
var _instrument = require("../features/metrics/instrument");
|
|
5
|
-
var _instrument2 = require("../features/jserrors/instrument");
|
|
6
|
-
var _instrument3 = require("../features/ajax/instrument");
|
|
7
|
-
var _instrument4 = require("../features/page_action/instrument");
|
|
8
|
-
/**
|
|
9
|
-
* @file Creates a "Worker" agent loader bundle composed of the core Agent and the subset of feature modules applicable
|
|
10
|
-
* in a service worker context.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
new _agent.Agent({
|
|
14
|
-
features: [_instrument.Instrument, _instrument2.Instrument, _instrument3.Instrument, _instrument4.Instrument],
|
|
15
|
-
loaderType: 'worker'
|
|
16
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.WorkerAgent = void 0;
|
|
7
|
-
var _agent = require("./agent");
|
|
8
|
-
var _instrument = require("../features/metrics/instrument");
|
|
9
|
-
var _instrument2 = require("../features/jserrors/instrument");
|
|
10
|
-
var _instrument3 = require("../features/ajax/instrument");
|
|
11
|
-
var _instrument4 = require("../features/page_action/instrument");
|
|
12
|
-
/**
|
|
13
|
-
* A streamlined agent class designed for the service worker context, limited to features relevant in that scope.
|
|
14
|
-
*/
|
|
15
|
-
class WorkerAgent extends _agent.Agent {
|
|
16
|
-
constructor(args) {
|
|
17
|
-
super({
|
|
18
|
-
...args,
|
|
19
|
-
features: [_instrument.Instrument, _instrument2.Instrument, _instrument3.Instrument, _instrument4.Instrument],
|
|
20
|
-
loaderType: 'worker-agent'
|
|
21
|
-
});
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
exports.WorkerAgent = WorkerAgent;
|
package/dist/esm/cdn/worker.js
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Creates a "Worker" agent loader bundle composed of the core Agent and the subset of feature modules applicable
|
|
3
|
-
* in a service worker context.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Agent } from '../loaders/agent';
|
|
7
|
-
import { Instrument as InstrumentMetrics } from '../features/metrics/instrument';
|
|
8
|
-
import { Instrument as InstrumentErrors } from '../features/jserrors/instrument';
|
|
9
|
-
import { Instrument as InstrumentXhr } from '../features/ajax/instrument';
|
|
10
|
-
import { Instrument as InstrumentPageAction } from '../features/page_action/instrument';
|
|
11
|
-
new Agent({
|
|
12
|
-
features: [InstrumentMetrics, InstrumentErrors, InstrumentXhr, InstrumentPageAction],
|
|
13
|
-
loaderType: 'worker'
|
|
14
|
-
});
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
import { Agent } from './agent';
|
|
2
|
-
import { Instrument as InstrumentMetrics } from '../features/metrics/instrument';
|
|
3
|
-
import { Instrument as InstrumentErrors } from '../features/jserrors/instrument';
|
|
4
|
-
import { Instrument as InstrumentXhr } from '../features/ajax/instrument';
|
|
5
|
-
import { Instrument as InstrumentPageAction } from '../features/page_action/instrument';
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* A streamlined agent class designed for the service worker context, limited to features relevant in that scope.
|
|
9
|
-
*/
|
|
10
|
-
export class WorkerAgent extends Agent {
|
|
11
|
-
constructor(args) {
|
|
12
|
-
super({
|
|
13
|
-
...args,
|
|
14
|
-
features: [InstrumentMetrics, InstrumentErrors, InstrumentXhr, InstrumentPageAction],
|
|
15
|
-
loaderType: 'worker-agent'
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"worker.d.ts","sourceRoot":"","sources":["../../../src/cdn/worker.js"],"names":[],"mappings":""}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* A streamlined agent class designed for the service worker context, limited to features relevant in that scope.
|
|
3
|
-
*/
|
|
4
|
-
export class WorkerAgent extends Agent {
|
|
5
|
-
constructor(args: any);
|
|
6
|
-
}
|
|
7
|
-
import { Agent } from './agent';
|
|
8
|
-
//# sourceMappingURL=worker-agent.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"worker-agent.d.ts","sourceRoot":"","sources":["../../../src/loaders/worker-agent.js"],"names":[],"mappings":"AAOA;;GAEG;AACH;IACE,uBAWC;CACF;sBAvBqB,SAAS"}
|
package/src/cdn/worker.js
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Creates a "Worker" agent loader bundle composed of the core Agent and the subset of feature modules applicable
|
|
3
|
-
* in a service worker context.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
import { Agent } from '../loaders/agent'
|
|
7
|
-
|
|
8
|
-
import { Instrument as InstrumentMetrics } from '../features/metrics/instrument'
|
|
9
|
-
import { Instrument as InstrumentErrors } from '../features/jserrors/instrument'
|
|
10
|
-
import { Instrument as InstrumentXhr } from '../features/ajax/instrument'
|
|
11
|
-
import { Instrument as InstrumentPageAction } from '../features/page_action/instrument'
|
|
12
|
-
|
|
13
|
-
new Agent({
|
|
14
|
-
features: [
|
|
15
|
-
InstrumentMetrics,
|
|
16
|
-
InstrumentErrors,
|
|
17
|
-
InstrumentXhr,
|
|
18
|
-
InstrumentPageAction
|
|
19
|
-
],
|
|
20
|
-
loaderType: 'worker'
|
|
21
|
-
})
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { Agent } from './agent'
|
|
2
|
-
|
|
3
|
-
import { Instrument as InstrumentMetrics } from '../features/metrics/instrument'
|
|
4
|
-
import { Instrument as InstrumentErrors } from '../features/jserrors/instrument'
|
|
5
|
-
import { Instrument as InstrumentXhr } from '../features/ajax/instrument'
|
|
6
|
-
import { Instrument as InstrumentPageAction } from '../features/page_action/instrument'
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* A streamlined agent class designed for the service worker context, limited to features relevant in that scope.
|
|
10
|
-
*/
|
|
11
|
-
export class WorkerAgent extends Agent {
|
|
12
|
-
constructor (args) {
|
|
13
|
-
super({
|
|
14
|
-
...args,
|
|
15
|
-
features: [
|
|
16
|
-
InstrumentMetrics,
|
|
17
|
-
InstrumentErrors,
|
|
18
|
-
InstrumentXhr,
|
|
19
|
-
InstrumentPageAction
|
|
20
|
-
],
|
|
21
|
-
loaderType: 'worker-agent'
|
|
22
|
-
})
|
|
23
|
-
}
|
|
24
|
-
}
|