@amplitude/plugin-network-capture-browser 1.4.4 → 1.5.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/lib/cjs/constants.d.ts +1 -0
- package/lib/cjs/constants.d.ts.map +1 -1
- package/lib/cjs/constants.js +4 -1
- package/lib/cjs/constants.js.map +1 -1
- package/lib/cjs/track-network-event.d.ts +14 -1
- package/lib/cjs/track-network-event.d.ts.map +1 -1
- package/lib/cjs/track-network-event.js +100 -5
- package/lib/cjs/track-network-event.js.map +1 -1
- package/lib/cjs/version.d.ts +1 -1
- package/lib/cjs/version.js +1 -1
- package/lib/cjs/version.js.map +1 -1
- package/lib/esm/constants.d.ts +1 -0
- package/lib/esm/constants.d.ts.map +1 -1
- package/lib/esm/constants.js +3 -0
- package/lib/esm/constants.js.map +1 -1
- package/lib/esm/track-network-event.d.ts +14 -1
- package/lib/esm/track-network-event.d.ts.map +1 -1
- package/lib/esm/track-network-event.js +100 -7
- package/lib/esm/track-network-event.js.map +1 -1
- package/lib/esm/version.d.ts +1 -1
- package/lib/esm/version.js +1 -1
- package/lib/esm/version.js.map +1 -1
- package/lib/scripts/amplitude-min.js +1 -1
- package/lib/scripts/amplitude-min.js.gz +0 -0
- package/lib/scripts/amplitude-min.js.map +1 -1
- package/lib/scripts/amplitude-min.umd.js +1 -1
- package/lib/scripts/amplitude-min.umd.js.gz +0 -0
- package/lib/scripts/constants.d.ts +1 -0
- package/lib/scripts/constants.d.ts.map +1 -1
- package/lib/scripts/track-network-event.d.ts +14 -1
- package/lib/scripts/track-network-event.d.ts.map +1 -1
- package/lib/scripts/version.d.ts +1 -1
- package/package.json +3 -3
package/lib/cjs/constants.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,8CAA8C,CAAC;AAEvE,eAAO,MAAM,+BAA+B,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,8CAA8C,CAAC;AAEvE,eAAO,MAAM,+BAA+B,gCAAgC,CAAC;AAI7E,eAAO,MAAM,8BAA8B,OAAO,CAAC"}
|
package/lib/cjs/constants.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.AMPLITUDE_NETWORK_REQUEST_EVENT = exports.PLUGIN_NAME = void 0;
|
|
3
|
+
exports.IS_HEADER_CAPTURE_EXPERIMENTAL = exports.AMPLITUDE_NETWORK_REQUEST_EVENT = exports.PLUGIN_NAME = void 0;
|
|
4
4
|
exports.PLUGIN_NAME = '@amplitude/plugin-network-capture-browser';
|
|
5
5
|
exports.AMPLITUDE_NETWORK_REQUEST_EVENT = '[Amplitude] Network Request';
|
|
6
|
+
// TODO: when @experimental is removed from responseHeaders and requestHeaders,
|
|
7
|
+
// remove this constant or set it to false
|
|
8
|
+
exports.IS_HEADER_CAPTURE_EXPERIMENTAL = true;
|
|
6
9
|
//# sourceMappingURL=constants.js.map
|
package/lib/cjs/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG,2CAA2C,CAAC;AAE1D,QAAA,+BAA+B,GAAG,6BAA6B,CAAC","sourcesContent":["export const PLUGIN_NAME = '@amplitude/plugin-network-capture-browser';\n\nexport const AMPLITUDE_NETWORK_REQUEST_EVENT = '[Amplitude] Network Request';\n"]}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":";;;AAAa,QAAA,WAAW,GAAG,2CAA2C,CAAC;AAE1D,QAAA,+BAA+B,GAAG,6BAA6B,CAAC;AAE7E,+EAA+E;AAC/E,0CAA0C;AAC7B,QAAA,8BAA8B,GAAG,IAAI,CAAC","sourcesContent":["export const PLUGIN_NAME = '@amplitude/plugin-network-capture-browser';\n\nexport const AMPLITUDE_NETWORK_REQUEST_EVENT = '[Amplitude] Network Request';\n\n// TODO: when @experimental is removed from responseHeaders and requestHeaders,\n// remove this constant or set it to false\nexport const IS_HEADER_CAPTURE_EXPERIMENTAL = true;\n"]}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { BrowserClient, NetworkRequestEvent, NetworkTrackingOptions } from '@amplitude/analytics-core';
|
|
1
|
+
import { BrowserClient, NetworkRequestEvent, NetworkTrackingOptions, JsonObject } from '@amplitude/analytics-core';
|
|
2
2
|
import { AllWindowObservables } from './network-capture-plugin';
|
|
3
|
+
/**
|
|
4
|
+
* Takes a user provided header capture rule and returns a
|
|
5
|
+
* HeaderCaptureRule object that sets proper default values.
|
|
6
|
+
*
|
|
7
|
+
* @param rule - The header capture rule to parse.
|
|
8
|
+
* @returns A HeaderCaptureRule object.
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseHeaderCaptureRule(rule: string[] | boolean | undefined | null): string[] | undefined;
|
|
3
11
|
export declare function shouldTrackNetworkEvent(networkEvent: NetworkRequestEvent, options?: NetworkTrackingOptions): boolean;
|
|
4
12
|
export type NetworkAnalyticsEvent = {
|
|
5
13
|
['[Amplitude] URL']: string;
|
|
@@ -11,9 +19,14 @@ export type NetworkAnalyticsEvent = {
|
|
|
11
19
|
['[Amplitude] Completion Time']?: number;
|
|
12
20
|
['[Amplitude] Duration']?: number;
|
|
13
21
|
['[Amplitude] Request Body Size']?: number;
|
|
22
|
+
['[Amplitude] Request Headers']?: Record<string, string>;
|
|
23
|
+
['[Amplitude] Request Body']?: JsonObject;
|
|
14
24
|
['[Amplitude] Response Body Size']?: number;
|
|
25
|
+
['[Amplitude] Response Headers']?: Record<string, string>;
|
|
26
|
+
['[Amplitude] Response Body']?: JsonObject;
|
|
15
27
|
['[Amplitude] Request Type']?: 'xhr' | 'fetch';
|
|
16
28
|
};
|
|
29
|
+
export declare function logNetworkAnalyticsEvent(networkAnalyticsEvent: NetworkAnalyticsEvent, request: NetworkRequestEvent, amplitude: BrowserClient): Promise<void>;
|
|
17
30
|
export declare function trackNetworkEvents({ allObservables, networkTrackingOptions, amplitude, }: {
|
|
18
31
|
allObservables: AllWindowObservables;
|
|
19
32
|
networkTrackingOptions: NetworkTrackingOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-network-event.d.ts","sourceRoot":"","sources":["../../src/track-network-event.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EAEnB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"track-network-event.d.ts","sourceRoot":"","sources":["../../src/track-network-event.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EAEnB,sBAAsB,EAEtB,UAAU,EAGX,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,oBAAoB,EAAoB,MAAM,0BAA0B,CAAC;AA+GlF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,GAAG,SAAS,CAmBxG;AAOD,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,mBAAmB,EAAE,OAAO,GAAE,sBAA2B,WA2F9G;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC5B,CAAC,uBAAuB,CAAC,CAAC,EAAE,MAAM,CAAC;IACnC,CAAC,0BAA0B,CAAC,CAAC,EAAE,MAAM,CAAC;IACtC,CAAC,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACvC,CAAC,yBAAyB,CAAC,CAAC,EAAE,MAAM,CAAC;IACrC,CAAC,wBAAwB,CAAC,CAAC,EAAE,MAAM,CAAC;IACpC,CAAC,6BAA6B,CAAC,CAAC,EAAE,MAAM,CAAC;IACzC,CAAC,sBAAsB,CAAC,CAAC,EAAE,MAAM,CAAC;IAClC,CAAC,+BAA+B,CAAC,CAAC,EAAE,MAAM,CAAC;IAC3C,CAAC,6BAA6B,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzD,CAAC,0BAA0B,CAAC,CAAC,EAAE,UAAU,CAAC;IAC1C,CAAC,gCAAgC,CAAC,CAAC,EAAE,MAAM,CAAC;IAC5C,CAAC,8BAA8B,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC,2BAA2B,CAAC,CAAC,EAAE,UAAU,CAAC;IAC3C,CAAC,0BAA0B,CAAC,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;CAChD,CAAC;AAEF,wBAAsB,wBAAwB,CAC5C,qBAAqB,EAAE,qBAAqB,EAC5C,OAAO,EAAE,mBAAmB,EAC5B,SAAS,EAAE,aAAa,iBAazB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,cAAc,EACd,sBAAsB,EACtB,SAAS,GACV,EAAE;IACD,cAAc,EAAE,oBAAoB,CAAC;IACrC,sBAAsB,EAAE,sBAAsB,CAAC;IAC/C,SAAS,EAAE,aAAa,CAAC;CAC1B,+BA+CA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.trackNetworkEvents = exports.shouldTrackNetworkEvent = void 0;
|
|
3
|
+
exports.trackNetworkEvents = exports.logNetworkAnalyticsEvent = exports.shouldTrackNetworkEvent = exports.parseHeaderCaptureRule = void 0;
|
|
4
4
|
var tslib_1 = require("tslib");
|
|
5
5
|
var analytics_core_1 = require("@amplitude/analytics-core");
|
|
6
6
|
var rxjs_1 = require("rxjs");
|
|
@@ -38,11 +38,21 @@ function isStatusCodeInRange(statusCode, range) {
|
|
|
38
38
|
}
|
|
39
39
|
return false;
|
|
40
40
|
}
|
|
41
|
-
function isCaptureRuleMatch(rule, hostname, status) {
|
|
41
|
+
function isCaptureRuleMatch(rule, hostname, status, url, method) {
|
|
42
42
|
// check if the host is in the allowed hosts
|
|
43
43
|
if (rule.hosts && !rule.hosts.find(function (host) { return wildcardMatch(hostname, host); })) {
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
|
+
// check if the URL is in the allowed URL patterns
|
|
47
|
+
if (url && rule.urls && !(0, analytics_core_1.isUrlMatchAllowlist)(url, rule.urls)) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
// check if the method is in the allowed methods
|
|
51
|
+
if (method &&
|
|
52
|
+
rule.methods &&
|
|
53
|
+
!rule.methods.find(function (allowedMethod) { return method.toLowerCase() === allowedMethod.toLowerCase() || allowedMethod === '*'; })) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
46
56
|
// check if the status code is in the allowed range
|
|
47
57
|
if (status || status === 0) {
|
|
48
58
|
var statusCodeRange = rule.statusCodeRange || DEFAULT_STATUS_CODE_RANGE;
|
|
@@ -95,6 +105,38 @@ function isAmplitudeNetworkRequestEvent(host, requestWrapper) {
|
|
|
95
105
|
}
|
|
96
106
|
return false;
|
|
97
107
|
}
|
|
108
|
+
/**
|
|
109
|
+
* Takes a user provided header capture rule and returns a
|
|
110
|
+
* HeaderCaptureRule object that sets proper default values.
|
|
111
|
+
*
|
|
112
|
+
* @param rule - The header capture rule to parse.
|
|
113
|
+
* @returns A HeaderCaptureRule object.
|
|
114
|
+
*/
|
|
115
|
+
function parseHeaderCaptureRule(rule) {
|
|
116
|
+
if (typeof rule !== 'object' || rule === null) {
|
|
117
|
+
// if rule is truthy or undefined, return SAFE_HEADERS
|
|
118
|
+
if (rule) {
|
|
119
|
+
return tslib_1.__spreadArray([], tslib_1.__read(analytics_core_1.SAFE_HEADERS), false);
|
|
120
|
+
}
|
|
121
|
+
else if (rule === undefined) {
|
|
122
|
+
/* istanbul ignore next */
|
|
123
|
+
var res = constants_1.IS_HEADER_CAPTURE_EXPERIMENTAL ? undefined : tslib_1.__spreadArray([], tslib_1.__read(analytics_core_1.SAFE_HEADERS), false);
|
|
124
|
+
return res;
|
|
125
|
+
}
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
// if the rule is defined but empty, return undefined
|
|
129
|
+
if (rule.length === 0) {
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
return rule;
|
|
133
|
+
}
|
|
134
|
+
exports.parseHeaderCaptureRule = parseHeaderCaptureRule;
|
|
135
|
+
function isBodyCaptureRuleEmpty(rule) {
|
|
136
|
+
var _a, _b;
|
|
137
|
+
/* istanbul ignore next */
|
|
138
|
+
return !((_a = rule === null || rule === void 0 ? void 0 : rule.allowlist) === null || _a === void 0 ? void 0 : _a.length) && !((_b = rule === null || rule === void 0 ? void 0 : rule.blocklist) === null || _b === void 0 ? void 0 : _b.length);
|
|
139
|
+
}
|
|
98
140
|
function shouldTrackNetworkEvent(networkEvent, options) {
|
|
99
141
|
var _a;
|
|
100
142
|
if (options === void 0) { options = {}; }
|
|
@@ -127,7 +169,32 @@ function shouldTrackNetworkEvent(networkEvent, options) {
|
|
|
127
169
|
// that is a match (true) or a miss (false)
|
|
128
170
|
var isMatch_1;
|
|
129
171
|
tslib_1.__spreadArray([], tslib_1.__read(options.captureRules), false).reverse().find(function (rule) {
|
|
130
|
-
isMatch_1 = isCaptureRuleMatch(rule, host, networkEvent.status);
|
|
172
|
+
isMatch_1 = isCaptureRuleMatch(rule, host, networkEvent.status, networkEvent.url, networkEvent.method);
|
|
173
|
+
if (isMatch_1) {
|
|
174
|
+
var responseHeadersRule = parseHeaderCaptureRule(rule.responseHeaders);
|
|
175
|
+
if (networkEvent.responseWrapper && responseHeadersRule) {
|
|
176
|
+
var responseHeaders = networkEvent.responseWrapper.headers(responseHeadersRule);
|
|
177
|
+
if (responseHeaders) {
|
|
178
|
+
networkEvent.responseHeaders = responseHeaders;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
// if requestHeaders rule is specified, enrich the event with the request headers
|
|
182
|
+
var requestHeadersRule = parseHeaderCaptureRule(rule.requestHeaders);
|
|
183
|
+
if (networkEvent.requestWrapper && requestHeadersRule) {
|
|
184
|
+
var requestHeaders = networkEvent.requestWrapper.headers(requestHeadersRule);
|
|
185
|
+
if (requestHeaders) {
|
|
186
|
+
networkEvent.requestHeaders = requestHeaders;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
// if responseBody rule is specified, enrich the event with the response body
|
|
190
|
+
if (networkEvent.responseWrapper && rule.responseBody && !isBodyCaptureRuleEmpty(rule.responseBody)) {
|
|
191
|
+
networkEvent.responseBodyJson = networkEvent.responseWrapper.json(rule.responseBody.allowlist, rule.responseBody.blocklist);
|
|
192
|
+
}
|
|
193
|
+
// if requestBody rule is specified, enrich the event with the request body
|
|
194
|
+
if (networkEvent.requestWrapper && rule.requestBody && !isBodyCaptureRuleEmpty(rule.requestBody)) {
|
|
195
|
+
networkEvent.requestBodyJson = networkEvent.requestWrapper.json(rule.requestBody.allowlist, rule.requestBody.blocklist);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
131
198
|
return isMatch_1 !== undefined;
|
|
132
199
|
});
|
|
133
200
|
// if we found a miss (false) or no match (undefined),
|
|
@@ -143,6 +210,32 @@ function shouldTrackNetworkEvent(networkEvent, options) {
|
|
|
143
210
|
return true;
|
|
144
211
|
}
|
|
145
212
|
exports.shouldTrackNetworkEvent = shouldTrackNetworkEvent;
|
|
213
|
+
function logNetworkAnalyticsEvent(networkAnalyticsEvent, request, amplitude) {
|
|
214
|
+
return tslib_1.__awaiter(this, void 0, void 0, function () {
|
|
215
|
+
var _a, requestBody, responseBody;
|
|
216
|
+
return tslib_1.__generator(this, function (_b) {
|
|
217
|
+
switch (_b.label) {
|
|
218
|
+
case 0:
|
|
219
|
+
if (!(request.requestBodyJson || request.responseBodyJson)) return [3 /*break*/, 2];
|
|
220
|
+
return [4 /*yield*/, Promise.all([request.requestBodyJson, request.responseBodyJson])];
|
|
221
|
+
case 1:
|
|
222
|
+
_a = tslib_1.__read.apply(void 0, [_b.sent(), 2]), requestBody = _a[0], responseBody = _a[1];
|
|
223
|
+
if (requestBody) {
|
|
224
|
+
networkAnalyticsEvent['[Amplitude] Request Body'] = requestBody;
|
|
225
|
+
}
|
|
226
|
+
if (responseBody) {
|
|
227
|
+
networkAnalyticsEvent['[Amplitude] Response Body'] = responseBody;
|
|
228
|
+
}
|
|
229
|
+
_b.label = 2;
|
|
230
|
+
case 2:
|
|
231
|
+
/* istanbul ignore next */
|
|
232
|
+
amplitude === null || amplitude === void 0 ? void 0 : amplitude.track(constants_1.AMPLITUDE_NETWORK_REQUEST_EVENT, networkAnalyticsEvent);
|
|
233
|
+
return [2 /*return*/];
|
|
234
|
+
}
|
|
235
|
+
});
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
exports.logNetworkAnalyticsEvent = logNetworkAnalyticsEvent;
|
|
146
239
|
function trackNetworkEvents(_a) {
|
|
147
240
|
var allObservables = _a.allObservables, networkTrackingOptions = _a.networkTrackingOptions, amplitude = _a.amplitude;
|
|
148
241
|
var networkObservable = allObservables.networkObservable;
|
|
@@ -179,9 +272,11 @@ function trackNetworkEvents(_a) {
|
|
|
179
272
|
_a['[Amplitude] Request Body Size'] = requestBodySize,
|
|
180
273
|
_a['[Amplitude] Response Body Size'] = responseBodySize,
|
|
181
274
|
_a['[Amplitude] Request Type'] = request.type,
|
|
275
|
+
_a['[Amplitude] Request Headers'] = request.requestHeaders,
|
|
276
|
+
_a['[Amplitude] Response Headers'] = request.responseHeaders,
|
|
182
277
|
_a);
|
|
183
|
-
|
|
184
|
-
|
|
278
|
+
// fire-and-forget promise that tracks the event
|
|
279
|
+
void logNetworkAnalyticsEvent(networkAnalyticsEvent, request, amplitude);
|
|
185
280
|
});
|
|
186
281
|
}
|
|
187
282
|
exports.trackNetworkEvents = trackNetworkEvents;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-network-event.js","sourceRoot":"","sources":["../../src/track-network-event.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BrowserClient,\n NetworkRequestEvent,\n NetworkCaptureRule,\n NetworkTrackingOptions,\n getGlobalScope,\n} from '@amplitude/analytics-core';\nimport { filter } from 'rxjs';\nimport { AllWindowObservables, TimestampedEvent } from './network-capture-plugin';\nimport { AMPLITUDE_NETWORK_REQUEST_EVENT } from './constants';\nimport { IRequestWrapper } from '@amplitude/analytics-core';\n\nconst DEFAULT_STATUS_CODE_RANGE = '500-599';\n\nfunction wildcardMatch(str: string, pattern: string) {\n // Escape all regex special characters except for *\n const escapedPattern = pattern.replace(/[-[\\]{}()+?.,\\\\^$|#\\s]/g, '\\\\$&');\n // Replace * with .*\n const regexPattern = '^' + escapedPattern.replace(/\\*/g, '.*') + '$';\n const regex = new RegExp(regexPattern);\n return regex.test(str);\n}\n\nfunction isStatusCodeInRange(statusCode: number, range: string) {\n const ranges = range.split(',');\n for (const r of ranges) {\n const [start, end] = r.split('-').map(Number);\n if (statusCode === start && end === undefined) {\n return true;\n }\n if (statusCode >= start && statusCode <= end) {\n return true;\n }\n }\n return false;\n}\n\nfunction isCaptureRuleMatch(rule: NetworkCaptureRule, hostname: string, status?: number) {\n // check if the host is in the allowed hosts\n if (rule.hosts && !rule.hosts.find((host: string) => wildcardMatch(hostname, host))) {\n return;\n }\n\n // check if the status code is in the allowed range\n if (status || status === 0) {\n const statusCodeRange = rule.statusCodeRange || DEFAULT_STATUS_CODE_RANGE;\n if (!isStatusCodeInRange(status, statusCodeRange)) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction parseUrl(url: string | undefined) {\n if (!url) {\n return;\n }\n try {\n /* istanbul ignore next */\n const currentHref = getGlobalScope()?.location.href;\n const urlObj = new URL(url, currentHref);\n const query = urlObj.searchParams.toString();\n const fragment = urlObj.hash.replace('#', '');\n const href = urlObj.href;\n const host = urlObj.host;\n urlObj.hash = '';\n urlObj.search = '';\n const hrefWithoutQueryOrHash = urlObj.href;\n return { query, fragment, href, hrefWithoutQueryOrHash, host };\n } catch (e) {\n /* istanbul ignore next */\n return;\n }\n}\n\nfunction isAmplitudeNetworkRequestEvent(host: string, requestWrapper: IRequestWrapper): boolean {\n if (host.includes('amplitude.com')) {\n try {\n const body = requestWrapper.body;\n if (typeof body !== 'string') {\n return false;\n }\n const bodyObj = JSON.parse(body) as { events: any[] };\n const { events } = bodyObj;\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n if (events.find((event: any) => event.event_type === AMPLITUDE_NETWORK_REQUEST_EVENT)) {\n return true;\n }\n } catch (e) {\n // do nothing\n }\n }\n return false;\n}\n\nexport function shouldTrackNetworkEvent(networkEvent: NetworkRequestEvent, options: NetworkTrackingOptions = {}) {\n const urlObj = parseUrl(networkEvent.url);\n /* istanbul ignore if */\n if (!urlObj) {\n // if the URL failed to parse, do not track the event\n // this is a probably impossible case that would only happen if the URL is malformed\n /* istanbul ignore next */\n return false;\n }\n const { host } = urlObj;\n\n // false if is amplitude request and not configured to track amplitude requests\n if (\n options.ignoreAmplitudeRequests !== false &&\n (wildcardMatch(host, '*.amplitude.com') || wildcardMatch(host, 'amplitude.com'))\n ) {\n return false;\n }\n\n // false if the host is in the ignore list\n if (options.ignoreHosts?.find((ignoreHost: string) => wildcardMatch(host, ignoreHost))) {\n return false;\n }\n\n // false if the status code is not 500-599 and there are no captureRules\n if (\n !options.captureRules &&\n networkEvent.status !== undefined &&\n !isStatusCodeInRange(networkEvent.status, DEFAULT_STATUS_CODE_RANGE)\n ) {\n return false;\n }\n\n if (options.captureRules) {\n // find the first capture rule, in reverse-order,\n // that is a match (true) or a miss (false)\n let isMatch: boolean | undefined;\n [...options.captureRules].reverse().find((rule) => {\n isMatch = isCaptureRuleMatch(rule, host, networkEvent.status);\n return isMatch !== undefined;\n });\n\n // if we found a miss (false) or no match (undefined),\n // then do not track the event\n if (!isMatch) {\n return false;\n }\n }\n\n // skip Amplitude network requests to \"[Amplitude] Network Request\" to avoid infinite loop\n if (networkEvent.requestWrapper && isAmplitudeNetworkRequestEvent(host, networkEvent.requestWrapper)) {\n return false;\n }\n\n return true;\n}\n\nexport type NetworkAnalyticsEvent = {\n ['[Amplitude] URL']: string;\n ['[Amplitude] URL Query']?: string;\n ['[Amplitude] URL Fragment']?: string;\n ['[Amplitude] Request Method']: string;\n ['[Amplitude] Status Code']?: number;\n ['[Amplitude] Start Time']?: number; // unix timestamp\n ['[Amplitude] Completion Time']?: number; // unix timestamp\n ['[Amplitude] Duration']?: number; // completionTime - startTime (millis)\n ['[Amplitude] Request Body Size']?: number;\n ['[Amplitude] Response Body Size']?: number;\n ['[Amplitude] Request Type']?: 'xhr' | 'fetch';\n};\n\nexport function trackNetworkEvents({\n allObservables,\n networkTrackingOptions,\n amplitude,\n}: {\n allObservables: AllWindowObservables;\n networkTrackingOptions: NetworkTrackingOptions;\n amplitude: BrowserClient;\n}) {\n const { networkObservable } = allObservables;\n\n const filteredNetworkObservable = networkObservable.pipe(\n filter((event: TimestampedEvent<NetworkRequestEvent>) => {\n // Only track network events that should be tracked,\n return shouldTrackNetworkEvent(event.event as NetworkRequestEvent, networkTrackingOptions);\n }),\n );\n\n return filteredNetworkObservable.subscribe((networkEvent) => {\n const request = networkEvent.event;\n\n // convert to NetworkAnalyticsEvent\n const urlObj = parseUrl(request.url);\n /* istanbul ignore if */\n if (!urlObj) {\n // if the URL failed to parse, do not track the event\n // this is a very unlikely case, because URL() shouldn't throw an exception\n // when the URL is a valid URL\n /* istanbul ignore next */\n return;\n }\n\n const responseBodySize = request.responseWrapper?.bodySize;\n /* istanbul ignore next */\n const requestBodySize = request.requestWrapper?.bodySize;\n\n const networkAnalyticsEvent: NetworkAnalyticsEvent = {\n ['[Amplitude] URL']: urlObj.hrefWithoutQueryOrHash,\n ['[Amplitude] URL Query']: urlObj.query,\n ['[Amplitude] URL Fragment']: urlObj.fragment,\n ['[Amplitude] Request Method']: request.method,\n ['[Amplitude] Status Code']: request.status,\n ['[Amplitude] Start Time']: request.startTime,\n ['[Amplitude] Completion Time']: request.endTime,\n ['[Amplitude] Duration']: request.duration,\n ['[Amplitude] Request Body Size']: requestBodySize,\n ['[Amplitude] Response Body Size']: responseBodySize,\n ['[Amplitude] Request Type']: request.type,\n };\n\n /* istanbul ignore next */\n amplitude?.track(AMPLITUDE_NETWORK_REQUEST_EVENT, networkAnalyticsEvent);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"track-network-event.js","sourceRoot":"","sources":["../../src/track-network-event.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BrowserClient,\n NetworkRequestEvent,\n NetworkCaptureRule,\n NetworkTrackingOptions,\n getGlobalScope,\n JsonObject,\n isUrlMatchAllowlist,\n SAFE_HEADERS,\n} from '@amplitude/analytics-core';\nimport { filter } from 'rxjs';\nimport { AllWindowObservables, TimestampedEvent } from './network-capture-plugin';\nimport { AMPLITUDE_NETWORK_REQUEST_EVENT, IS_HEADER_CAPTURE_EXPERIMENTAL } from './constants';\nimport { IRequestWrapper } from '@amplitude/analytics-core';\nimport { BodyCaptureRule } from '@amplitude/analytics-core/lib/esm/types/network-tracking';\n\nconst DEFAULT_STATUS_CODE_RANGE = '500-599';\n\nfunction wildcardMatch(str: string, pattern: string) {\n // Escape all regex special characters except for *\n const escapedPattern = pattern.replace(/[-[\\]{}()+?.,\\\\^$|#\\s]/g, '\\\\$&');\n // Replace * with .*\n const regexPattern = '^' + escapedPattern.replace(/\\*/g, '.*') + '$';\n const regex = new RegExp(regexPattern);\n return regex.test(str);\n}\n\nfunction isStatusCodeInRange(statusCode: number, range: string) {\n const ranges = range.split(',');\n for (const r of ranges) {\n const [start, end] = r.split('-').map(Number);\n if (statusCode === start && end === undefined) {\n return true;\n }\n if (statusCode >= start && statusCode <= end) {\n return true;\n }\n }\n return false;\n}\n\nfunction isCaptureRuleMatch(\n rule: NetworkCaptureRule,\n hostname: string,\n status?: number,\n url?: string,\n method?: string,\n) {\n // check if the host is in the allowed hosts\n if (rule.hosts && !rule.hosts.find((host: string) => wildcardMatch(hostname, host))) {\n return;\n }\n\n // check if the URL is in the allowed URL patterns\n if (url && rule.urls && !isUrlMatchAllowlist(url, rule.urls)) {\n return;\n }\n\n // check if the method is in the allowed methods\n if (\n method &&\n rule.methods &&\n !rule.methods.find(\n (allowedMethod: string) => method.toLowerCase() === allowedMethod.toLowerCase() || allowedMethod === '*',\n )\n ) {\n return;\n }\n\n // check if the status code is in the allowed range\n if (status || status === 0) {\n const statusCodeRange = rule.statusCodeRange || DEFAULT_STATUS_CODE_RANGE;\n if (!isStatusCodeInRange(status, statusCodeRange)) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction parseUrl(url: string | undefined) {\n if (!url) {\n return;\n }\n try {\n /* istanbul ignore next */\n const currentHref = getGlobalScope()?.location.href;\n const urlObj = new URL(url, currentHref);\n const query = urlObj.searchParams.toString();\n const fragment = urlObj.hash.replace('#', '');\n const href = urlObj.href;\n const host = urlObj.host;\n urlObj.hash = '';\n urlObj.search = '';\n const hrefWithoutQueryOrHash = urlObj.href;\n return { query, fragment, href, hrefWithoutQueryOrHash, host };\n } catch (e) {\n /* istanbul ignore next */\n return;\n }\n}\n\nfunction isAmplitudeNetworkRequestEvent(host: string, requestWrapper: IRequestWrapper): boolean {\n if (host.includes('amplitude.com')) {\n try {\n const body = requestWrapper.body;\n if (typeof body !== 'string') {\n return false;\n }\n const bodyObj = JSON.parse(body) as { events: any[] };\n const { events } = bodyObj;\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n if (events.find((event: any) => event.event_type === AMPLITUDE_NETWORK_REQUEST_EVENT)) {\n return true;\n }\n } catch (e) {\n // do nothing\n }\n }\n return false;\n}\n\n/**\n * Takes a user provided header capture rule and returns a\n * HeaderCaptureRule object that sets proper default values.\n *\n * @param rule - The header capture rule to parse.\n * @returns A HeaderCaptureRule object.\n */\nexport function parseHeaderCaptureRule(rule: string[] | boolean | undefined | null): string[] | undefined {\n if (typeof rule !== 'object' || rule === null) {\n // if rule is truthy or undefined, return SAFE_HEADERS\n if (rule) {\n return [...SAFE_HEADERS];\n } else if (rule === undefined) {\n /* istanbul ignore next */\n const res = IS_HEADER_CAPTURE_EXPERIMENTAL ? undefined : [...SAFE_HEADERS];\n return res;\n }\n return;\n }\n\n // if the rule is defined but empty, return undefined\n if (rule.length === 0) {\n return;\n }\n\n return rule;\n}\n\nfunction isBodyCaptureRuleEmpty(rule: BodyCaptureRule) {\n /* istanbul ignore next */\n return !rule?.allowlist?.length && !rule?.blocklist?.length;\n}\n\nexport function shouldTrackNetworkEvent(networkEvent: NetworkRequestEvent, options: NetworkTrackingOptions = {}) {\n const urlObj = parseUrl(networkEvent.url);\n /* istanbul ignore if */\n if (!urlObj) {\n // if the URL failed to parse, do not track the event\n // this is a probably impossible case that would only happen if the URL is malformed\n /* istanbul ignore next */\n return false;\n }\n const { host } = urlObj;\n\n // false if is amplitude request and not configured to track amplitude requests\n if (\n options.ignoreAmplitudeRequests !== false &&\n (wildcardMatch(host, '*.amplitude.com') || wildcardMatch(host, 'amplitude.com'))\n ) {\n return false;\n }\n\n // false if the host is in the ignore list\n if (options.ignoreHosts?.find((ignoreHost: string) => wildcardMatch(host, ignoreHost))) {\n return false;\n }\n\n // false if the status code is not 500-599 and there are no captureRules\n if (\n !options.captureRules &&\n networkEvent.status !== undefined &&\n !isStatusCodeInRange(networkEvent.status, DEFAULT_STATUS_CODE_RANGE)\n ) {\n return false;\n }\n\n if (options.captureRules) {\n // find the first capture rule, in reverse-order,\n // that is a match (true) or a miss (false)\n let isMatch: boolean | undefined;\n [...options.captureRules].reverse().find((rule) => {\n isMatch = isCaptureRuleMatch(rule, host, networkEvent.status, networkEvent.url, networkEvent.method);\n\n if (isMatch) {\n const responseHeadersRule = parseHeaderCaptureRule(rule.responseHeaders);\n if (networkEvent.responseWrapper && responseHeadersRule) {\n const responseHeaders = networkEvent.responseWrapper.headers(responseHeadersRule);\n if (responseHeaders) {\n networkEvent.responseHeaders = responseHeaders;\n }\n }\n\n // if requestHeaders rule is specified, enrich the event with the request headers\n const requestHeadersRule = parseHeaderCaptureRule(rule.requestHeaders);\n if (networkEvent.requestWrapper && requestHeadersRule) {\n const requestHeaders = networkEvent.requestWrapper.headers(requestHeadersRule);\n if (requestHeaders) {\n networkEvent.requestHeaders = requestHeaders;\n }\n }\n\n // if responseBody rule is specified, enrich the event with the response body\n if (networkEvent.responseWrapper && rule.responseBody && !isBodyCaptureRuleEmpty(rule.responseBody)) {\n networkEvent.responseBodyJson = networkEvent.responseWrapper.json(\n rule.responseBody.allowlist,\n rule.responseBody.blocklist,\n );\n }\n\n // if requestBody rule is specified, enrich the event with the request body\n if (networkEvent.requestWrapper && rule.requestBody && !isBodyCaptureRuleEmpty(rule.requestBody)) {\n networkEvent.requestBodyJson = networkEvent.requestWrapper.json(\n rule.requestBody.allowlist,\n rule.requestBody.blocklist,\n );\n }\n }\n\n return isMatch !== undefined;\n });\n\n // if we found a miss (false) or no match (undefined),\n // then do not track the event\n if (!isMatch) {\n return false;\n }\n }\n\n // skip Amplitude network requests to \"[Amplitude] Network Request\" to avoid infinite loop\n if (networkEvent.requestWrapper && isAmplitudeNetworkRequestEvent(host, networkEvent.requestWrapper)) {\n return false;\n }\n\n return true;\n}\n\nexport type NetworkAnalyticsEvent = {\n ['[Amplitude] URL']: string;\n ['[Amplitude] URL Query']?: string;\n ['[Amplitude] URL Fragment']?: string;\n ['[Amplitude] Request Method']: string;\n ['[Amplitude] Status Code']?: number;\n ['[Amplitude] Start Time']?: number; // unix timestamp\n ['[Amplitude] Completion Time']?: number; // unix timestamp\n ['[Amplitude] Duration']?: number; // completionTime - startTime (millis)\n ['[Amplitude] Request Body Size']?: number;\n ['[Amplitude] Request Headers']?: Record<string, string>;\n ['[Amplitude] Request Body']?: JsonObject;\n ['[Amplitude] Response Body Size']?: number;\n ['[Amplitude] Response Headers']?: Record<string, string>;\n ['[Amplitude] Response Body']?: JsonObject;\n ['[Amplitude] Request Type']?: 'xhr' | 'fetch';\n};\n\nexport async function logNetworkAnalyticsEvent(\n networkAnalyticsEvent: NetworkAnalyticsEvent,\n request: NetworkRequestEvent,\n amplitude: BrowserClient,\n) {\n if (request.requestBodyJson || request.responseBodyJson) {\n const [requestBody, responseBody] = await Promise.all([request.requestBodyJson, request.responseBodyJson]);\n if (requestBody) {\n networkAnalyticsEvent['[Amplitude] Request Body'] = requestBody;\n }\n if (responseBody) {\n networkAnalyticsEvent['[Amplitude] Response Body'] = responseBody;\n }\n }\n /* istanbul ignore next */\n amplitude?.track(AMPLITUDE_NETWORK_REQUEST_EVENT, networkAnalyticsEvent);\n}\n\nexport function trackNetworkEvents({\n allObservables,\n networkTrackingOptions,\n amplitude,\n}: {\n allObservables: AllWindowObservables;\n networkTrackingOptions: NetworkTrackingOptions;\n amplitude: BrowserClient;\n}) {\n const { networkObservable } = allObservables;\n\n const filteredNetworkObservable = networkObservable.pipe(\n filter((event: TimestampedEvent<NetworkRequestEvent>) => {\n // Only track network events that should be tracked,\n return shouldTrackNetworkEvent(event.event as NetworkRequestEvent, networkTrackingOptions);\n }),\n );\n\n return filteredNetworkObservable.subscribe((networkEvent) => {\n const request = networkEvent.event;\n\n // convert to NetworkAnalyticsEvent\n const urlObj = parseUrl(request.url);\n /* istanbul ignore if */\n if (!urlObj) {\n // if the URL failed to parse, do not track the event\n // this is a very unlikely case, because URL() shouldn't throw an exception\n // when the URL is a valid URL\n /* istanbul ignore next */\n return;\n }\n\n const responseBodySize = request.responseWrapper?.bodySize;\n /* istanbul ignore next */\n const requestBodySize = request.requestWrapper?.bodySize;\n\n const networkAnalyticsEvent: NetworkAnalyticsEvent = {\n ['[Amplitude] URL']: urlObj.hrefWithoutQueryOrHash,\n ['[Amplitude] URL Query']: urlObj.query,\n ['[Amplitude] URL Fragment']: urlObj.fragment,\n ['[Amplitude] Request Method']: request.method,\n ['[Amplitude] Status Code']: request.status,\n ['[Amplitude] Start Time']: request.startTime,\n ['[Amplitude] Completion Time']: request.endTime,\n ['[Amplitude] Duration']: request.duration,\n ['[Amplitude] Request Body Size']: requestBodySize,\n ['[Amplitude] Response Body Size']: responseBodySize,\n ['[Amplitude] Request Type']: request.type,\n ['[Amplitude] Request Headers']: request.requestHeaders,\n ['[Amplitude] Response Headers']: request.responseHeaders,\n };\n\n // fire-and-forget promise that tracks the event\n void logNetworkAnalyticsEvent(networkAnalyticsEvent, request, amplitude);\n });\n}\n"]}
|
package/lib/cjs/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.5.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/lib/cjs/version.js
CHANGED
package/lib/cjs/version.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,OAAO,CAAC","sourcesContent":["export const VERSION = '1.
|
|
1
|
+
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../src/version.ts"],"names":[],"mappings":";;;AAAa,QAAA,OAAO,GAAG,OAAO,CAAC","sourcesContent":["export const VERSION = '1.5.0';\n"]}
|
package/lib/esm/constants.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,8CAA8C,CAAC;AAEvE,eAAO,MAAM,+BAA+B,gCAAgC,CAAC"}
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,8CAA8C,CAAC;AAEvE,eAAO,MAAM,+BAA+B,gCAAgC,CAAC;AAI7E,eAAO,MAAM,8BAA8B,OAAO,CAAC"}
|
package/lib/esm/constants.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
export var PLUGIN_NAME = '@amplitude/plugin-network-capture-browser';
|
|
2
2
|
export var AMPLITUDE_NETWORK_REQUEST_EVENT = '[Amplitude] Network Request';
|
|
3
|
+
// TODO: when @experimental is removed from responseHeaders and requestHeaders,
|
|
4
|
+
// remove this constant or set it to false
|
|
5
|
+
export var IS_HEADER_CAPTURE_EXPERIMENTAL = true;
|
|
3
6
|
//# sourceMappingURL=constants.js.map
|
package/lib/esm/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,IAAM,WAAW,GAAG,2CAA2C,CAAC;AAEvE,MAAM,CAAC,IAAM,+BAA+B,GAAG,6BAA6B,CAAC","sourcesContent":["export const PLUGIN_NAME = '@amplitude/plugin-network-capture-browser';\n\nexport const AMPLITUDE_NETWORK_REQUEST_EVENT = '[Amplitude] Network Request';\n"]}
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../../src/constants.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,IAAM,WAAW,GAAG,2CAA2C,CAAC;AAEvE,MAAM,CAAC,IAAM,+BAA+B,GAAG,6BAA6B,CAAC;AAE7E,+EAA+E;AAC/E,0CAA0C;AAC1C,MAAM,CAAC,IAAM,8BAA8B,GAAG,IAAI,CAAC","sourcesContent":["export const PLUGIN_NAME = '@amplitude/plugin-network-capture-browser';\n\nexport const AMPLITUDE_NETWORK_REQUEST_EVENT = '[Amplitude] Network Request';\n\n// TODO: when @experimental is removed from responseHeaders and requestHeaders,\n// remove this constant or set it to false\nexport const IS_HEADER_CAPTURE_EXPERIMENTAL = true;\n"]}
|
|
@@ -1,5 +1,13 @@
|
|
|
1
|
-
import { BrowserClient, NetworkRequestEvent, NetworkTrackingOptions } from '@amplitude/analytics-core';
|
|
1
|
+
import { BrowserClient, NetworkRequestEvent, NetworkTrackingOptions, JsonObject } from '@amplitude/analytics-core';
|
|
2
2
|
import { AllWindowObservables } from './network-capture-plugin';
|
|
3
|
+
/**
|
|
4
|
+
* Takes a user provided header capture rule and returns a
|
|
5
|
+
* HeaderCaptureRule object that sets proper default values.
|
|
6
|
+
*
|
|
7
|
+
* @param rule - The header capture rule to parse.
|
|
8
|
+
* @returns A HeaderCaptureRule object.
|
|
9
|
+
*/
|
|
10
|
+
export declare function parseHeaderCaptureRule(rule: string[] | boolean | undefined | null): string[] | undefined;
|
|
3
11
|
export declare function shouldTrackNetworkEvent(networkEvent: NetworkRequestEvent, options?: NetworkTrackingOptions): boolean;
|
|
4
12
|
export type NetworkAnalyticsEvent = {
|
|
5
13
|
['[Amplitude] URL']: string;
|
|
@@ -11,9 +19,14 @@ export type NetworkAnalyticsEvent = {
|
|
|
11
19
|
['[Amplitude] Completion Time']?: number;
|
|
12
20
|
['[Amplitude] Duration']?: number;
|
|
13
21
|
['[Amplitude] Request Body Size']?: number;
|
|
22
|
+
['[Amplitude] Request Headers']?: Record<string, string>;
|
|
23
|
+
['[Amplitude] Request Body']?: JsonObject;
|
|
14
24
|
['[Amplitude] Response Body Size']?: number;
|
|
25
|
+
['[Amplitude] Response Headers']?: Record<string, string>;
|
|
26
|
+
['[Amplitude] Response Body']?: JsonObject;
|
|
15
27
|
['[Amplitude] Request Type']?: 'xhr' | 'fetch';
|
|
16
28
|
};
|
|
29
|
+
export declare function logNetworkAnalyticsEvent(networkAnalyticsEvent: NetworkAnalyticsEvent, request: NetworkRequestEvent, amplitude: BrowserClient): Promise<void>;
|
|
17
30
|
export declare function trackNetworkEvents({ allObservables, networkTrackingOptions, amplitude, }: {
|
|
18
31
|
allObservables: AllWindowObservables;
|
|
19
32
|
networkTrackingOptions: NetworkTrackingOptions;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-network-event.d.ts","sourceRoot":"","sources":["../../src/track-network-event.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EAEnB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"track-network-event.d.ts","sourceRoot":"","sources":["../../src/track-network-event.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,mBAAmB,EAEnB,sBAAsB,EAEtB,UAAU,EAGX,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,oBAAoB,EAAoB,MAAM,0BAA0B,CAAC;AA+GlF;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,EAAE,GAAG,SAAS,CAmBxG;AAOD,wBAAgB,uBAAuB,CAAC,YAAY,EAAE,mBAAmB,EAAE,OAAO,GAAE,sBAA2B,WA2F9G;AAED,MAAM,MAAM,qBAAqB,GAAG;IAClC,CAAC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC5B,CAAC,uBAAuB,CAAC,CAAC,EAAE,MAAM,CAAC;IACnC,CAAC,0BAA0B,CAAC,CAAC,EAAE,MAAM,CAAC;IACtC,CAAC,4BAA4B,CAAC,EAAE,MAAM,CAAC;IACvC,CAAC,yBAAyB,CAAC,CAAC,EAAE,MAAM,CAAC;IACrC,CAAC,wBAAwB,CAAC,CAAC,EAAE,MAAM,CAAC;IACpC,CAAC,6BAA6B,CAAC,CAAC,EAAE,MAAM,CAAC;IACzC,CAAC,sBAAsB,CAAC,CAAC,EAAE,MAAM,CAAC;IAClC,CAAC,+BAA+B,CAAC,CAAC,EAAE,MAAM,CAAC;IAC3C,CAAC,6BAA6B,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACzD,CAAC,0BAA0B,CAAC,CAAC,EAAE,UAAU,CAAC;IAC1C,CAAC,gCAAgC,CAAC,CAAC,EAAE,MAAM,CAAC;IAC5C,CAAC,8BAA8B,CAAC,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC1D,CAAC,2BAA2B,CAAC,CAAC,EAAE,UAAU,CAAC;IAC3C,CAAC,0BAA0B,CAAC,CAAC,EAAE,KAAK,GAAG,OAAO,CAAC;CAChD,CAAC;AAEF,wBAAsB,wBAAwB,CAC5C,qBAAqB,EAAE,qBAAqB,EAC5C,OAAO,EAAE,mBAAmB,EAC5B,SAAS,EAAE,aAAa,iBAazB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,cAAc,EACd,sBAAsB,EACtB,SAAS,GACV,EAAE;IACD,cAAc,EAAE,oBAAoB,CAAC;IACrC,sBAAsB,EAAE,sBAAsB,CAAC;IAC/C,SAAS,EAAE,aAAa,CAAC;CAC1B,+BA+CA"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { __read, __spreadArray, __values } from "tslib";
|
|
2
|
-
import { getGlobalScope, } from '@amplitude/analytics-core';
|
|
1
|
+
import { __awaiter, __generator, __read, __spreadArray, __values } from "tslib";
|
|
2
|
+
import { getGlobalScope, isUrlMatchAllowlist, SAFE_HEADERS, } from '@amplitude/analytics-core';
|
|
3
3
|
import { filter } from 'rxjs';
|
|
4
|
-
import { AMPLITUDE_NETWORK_REQUEST_EVENT } from './constants';
|
|
4
|
+
import { AMPLITUDE_NETWORK_REQUEST_EVENT, IS_HEADER_CAPTURE_EXPERIMENTAL } from './constants';
|
|
5
5
|
var DEFAULT_STATUS_CODE_RANGE = '500-599';
|
|
6
6
|
function wildcardMatch(str, pattern) {
|
|
7
7
|
// Escape all regex special characters except for *
|
|
@@ -35,11 +35,21 @@ function isStatusCodeInRange(statusCode, range) {
|
|
|
35
35
|
}
|
|
36
36
|
return false;
|
|
37
37
|
}
|
|
38
|
-
function isCaptureRuleMatch(rule, hostname, status) {
|
|
38
|
+
function isCaptureRuleMatch(rule, hostname, status, url, method) {
|
|
39
39
|
// check if the host is in the allowed hosts
|
|
40
40
|
if (rule.hosts && !rule.hosts.find(function (host) { return wildcardMatch(hostname, host); })) {
|
|
41
41
|
return;
|
|
42
42
|
}
|
|
43
|
+
// check if the URL is in the allowed URL patterns
|
|
44
|
+
if (url && rule.urls && !isUrlMatchAllowlist(url, rule.urls)) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// check if the method is in the allowed methods
|
|
48
|
+
if (method &&
|
|
49
|
+
rule.methods &&
|
|
50
|
+
!rule.methods.find(function (allowedMethod) { return method.toLowerCase() === allowedMethod.toLowerCase() || allowedMethod === '*'; })) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
43
53
|
// check if the status code is in the allowed range
|
|
44
54
|
if (status || status === 0) {
|
|
45
55
|
var statusCodeRange = rule.statusCodeRange || DEFAULT_STATUS_CODE_RANGE;
|
|
@@ -92,6 +102,37 @@ function isAmplitudeNetworkRequestEvent(host, requestWrapper) {
|
|
|
92
102
|
}
|
|
93
103
|
return false;
|
|
94
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* Takes a user provided header capture rule and returns a
|
|
107
|
+
* HeaderCaptureRule object that sets proper default values.
|
|
108
|
+
*
|
|
109
|
+
* @param rule - The header capture rule to parse.
|
|
110
|
+
* @returns A HeaderCaptureRule object.
|
|
111
|
+
*/
|
|
112
|
+
export function parseHeaderCaptureRule(rule) {
|
|
113
|
+
if (typeof rule !== 'object' || rule === null) {
|
|
114
|
+
// if rule is truthy or undefined, return SAFE_HEADERS
|
|
115
|
+
if (rule) {
|
|
116
|
+
return __spreadArray([], __read(SAFE_HEADERS), false);
|
|
117
|
+
}
|
|
118
|
+
else if (rule === undefined) {
|
|
119
|
+
/* istanbul ignore next */
|
|
120
|
+
var res = IS_HEADER_CAPTURE_EXPERIMENTAL ? undefined : __spreadArray([], __read(SAFE_HEADERS), false);
|
|
121
|
+
return res;
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// if the rule is defined but empty, return undefined
|
|
126
|
+
if (rule.length === 0) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
return rule;
|
|
130
|
+
}
|
|
131
|
+
function isBodyCaptureRuleEmpty(rule) {
|
|
132
|
+
var _a, _b;
|
|
133
|
+
/* istanbul ignore next */
|
|
134
|
+
return !((_a = rule === null || rule === void 0 ? void 0 : rule.allowlist) === null || _a === void 0 ? void 0 : _a.length) && !((_b = rule === null || rule === void 0 ? void 0 : rule.blocklist) === null || _b === void 0 ? void 0 : _b.length);
|
|
135
|
+
}
|
|
95
136
|
export function shouldTrackNetworkEvent(networkEvent, options) {
|
|
96
137
|
var _a;
|
|
97
138
|
if (options === void 0) { options = {}; }
|
|
@@ -124,7 +165,32 @@ export function shouldTrackNetworkEvent(networkEvent, options) {
|
|
|
124
165
|
// that is a match (true) or a miss (false)
|
|
125
166
|
var isMatch_1;
|
|
126
167
|
__spreadArray([], __read(options.captureRules), false).reverse().find(function (rule) {
|
|
127
|
-
isMatch_1 = isCaptureRuleMatch(rule, host, networkEvent.status);
|
|
168
|
+
isMatch_1 = isCaptureRuleMatch(rule, host, networkEvent.status, networkEvent.url, networkEvent.method);
|
|
169
|
+
if (isMatch_1) {
|
|
170
|
+
var responseHeadersRule = parseHeaderCaptureRule(rule.responseHeaders);
|
|
171
|
+
if (networkEvent.responseWrapper && responseHeadersRule) {
|
|
172
|
+
var responseHeaders = networkEvent.responseWrapper.headers(responseHeadersRule);
|
|
173
|
+
if (responseHeaders) {
|
|
174
|
+
networkEvent.responseHeaders = responseHeaders;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// if requestHeaders rule is specified, enrich the event with the request headers
|
|
178
|
+
var requestHeadersRule = parseHeaderCaptureRule(rule.requestHeaders);
|
|
179
|
+
if (networkEvent.requestWrapper && requestHeadersRule) {
|
|
180
|
+
var requestHeaders = networkEvent.requestWrapper.headers(requestHeadersRule);
|
|
181
|
+
if (requestHeaders) {
|
|
182
|
+
networkEvent.requestHeaders = requestHeaders;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// if responseBody rule is specified, enrich the event with the response body
|
|
186
|
+
if (networkEvent.responseWrapper && rule.responseBody && !isBodyCaptureRuleEmpty(rule.responseBody)) {
|
|
187
|
+
networkEvent.responseBodyJson = networkEvent.responseWrapper.json(rule.responseBody.allowlist, rule.responseBody.blocklist);
|
|
188
|
+
}
|
|
189
|
+
// if requestBody rule is specified, enrich the event with the request body
|
|
190
|
+
if (networkEvent.requestWrapper && rule.requestBody && !isBodyCaptureRuleEmpty(rule.requestBody)) {
|
|
191
|
+
networkEvent.requestBodyJson = networkEvent.requestWrapper.json(rule.requestBody.allowlist, rule.requestBody.blocklist);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
128
194
|
return isMatch_1 !== undefined;
|
|
129
195
|
});
|
|
130
196
|
// if we found a miss (false) or no match (undefined),
|
|
@@ -139,6 +205,31 @@ export function shouldTrackNetworkEvent(networkEvent, options) {
|
|
|
139
205
|
}
|
|
140
206
|
return true;
|
|
141
207
|
}
|
|
208
|
+
export function logNetworkAnalyticsEvent(networkAnalyticsEvent, request, amplitude) {
|
|
209
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
210
|
+
var _a, requestBody, responseBody;
|
|
211
|
+
return __generator(this, function (_b) {
|
|
212
|
+
switch (_b.label) {
|
|
213
|
+
case 0:
|
|
214
|
+
if (!(request.requestBodyJson || request.responseBodyJson)) return [3 /*break*/, 2];
|
|
215
|
+
return [4 /*yield*/, Promise.all([request.requestBodyJson, request.responseBodyJson])];
|
|
216
|
+
case 1:
|
|
217
|
+
_a = __read.apply(void 0, [_b.sent(), 2]), requestBody = _a[0], responseBody = _a[1];
|
|
218
|
+
if (requestBody) {
|
|
219
|
+
networkAnalyticsEvent['[Amplitude] Request Body'] = requestBody;
|
|
220
|
+
}
|
|
221
|
+
if (responseBody) {
|
|
222
|
+
networkAnalyticsEvent['[Amplitude] Response Body'] = responseBody;
|
|
223
|
+
}
|
|
224
|
+
_b.label = 2;
|
|
225
|
+
case 2:
|
|
226
|
+
/* istanbul ignore next */
|
|
227
|
+
amplitude === null || amplitude === void 0 ? void 0 : amplitude.track(AMPLITUDE_NETWORK_REQUEST_EVENT, networkAnalyticsEvent);
|
|
228
|
+
return [2 /*return*/];
|
|
229
|
+
}
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
}
|
|
142
233
|
export function trackNetworkEvents(_a) {
|
|
143
234
|
var allObservables = _a.allObservables, networkTrackingOptions = _a.networkTrackingOptions, amplitude = _a.amplitude;
|
|
144
235
|
var networkObservable = allObservables.networkObservable;
|
|
@@ -175,9 +266,11 @@ export function trackNetworkEvents(_a) {
|
|
|
175
266
|
_a['[Amplitude] Request Body Size'] = requestBodySize,
|
|
176
267
|
_a['[Amplitude] Response Body Size'] = responseBodySize,
|
|
177
268
|
_a['[Amplitude] Request Type'] = request.type,
|
|
269
|
+
_a['[Amplitude] Request Headers'] = request.requestHeaders,
|
|
270
|
+
_a['[Amplitude] Response Headers'] = request.responseHeaders,
|
|
178
271
|
_a);
|
|
179
|
-
|
|
180
|
-
|
|
272
|
+
// fire-and-forget promise that tracks the event
|
|
273
|
+
void logNetworkAnalyticsEvent(networkAnalyticsEvent, request, amplitude);
|
|
181
274
|
});
|
|
182
275
|
}
|
|
183
276
|
//# sourceMappingURL=track-network-event.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"track-network-event.js","sourceRoot":"","sources":["../../src/track-network-event.ts"],"names":[],"mappings":";AAAA,OAAO,EAKL,cAAc,GACf,MAAM,2BAA2B,CAAC;AACnC,OAAO,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC;AAE9B,OAAO,EAAE,+BAA+B,EAAE,MAAM,aAAa,CAAC;AAG9D,IAAM,yBAAyB,GAAG,SAAS,CAAC;AAE5C,SAAS,aAAa,CAAC,GAAW,EAAE,OAAe;IACjD,mDAAmD;IACnD,IAAM,cAAc,GAAG,OAAO,CAAC,OAAO,CAAC,yBAAyB,EAAE,MAAM,CAAC,CAAC;IAC1E,oBAAoB;IACpB,IAAM,YAAY,GAAG,GAAG,GAAG,cAAc,CAAC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,GAAG,CAAC;IACrE,IAAM,KAAK,GAAG,IAAI,MAAM,CAAC,YAAY,CAAC,CAAC;IACvC,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACzB,CAAC;AAED,SAAS,mBAAmB,CAAC,UAAkB,EAAE,KAAa;;IAC5D,IAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;;QAChC,KAAgB,IAAA,WAAA,SAAA,MAAM,CAAA,8BAAA,kDAAE;YAAnB,IAAM,CAAC,mBAAA;YACJ,IAAA,KAAA,OAAe,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,IAAA,EAAtC,KAAK,QAAA,EAAE,GAAG,QAA4B,CAAC;YAC9C,IAAI,UAAU,KAAK,KAAK,IAAI,GAAG,KAAK,SAAS,EAAE;gBAC7C,OAAO,IAAI,CAAC;aACb;YACD,IAAI,UAAU,IAAI,KAAK,IAAI,UAAU,IAAI,GAAG,EAAE;gBAC5C,OAAO,IAAI,CAAC;aACb;SACF;;;;;;;;;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,kBAAkB,CAAC,IAAwB,EAAE,QAAgB,EAAE,MAAe;IACrF,4CAA4C;IAC5C,IAAI,IAAI,CAAC,KAAK,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,UAAC,IAAY,IAAK,OAAA,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,EAA7B,CAA6B,CAAC,EAAE;QACnF,OAAO;KACR;IAED,mDAAmD;IACnD,IAAI,MAAM,IAAI,MAAM,KAAK,CAAC,EAAE;QAC1B,IAAM,eAAe,GAAG,IAAI,CAAC,eAAe,IAAI,yBAAyB,CAAC;QAC1E,IAAI,CAAC,mBAAmB,CAAC,MAAM,EAAE,eAAe,CAAC,EAAE;YACjD,OAAO,KAAK,CAAC;SACd;KACF;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CAAC,GAAuB;;IACvC,IAAI,CAAC,GAAG,EAAE;QACR,OAAO;KACR;IACD,IAAI;QACF,0BAA0B;QAC1B,IAAM,WAAW,GAAG,MAAA,cAAc,EAAE,0CAAE,QAAQ,CAAC,IAAI,CAAC;QACpD,IAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC;QACzC,IAAM,KAAK,GAAG,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,CAAC;QAC7C,IAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;QAC9C,IAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACzB,IAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC;QACzB,MAAM,CAAC,IAAI,GAAG,EAAE,CAAC;QACjB,MAAM,CAAC,MAAM,GAAG,EAAE,CAAC;QACnB,IAAM,sBAAsB,GAAG,MAAM,CAAC,IAAI,CAAC;QAC3C,OAAO,EAAE,KAAK,OAAA,EAAE,QAAQ,UAAA,EAAE,IAAI,MAAA,EAAE,sBAAsB,wBAAA,EAAE,IAAI,MAAA,EAAE,CAAC;KAChE;IAAC,OAAO,CAAC,EAAE;QACV,0BAA0B;QAC1B,OAAO;KACR;AACH,CAAC;AAED,SAAS,8BAA8B,CAAC,IAAY,EAAE,cAA+B;IACnF,IAAI,IAAI,CAAC,QAAQ,CAAC,eAAe,CAAC,EAAE;QAClC,IAAI;YACF,IAAM,IAAI,GAAG,cAAc,CAAC,IAAI,CAAC;YACjC,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE;gBAC5B,OAAO,KAAK,CAAC;aACd;YACD,IAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAsB,CAAC;YAC9C,IAAA,MAAM,GAAK,OAAO,OAAZ,CAAa;YAC3B,yEAAyE;YACzE,IAAI,MAAM,CAAC,IAAI,CAAC,UAAC,KAAU,IAAK,OAAA,KAAK,CAAC,UAAU,KAAK,+BAA+B,EAApD,CAAoD,CAAC,EAAE;gBACrF,OAAO,IAAI,CAAC;aACb;SACF;QAAC,OAAO,CAAC,EAAE;YACV,aAAa;SACd;KACF;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,YAAiC,EAAE,OAAoC;;IAApC,wBAAA,EAAA,YAAoC;IAC7G,IAAM,MAAM,GAAG,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAC1C,wBAAwB;IACxB,IAAI,CAAC,MAAM,EAAE;QACX,qDAAqD;QACrD,oFAAoF;QACpF,0BAA0B;QAC1B,OAAO,KAAK,CAAC;KACd;IACO,IAAA,IAAI,GAAK,MAAM,KAAX,CAAY;IAExB,+EAA+E;IAC/E,IACE,OAAO,CAAC,uBAAuB,KAAK,KAAK;QACzC,CAAC,aAAa,CAAC,IAAI,EAAE,iBAAiB,CAAC,IAAI,aAAa,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC,EAChF;QACA,OAAO,KAAK,CAAC;KACd;IAED,0CAA0C;IAC1C,IAAI,MAAA,OAAO,CAAC,WAAW,0CAAE,IAAI,CAAC,UAAC,UAAkB,IAAK,OAAA,aAAa,CAAC,IAAI,EAAE,UAAU,CAAC,EAA/B,CAA+B,CAAC,EAAE;QACtF,OAAO,KAAK,CAAC;KACd;IAED,wEAAwE;IACxE,IACE,CAAC,OAAO,CAAC,YAAY;QACrB,YAAY,CAAC,MAAM,KAAK,SAAS;QACjC,CAAC,mBAAmB,CAAC,YAAY,CAAC,MAAM,EAAE,yBAAyB,CAAC,EACpE;QACA,OAAO,KAAK,CAAC;KACd;IAED,IAAI,OAAO,CAAC,YAAY,EAAE;QACxB,iDAAiD;QACjD,2CAA2C;QAC3C,IAAI,SAA4B,CAAC;QACjC,yBAAI,OAAO,CAAC,YAAY,UAAE,OAAO,EAAE,CAAC,IAAI,CAAC,UAAC,IAAI;YAC5C,SAAO,GAAG,kBAAkB,CAAC,IAAI,EAAE,IAAI,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;YAC9D,OAAO,SAAO,KAAK,SAAS,CAAC;QAC/B,CAAC,CAAC,CAAC;QAEH,sDAAsD;QACtD,8BAA8B;QAC9B,IAAI,CAAC,SAAO,EAAE;YACZ,OAAO,KAAK,CAAC;SACd;KACF;IAED,0FAA0F;IAC1F,IAAI,YAAY,CAAC,cAAc,IAAI,8BAA8B,CAAC,IAAI,EAAE,YAAY,CAAC,cAAc,CAAC,EAAE;QACpG,OAAO,KAAK,CAAC;KACd;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAgBD,MAAM,UAAU,kBAAkB,CAAC,EAQlC;QAPC,cAAc,oBAAA,EACd,sBAAsB,4BAAA,EACtB,SAAS,eAAA;IAMD,IAAA,iBAAiB,GAAK,cAAc,kBAAnB,CAAoB;IAE7C,IAAM,yBAAyB,GAAG,iBAAiB,CAAC,IAAI,CACtD,MAAM,CAAC,UAAC,KAA4C;QAClD,oDAAoD;QACpD,OAAO,uBAAuB,CAAC,KAAK,CAAC,KAA4B,EAAE,sBAAsB,CAAC,CAAC;IAC7F,CAAC,CAAC,CACH,CAAC;IAEF,OAAO,yBAAyB,CAAC,SAAS,CAAC,UAAC,YAAY;;;QACtD,IAAM,OAAO,GAAG,YAAY,CAAC,KAAK,CAAC;QAEnC,mCAAmC;QACnC,IAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACrC,wBAAwB;QACxB,IAAI,CAAC,MAAM,EAAE;YACX,qDAAqD;YACrD,2EAA2E;YAC3E,8BAA8B;YAC9B,0BAA0B;YAC1B,OAAO;SACR;QAED,IAAM,gBAAgB,GAAG,MAAA,OAAO,CAAC,eAAe,0CAAE,QAAQ,CAAC;QAC3D,0BAA0B;QAC1B,IAAM,eAAe,GAAG,MAAA,OAAO,CAAC,cAAc,0CAAE,QAAQ,CAAC;QAEzD,IAAM,qBAAqB;YACzB,GAAC,iBAAiB,IAAG,MAAM,CAAC,sBAAsB;YAClD,GAAC,uBAAuB,IAAG,MAAM,CAAC,KAAK;YACvC,GAAC,0BAA0B,IAAG,MAAM,CAAC,QAAQ;YAC7C,GAAC,4BAA4B,IAAG,OAAO,CAAC,MAAM;YAC9C,GAAC,yBAAyB,IAAG,OAAO,CAAC,MAAM;YAC3C,GAAC,wBAAwB,IAAG,OAAO,CAAC,SAAS;YAC7C,GAAC,6BAA6B,IAAG,OAAO,CAAC,OAAO;YAChD,GAAC,sBAAsB,IAAG,OAAO,CAAC,QAAQ;YAC1C,GAAC,+BAA+B,IAAG,eAAe;YAClD,GAAC,gCAAgC,IAAG,gBAAgB;YACpD,GAAC,0BAA0B,IAAG,OAAO,CAAC,IAAI;eAC3C,CAAC;QAEF,0BAA0B;QAC1B,SAAS,aAAT,SAAS,uBAAT,SAAS,CAAE,KAAK,CAAC,+BAA+B,EAAE,qBAAqB,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;AACL,CAAC","sourcesContent":["import {\n BrowserClient,\n NetworkRequestEvent,\n NetworkCaptureRule,\n NetworkTrackingOptions,\n getGlobalScope,\n} from '@amplitude/analytics-core';\nimport { filter } from 'rxjs';\nimport { AllWindowObservables, TimestampedEvent } from './network-capture-plugin';\nimport { AMPLITUDE_NETWORK_REQUEST_EVENT } from './constants';\nimport { IRequestWrapper } from '@amplitude/analytics-core';\n\nconst DEFAULT_STATUS_CODE_RANGE = '500-599';\n\nfunction wildcardMatch(str: string, pattern: string) {\n // Escape all regex special characters except for *\n const escapedPattern = pattern.replace(/[-[\\]{}()+?.,\\\\^$|#\\s]/g, '\\\\$&');\n // Replace * with .*\n const regexPattern = '^' + escapedPattern.replace(/\\*/g, '.*') + '$';\n const regex = new RegExp(regexPattern);\n return regex.test(str);\n}\n\nfunction isStatusCodeInRange(statusCode: number, range: string) {\n const ranges = range.split(',');\n for (const r of ranges) {\n const [start, end] = r.split('-').map(Number);\n if (statusCode === start && end === undefined) {\n return true;\n }\n if (statusCode >= start && statusCode <= end) {\n return true;\n }\n }\n return false;\n}\n\nfunction isCaptureRuleMatch(rule: NetworkCaptureRule, hostname: string, status?: number) {\n // check if the host is in the allowed hosts\n if (rule.hosts && !rule.hosts.find((host: string) => wildcardMatch(hostname, host))) {\n return;\n }\n\n // check if the status code is in the allowed range\n if (status || status === 0) {\n const statusCodeRange = rule.statusCodeRange || DEFAULT_STATUS_CODE_RANGE;\n if (!isStatusCodeInRange(status, statusCodeRange)) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction parseUrl(url: string | undefined) {\n if (!url) {\n return;\n }\n try {\n /* istanbul ignore next */\n const currentHref = getGlobalScope()?.location.href;\n const urlObj = new URL(url, currentHref);\n const query = urlObj.searchParams.toString();\n const fragment = urlObj.hash.replace('#', '');\n const href = urlObj.href;\n const host = urlObj.host;\n urlObj.hash = '';\n urlObj.search = '';\n const hrefWithoutQueryOrHash = urlObj.href;\n return { query, fragment, href, hrefWithoutQueryOrHash, host };\n } catch (e) {\n /* istanbul ignore next */\n return;\n }\n}\n\nfunction isAmplitudeNetworkRequestEvent(host: string, requestWrapper: IRequestWrapper): boolean {\n if (host.includes('amplitude.com')) {\n try {\n const body = requestWrapper.body;\n if (typeof body !== 'string') {\n return false;\n }\n const bodyObj = JSON.parse(body) as { events: any[] };\n const { events } = bodyObj;\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n if (events.find((event: any) => event.event_type === AMPLITUDE_NETWORK_REQUEST_EVENT)) {\n return true;\n }\n } catch (e) {\n // do nothing\n }\n }\n return false;\n}\n\nexport function shouldTrackNetworkEvent(networkEvent: NetworkRequestEvent, options: NetworkTrackingOptions = {}) {\n const urlObj = parseUrl(networkEvent.url);\n /* istanbul ignore if */\n if (!urlObj) {\n // if the URL failed to parse, do not track the event\n // this is a probably impossible case that would only happen if the URL is malformed\n /* istanbul ignore next */\n return false;\n }\n const { host } = urlObj;\n\n // false if is amplitude request and not configured to track amplitude requests\n if (\n options.ignoreAmplitudeRequests !== false &&\n (wildcardMatch(host, '*.amplitude.com') || wildcardMatch(host, 'amplitude.com'))\n ) {\n return false;\n }\n\n // false if the host is in the ignore list\n if (options.ignoreHosts?.find((ignoreHost: string) => wildcardMatch(host, ignoreHost))) {\n return false;\n }\n\n // false if the status code is not 500-599 and there are no captureRules\n if (\n !options.captureRules &&\n networkEvent.status !== undefined &&\n !isStatusCodeInRange(networkEvent.status, DEFAULT_STATUS_CODE_RANGE)\n ) {\n return false;\n }\n\n if (options.captureRules) {\n // find the first capture rule, in reverse-order,\n // that is a match (true) or a miss (false)\n let isMatch: boolean | undefined;\n [...options.captureRules].reverse().find((rule) => {\n isMatch = isCaptureRuleMatch(rule, host, networkEvent.status);\n return isMatch !== undefined;\n });\n\n // if we found a miss (false) or no match (undefined),\n // then do not track the event\n if (!isMatch) {\n return false;\n }\n }\n\n // skip Amplitude network requests to \"[Amplitude] Network Request\" to avoid infinite loop\n if (networkEvent.requestWrapper && isAmplitudeNetworkRequestEvent(host, networkEvent.requestWrapper)) {\n return false;\n }\n\n return true;\n}\n\nexport type NetworkAnalyticsEvent = {\n ['[Amplitude] URL']: string;\n ['[Amplitude] URL Query']?: string;\n ['[Amplitude] URL Fragment']?: string;\n ['[Amplitude] Request Method']: string;\n ['[Amplitude] Status Code']?: number;\n ['[Amplitude] Start Time']?: number; // unix timestamp\n ['[Amplitude] Completion Time']?: number; // unix timestamp\n ['[Amplitude] Duration']?: number; // completionTime - startTime (millis)\n ['[Amplitude] Request Body Size']?: number;\n ['[Amplitude] Response Body Size']?: number;\n ['[Amplitude] Request Type']?: 'xhr' | 'fetch';\n};\n\nexport function trackNetworkEvents({\n allObservables,\n networkTrackingOptions,\n amplitude,\n}: {\n allObservables: AllWindowObservables;\n networkTrackingOptions: NetworkTrackingOptions;\n amplitude: BrowserClient;\n}) {\n const { networkObservable } = allObservables;\n\n const filteredNetworkObservable = networkObservable.pipe(\n filter((event: TimestampedEvent<NetworkRequestEvent>) => {\n // Only track network events that should be tracked,\n return shouldTrackNetworkEvent(event.event as NetworkRequestEvent, networkTrackingOptions);\n }),\n );\n\n return filteredNetworkObservable.subscribe((networkEvent) => {\n const request = networkEvent.event;\n\n // convert to NetworkAnalyticsEvent\n const urlObj = parseUrl(request.url);\n /* istanbul ignore if */\n if (!urlObj) {\n // if the URL failed to parse, do not track the event\n // this is a very unlikely case, because URL() shouldn't throw an exception\n // when the URL is a valid URL\n /* istanbul ignore next */\n return;\n }\n\n const responseBodySize = request.responseWrapper?.bodySize;\n /* istanbul ignore next */\n const requestBodySize = request.requestWrapper?.bodySize;\n\n const networkAnalyticsEvent: NetworkAnalyticsEvent = {\n ['[Amplitude] URL']: urlObj.hrefWithoutQueryOrHash,\n ['[Amplitude] URL Query']: urlObj.query,\n ['[Amplitude] URL Fragment']: urlObj.fragment,\n ['[Amplitude] Request Method']: request.method,\n ['[Amplitude] Status Code']: request.status,\n ['[Amplitude] Start Time']: request.startTime,\n ['[Amplitude] Completion Time']: request.endTime,\n ['[Amplitude] Duration']: request.duration,\n ['[Amplitude] Request Body Size']: requestBodySize,\n ['[Amplitude] Response Body Size']: responseBodySize,\n ['[Amplitude] Request Type']: request.type,\n };\n\n /* istanbul ignore next */\n amplitude?.track(AMPLITUDE_NETWORK_REQUEST_EVENT, networkAnalyticsEvent);\n });\n}\n"]}
|
|
1
|
+
{"version":3,"file":"track-network-event.js","sourceRoot":"","sources":["../../src/track-network-event.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n BrowserClient,\n NetworkRequestEvent,\n NetworkCaptureRule,\n NetworkTrackingOptions,\n getGlobalScope,\n JsonObject,\n isUrlMatchAllowlist,\n SAFE_HEADERS,\n} from '@amplitude/analytics-core';\nimport { filter } from 'rxjs';\nimport { AllWindowObservables, TimestampedEvent } from './network-capture-plugin';\nimport { AMPLITUDE_NETWORK_REQUEST_EVENT, IS_HEADER_CAPTURE_EXPERIMENTAL } from './constants';\nimport { IRequestWrapper } from '@amplitude/analytics-core';\nimport { BodyCaptureRule } from '@amplitude/analytics-core/lib/esm/types/network-tracking';\n\nconst DEFAULT_STATUS_CODE_RANGE = '500-599';\n\nfunction wildcardMatch(str: string, pattern: string) {\n // Escape all regex special characters except for *\n const escapedPattern = pattern.replace(/[-[\\]{}()+?.,\\\\^$|#\\s]/g, '\\\\$&');\n // Replace * with .*\n const regexPattern = '^' + escapedPattern.replace(/\\*/g, '.*') + '$';\n const regex = new RegExp(regexPattern);\n return regex.test(str);\n}\n\nfunction isStatusCodeInRange(statusCode: number, range: string) {\n const ranges = range.split(',');\n for (const r of ranges) {\n const [start, end] = r.split('-').map(Number);\n if (statusCode === start && end === undefined) {\n return true;\n }\n if (statusCode >= start && statusCode <= end) {\n return true;\n }\n }\n return false;\n}\n\nfunction isCaptureRuleMatch(\n rule: NetworkCaptureRule,\n hostname: string,\n status?: number,\n url?: string,\n method?: string,\n) {\n // check if the host is in the allowed hosts\n if (rule.hosts && !rule.hosts.find((host: string) => wildcardMatch(hostname, host))) {\n return;\n }\n\n // check if the URL is in the allowed URL patterns\n if (url && rule.urls && !isUrlMatchAllowlist(url, rule.urls)) {\n return;\n }\n\n // check if the method is in the allowed methods\n if (\n method &&\n rule.methods &&\n !rule.methods.find(\n (allowedMethod: string) => method.toLowerCase() === allowedMethod.toLowerCase() || allowedMethod === '*',\n )\n ) {\n return;\n }\n\n // check if the status code is in the allowed range\n if (status || status === 0) {\n const statusCodeRange = rule.statusCodeRange || DEFAULT_STATUS_CODE_RANGE;\n if (!isStatusCodeInRange(status, statusCodeRange)) {\n return false;\n }\n }\n\n return true;\n}\n\nfunction parseUrl(url: string | undefined) {\n if (!url) {\n return;\n }\n try {\n /* istanbul ignore next */\n const currentHref = getGlobalScope()?.location.href;\n const urlObj = new URL(url, currentHref);\n const query = urlObj.searchParams.toString();\n const fragment = urlObj.hash.replace('#', '');\n const href = urlObj.href;\n const host = urlObj.host;\n urlObj.hash = '';\n urlObj.search = '';\n const hrefWithoutQueryOrHash = urlObj.href;\n return { query, fragment, href, hrefWithoutQueryOrHash, host };\n } catch (e) {\n /* istanbul ignore next */\n return;\n }\n}\n\nfunction isAmplitudeNetworkRequestEvent(host: string, requestWrapper: IRequestWrapper): boolean {\n if (host.includes('amplitude.com')) {\n try {\n const body = requestWrapper.body;\n if (typeof body !== 'string') {\n return false;\n }\n const bodyObj = JSON.parse(body) as { events: any[] };\n const { events } = bodyObj;\n /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */\n if (events.find((event: any) => event.event_type === AMPLITUDE_NETWORK_REQUEST_EVENT)) {\n return true;\n }\n } catch (e) {\n // do nothing\n }\n }\n return false;\n}\n\n/**\n * Takes a user provided header capture rule and returns a\n * HeaderCaptureRule object that sets proper default values.\n *\n * @param rule - The header capture rule to parse.\n * @returns A HeaderCaptureRule object.\n */\nexport function parseHeaderCaptureRule(rule: string[] | boolean | undefined | null): string[] | undefined {\n if (typeof rule !== 'object' || rule === null) {\n // if rule is truthy or undefined, return SAFE_HEADERS\n if (rule) {\n return [...SAFE_HEADERS];\n } else if (rule === undefined) {\n /* istanbul ignore next */\n const res = IS_HEADER_CAPTURE_EXPERIMENTAL ? undefined : [...SAFE_HEADERS];\n return res;\n }\n return;\n }\n\n // if the rule is defined but empty, return undefined\n if (rule.length === 0) {\n return;\n }\n\n return rule;\n}\n\nfunction isBodyCaptureRuleEmpty(rule: BodyCaptureRule) {\n /* istanbul ignore next */\n return !rule?.allowlist?.length && !rule?.blocklist?.length;\n}\n\nexport function shouldTrackNetworkEvent(networkEvent: NetworkRequestEvent, options: NetworkTrackingOptions = {}) {\n const urlObj = parseUrl(networkEvent.url);\n /* istanbul ignore if */\n if (!urlObj) {\n // if the URL failed to parse, do not track the event\n // this is a probably impossible case that would only happen if the URL is malformed\n /* istanbul ignore next */\n return false;\n }\n const { host } = urlObj;\n\n // false if is amplitude request and not configured to track amplitude requests\n if (\n options.ignoreAmplitudeRequests !== false &&\n (wildcardMatch(host, '*.amplitude.com') || wildcardMatch(host, 'amplitude.com'))\n ) {\n return false;\n }\n\n // false if the host is in the ignore list\n if (options.ignoreHosts?.find((ignoreHost: string) => wildcardMatch(host, ignoreHost))) {\n return false;\n }\n\n // false if the status code is not 500-599 and there are no captureRules\n if (\n !options.captureRules &&\n networkEvent.status !== undefined &&\n !isStatusCodeInRange(networkEvent.status, DEFAULT_STATUS_CODE_RANGE)\n ) {\n return false;\n }\n\n if (options.captureRules) {\n // find the first capture rule, in reverse-order,\n // that is a match (true) or a miss (false)\n let isMatch: boolean | undefined;\n [...options.captureRules].reverse().find((rule) => {\n isMatch = isCaptureRuleMatch(rule, host, networkEvent.status, networkEvent.url, networkEvent.method);\n\n if (isMatch) {\n const responseHeadersRule = parseHeaderCaptureRule(rule.responseHeaders);\n if (networkEvent.responseWrapper && responseHeadersRule) {\n const responseHeaders = networkEvent.responseWrapper.headers(responseHeadersRule);\n if (responseHeaders) {\n networkEvent.responseHeaders = responseHeaders;\n }\n }\n\n // if requestHeaders rule is specified, enrich the event with the request headers\n const requestHeadersRule = parseHeaderCaptureRule(rule.requestHeaders);\n if (networkEvent.requestWrapper && requestHeadersRule) {\n const requestHeaders = networkEvent.requestWrapper.headers(requestHeadersRule);\n if (requestHeaders) {\n networkEvent.requestHeaders = requestHeaders;\n }\n }\n\n // if responseBody rule is specified, enrich the event with the response body\n if (networkEvent.responseWrapper && rule.responseBody && !isBodyCaptureRuleEmpty(rule.responseBody)) {\n networkEvent.responseBodyJson = networkEvent.responseWrapper.json(\n rule.responseBody.allowlist,\n rule.responseBody.blocklist,\n );\n }\n\n // if requestBody rule is specified, enrich the event with the request body\n if (networkEvent.requestWrapper && rule.requestBody && !isBodyCaptureRuleEmpty(rule.requestBody)) {\n networkEvent.requestBodyJson = networkEvent.requestWrapper.json(\n rule.requestBody.allowlist,\n rule.requestBody.blocklist,\n );\n }\n }\n\n return isMatch !== undefined;\n });\n\n // if we found a miss (false) or no match (undefined),\n // then do not track the event\n if (!isMatch) {\n return false;\n }\n }\n\n // skip Amplitude network requests to \"[Amplitude] Network Request\" to avoid infinite loop\n if (networkEvent.requestWrapper && isAmplitudeNetworkRequestEvent(host, networkEvent.requestWrapper)) {\n return false;\n }\n\n return true;\n}\n\nexport type NetworkAnalyticsEvent = {\n ['[Amplitude] URL']: string;\n ['[Amplitude] URL Query']?: string;\n ['[Amplitude] URL Fragment']?: string;\n ['[Amplitude] Request Method']: string;\n ['[Amplitude] Status Code']?: number;\n ['[Amplitude] Start Time']?: number; // unix timestamp\n ['[Amplitude] Completion Time']?: number; // unix timestamp\n ['[Amplitude] Duration']?: number; // completionTime - startTime (millis)\n ['[Amplitude] Request Body Size']?: number;\n ['[Amplitude] Request Headers']?: Record<string, string>;\n ['[Amplitude] Request Body']?: JsonObject;\n ['[Amplitude] Response Body Size']?: number;\n ['[Amplitude] Response Headers']?: Record<string, string>;\n ['[Amplitude] Response Body']?: JsonObject;\n ['[Amplitude] Request Type']?: 'xhr' | 'fetch';\n};\n\nexport async function logNetworkAnalyticsEvent(\n networkAnalyticsEvent: NetworkAnalyticsEvent,\n request: NetworkRequestEvent,\n amplitude: BrowserClient,\n) {\n if (request.requestBodyJson || request.responseBodyJson) {\n const [requestBody, responseBody] = await Promise.all([request.requestBodyJson, request.responseBodyJson]);\n if (requestBody) {\n networkAnalyticsEvent['[Amplitude] Request Body'] = requestBody;\n }\n if (responseBody) {\n networkAnalyticsEvent['[Amplitude] Response Body'] = responseBody;\n }\n }\n /* istanbul ignore next */\n amplitude?.track(AMPLITUDE_NETWORK_REQUEST_EVENT, networkAnalyticsEvent);\n}\n\nexport function trackNetworkEvents({\n allObservables,\n networkTrackingOptions,\n amplitude,\n}: {\n allObservables: AllWindowObservables;\n networkTrackingOptions: NetworkTrackingOptions;\n amplitude: BrowserClient;\n}) {\n const { networkObservable } = allObservables;\n\n const filteredNetworkObservable = networkObservable.pipe(\n filter((event: TimestampedEvent<NetworkRequestEvent>) => {\n // Only track network events that should be tracked,\n return shouldTrackNetworkEvent(event.event as NetworkRequestEvent, networkTrackingOptions);\n }),\n );\n\n return filteredNetworkObservable.subscribe((networkEvent) => {\n const request = networkEvent.event;\n\n // convert to NetworkAnalyticsEvent\n const urlObj = parseUrl(request.url);\n /* istanbul ignore if */\n if (!urlObj) {\n // if the URL failed to parse, do not track the event\n // this is a very unlikely case, because URL() shouldn't throw an exception\n // when the URL is a valid URL\n /* istanbul ignore next */\n return;\n }\n\n const responseBodySize = request.responseWrapper?.bodySize;\n /* istanbul ignore next */\n const requestBodySize = request.requestWrapper?.bodySize;\n\n const networkAnalyticsEvent: NetworkAnalyticsEvent = {\n ['[Amplitude] URL']: urlObj.hrefWithoutQueryOrHash,\n ['[Amplitude] URL Query']: urlObj.query,\n ['[Amplitude] URL Fragment']: urlObj.fragment,\n ['[Amplitude] Request Method']: request.method,\n ['[Amplitude] Status Code']: request.status,\n ['[Amplitude] Start Time']: request.startTime,\n ['[Amplitude] Completion Time']: request.endTime,\n ['[Amplitude] Duration']: request.duration,\n ['[Amplitude] Request Body Size']: requestBodySize,\n ['[Amplitude] Response Body Size']: responseBodySize,\n ['[Amplitude] Request Type']: request.type,\n ['[Amplitude] Request Headers']: request.requestHeaders,\n ['[Amplitude] Response Headers']: request.responseHeaders,\n };\n\n // fire-and-forget promise that tracks the event\n void logNetworkAnalyticsEvent(networkAnalyticsEvent, request, amplitude);\n });\n}\n"]}
|
package/lib/esm/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.5.0";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|