@amplitude/analytics-core
Version:
175 lines • 7.41 kB
JavaScript
import { __awaiter, __generator, __read, __values } from "tslib";
import { getGlobalScope } from './global-scope';
import { UUID } from './utils/uuid';
var MAXIMUM_ENTRIES = 100;
export function getRequestBodyLength(body) {
var e_1, _a;
var global = 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 = __values(formData.entries()), _c = _b.next(); !_c.done; _c = _b.next()) {
var _d = __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;
}
var NetworkEventCallback = /** @class */ (function () {
function NetworkEventCallback(callback, id) {
if (id === void 0) { id = UUID(); }
this.callback = callback;
this.id = id;
}
return NetworkEventCallback;
}());
export { NetworkEventCallback };
var NetworkObserver = /** @class */ (function () {
function NetworkObserver(logger) {
var _a;
this.eventCallbacks = new Map();
this.isObserving = false;
var globalScope = 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 = 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 __awaiter(_this, void 0, void 0, function () {
var startTime, requestEvent, response, endTime, headers_1, contentLength_1, error_1, endTime, typedError;
return __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;
}());
export { NetworkObserver };
// singleton instance of NetworkObserver
export var networkObserver = new NetworkObserver();
//# sourceMappingURL=network-observer.js.map