UNPKG

@amplitude/analytics-core

Version:
179 lines 7.75 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.networkObserver = exports.NetworkObserver = exports.NetworkEventCallback = exports.getRequestBodyLength = void 0; var tslib_1 = require("tslib"); var global_scope_1 = require("./global-scope"); var uuid_1 = require("./utils/uuid"); var MAXIMUM_ENTRIES = 100; function getRequestBodyLength(body) { var e_1, _a; var global = (0, global_scope_1.getGlobalScope)(); if (!(global === null || global === void 0 ? void 0 : global.TextEncoder)) { return; } var TextEncoder = global.TextEncoder; if (typeof body === 'string') { return new TextEncoder().encode(body).length; } else if (body instanceof Blob) { return body.size; } else if (body instanceof URLSearchParams) { return new TextEncoder().encode(body.toString()).length; } else if (body instanceof ArrayBuffer) { return body.byteLength; } else if (ArrayBuffer.isView(body)) { return body.byteLength; } else if (body instanceof FormData) { // Estimating only for text parts; not accurate for files var formData = body; var total = 0; var count = 0; try { for (var _b = tslib_1.__values(formData.entries()), _c = _b.next(); !_c.done; _c = _b.next()) { var _d = tslib_1.__read(_c.value, 2), key = _d[0], value = _d[1]; total += key.length; if (typeof value === 'string') { total += new TextEncoder().encode(value).length; } else if (value.size) { // if we encounter a "File" type, we should not count it and just return undefined total += value.size; } // terminate if we reach the maximum number of entries // to avoid performance issues in case of very large FormDataß if (++count >= MAXIMUM_ENTRIES) { return; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (_c && !_c.done && (_a = _b.return)) _a.call(_b); } finally { if (e_1) throw e_1.error; } } return total; } // Stream or unknown return; } exports.getRequestBodyLength = getRequestBodyLength; var NetworkEventCallback = /** @class */ (function () { function NetworkEventCallback(callback, id) { if (id === void 0) { id = (0, uuid_1.UUID)(); } this.callback = callback; this.id = id; } return NetworkEventCallback; }()); exports.NetworkEventCallback = NetworkEventCallback; var NetworkObserver = /** @class */ (function () { function NetworkObserver(logger) { var _a; this.eventCallbacks = new Map(); this.isObserving = false; var globalScope = (0, global_scope_1.getGlobalScope)(); if (!NetworkObserver.isSupported()) { /* istanbul ignore next */ logger === null || logger === void 0 ? void 0 : logger.error('Fetch API is not supported in this environment.'); return; } this.globalScope = globalScope; /* istanbul ignore next */ this.originalFetch = (_a = this.globalScope) === null || _a === void 0 ? void 0 : _a.fetch; } NetworkObserver.isSupported = function () { var globalScope = (0, global_scope_1.getGlobalScope)(); return !!globalScope && !!globalScope.fetch; }; NetworkObserver.prototype.subscribe = function (eventCallback) { this.eventCallbacks.set(eventCallback.id, eventCallback); if (!this.isObserving) { this.observeFetch(); this.isObserving = true; } }; NetworkObserver.prototype.unsubscribe = function (eventCallback) { this.eventCallbacks.delete(eventCallback.id); if (this.originalFetch && this.globalScope && this.eventCallbacks.size === 0 && this.isObserving) { this.globalScope.fetch = this.originalFetch; this.isObserving = false; } }; NetworkObserver.prototype.triggerEventCallbacks = function (event) { this.eventCallbacks.forEach(function (callback) { callback.callback(event); }); }; NetworkObserver.prototype.observeFetch = function () { var _this = this; /* istanbul ignore next */ if (!this.globalScope || !this.originalFetch) { return; } var originalFetch = this.globalScope.fetch; this.globalScope.fetch = function (input, init) { return tslib_1.__awaiter(_this, void 0, void 0, function () { var startTime, requestEvent, response, endTime, headers_1, contentLength_1, error_1, endTime, typedError; return tslib_1.__generator(this, function (_a) { switch (_a.label) { case 0: startTime = Date.now(); requestEvent = { timestamp: startTime, startTime: startTime, type: 'fetch', method: (init === null || init === void 0 ? void 0 : init.method) || 'GET', url: input.toString(), requestHeaders: init === null || init === void 0 ? void 0 : init.headers, requestBodySize: getRequestBodyLength(init === null || init === void 0 ? void 0 : init.body), }; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, originalFetch(input, init)]; case 2: response = _a.sent(); endTime = Date.now(); requestEvent.status = response.status; requestEvent.duration = endTime - startTime; requestEvent.startTime = startTime; requestEvent.endTime = endTime; headers_1 = {}; contentLength_1 = undefined; response.headers.forEach(function (value, key) { headers_1[key] = value; if (key === 'content-length') { contentLength_1 = parseInt(value, 10) || undefined; } }); requestEvent.responseHeaders = headers_1; requestEvent.responseBodySize = contentLength_1; this.triggerEventCallbacks(requestEvent); return [2 /*return*/, response]; case 3: error_1 = _a.sent(); endTime = Date.now(); requestEvent.duration = endTime - startTime; typedError = error_1; requestEvent.error = { name: typedError.name || 'UnknownError', message: typedError.message || 'An unknown error occurred', }; this.triggerEventCallbacks(requestEvent); throw error_1; case 4: return [2 /*return*/]; } }); }); }; }; return NetworkObserver; }()); exports.NetworkObserver = NetworkObserver; // singleton instance of NetworkObserver exports.networkObserver = new NetworkObserver(); //# sourceMappingURL=network-observer.js.map