UNPKG

sentry-wechat-miniprogram

Version:
1,539 lines (1,515 loc) 186 kB
/*! * sentry-wechat-miniprogram v0.0.0 * (c) Jay Fong <fjc0kb@gmail.com> (https://github.com/fjc0k) * Released under the MIT License. */ /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spread() { for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i])); return ar; } /** Console logging verbosity for the SDK. */ var LogLevel; (function (LogLevel) { /** No logs will be generated. */ LogLevel[LogLevel["None"] = 0] = "None"; /** Only SDK internal errors will be logged. */ LogLevel[LogLevel["Error"] = 1] = "Error"; /** Information useful for debugging the SDK will be logged. */ LogLevel[LogLevel["Debug"] = 2] = "Debug"; /** All SDK actions will be logged. */ LogLevel[LogLevel["Verbose"] = 3] = "Verbose"; })(LogLevel || (LogLevel = {})); /** JSDoc */ var Severity; (function (Severity) { /** JSDoc */ Severity["Fatal"] = "fatal"; /** JSDoc */ Severity["Error"] = "error"; /** JSDoc */ Severity["Warning"] = "warning"; /** JSDoc */ Severity["Log"] = "log"; /** JSDoc */ Severity["Info"] = "info"; /** JSDoc */ Severity["Debug"] = "debug"; /** JSDoc */ Severity["Critical"] = "critical"; })(Severity || (Severity = {})); // tslint:disable:completed-docs // tslint:disable:no-unnecessary-qualifier no-namespace (function (Severity) { /** * Converts a string-based level into a {@link Severity}. * * @param level string representation of Severity * @returns Severity */ function fromString(level) { switch (level) { case 'debug': return Severity.Debug; case 'info': return Severity.Info; case 'warn': case 'warning': return Severity.Warning; case 'error': return Severity.Error; case 'fatal': return Severity.Fatal; case 'critical': return Severity.Critical; case 'log': default: return Severity.Log; } } Severity.fromString = fromString; })(Severity || (Severity = {})); /** The status of an event. */ var Status; (function (Status) { /** The status could not be determined. */ Status["Unknown"] = "unknown"; /** The event was skipped due to configuration or callbacks. */ Status["Skipped"] = "skipped"; /** The event was sent to Sentry successfully. */ Status["Success"] = "success"; /** The client is currently rate limited and will try again later. */ Status["RateLimit"] = "rate_limit"; /** The event could not be processed. */ Status["Invalid"] = "invalid"; /** A server-side error ocurred during submission. */ Status["Failed"] = "failed"; })(Status || (Status = {})); // tslint:disable:completed-docs // tslint:disable:no-unnecessary-qualifier no-namespace (function (Status) { /** * Converts a HTTP status code into a {@link Status}. * * @param code The HTTP response status code. * @returns The send status or {@link Status.Unknown}. */ function fromHttpCode(code) { if (code >= 200 && code < 300) { return Status.Success; } if (code === 429) { return Status.RateLimit; } if (code >= 400 && code < 500) { return Status.Invalid; } if (code >= 500) { return Status.Failed; } return Status.Unknown; } Status.fromHttpCode = fromHttpCode; })(Status || (Status = {})); var setPrototypeOf = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array ? setProtoOf : mixinProperties); // tslint:disable-line:no-unbound-method /** * setPrototypeOf polyfill using __proto__ */ function setProtoOf(obj, proto) { // @ts-ignore obj.__proto__ = proto; return obj; } /** * setPrototypeOf polyfill using mixin */ function mixinProperties(obj, proto) { for (var prop in proto) { if (!obj.hasOwnProperty(prop)) { // @ts-ignore obj[prop] = proto[prop]; } } return obj; } /** An error emitted by Sentry SDKs and related utilities. */ var SentryError = /** @class */ (function (_super) { __extends(SentryError, _super); function SentryError(message) { var _newTarget = this.constructor; var _this = _super.call(this, message) || this; _this.message = message; // tslint:disable:no-unsafe-any _this.name = _newTarget.prototype.constructor.name; setPrototypeOf(_this, _newTarget.prototype); return _this; } return SentryError; }(Error)); /** * Checks whether given value's type is one of a few Error or Error-like * {@link isError}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isError(wat) { switch (Object.prototype.toString.call(wat)) { case '[object Error]': return true; case '[object Exception]': return true; case '[object DOMException]': return true; default: return wat instanceof Error; } } /** * Checks whether given value's type is ErrorEvent * {@link isErrorEvent}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isErrorEvent(wat) { return Object.prototype.toString.call(wat) === '[object ErrorEvent]'; } /** * Checks whether given value's type is a string * {@link isString}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isString(wat) { return Object.prototype.toString.call(wat) === '[object String]'; } /** * Checks whether given value's is a primitive (undefined, null, number, boolean, string) * {@link isPrimitive}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isPrimitive(wat) { return wat === null || (typeof wat !== 'object' && typeof wat !== 'function'); } /** * Checks whether given value's type is an object literal * {@link isPlainObject}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isPlainObject(wat) { return Object.prototype.toString.call(wat) === '[object Object]'; } /** * Checks whether given value's type is an regexp * {@link isRegExp}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isRegExp(wat) { return Object.prototype.toString.call(wat) === '[object RegExp]'; } /** * Checks whether given value has a then function. * @param wat A value to be checked. */ function isThenable(wat) { // tslint:disable:no-unsafe-any return Boolean(wat && wat.then && typeof wat.then === 'function'); // tslint:enable:no-unsafe-any } /** * Checks whether given value's type is a SyntheticEvent * {@link isSyntheticEvent}. * * @param wat A value to be checked. * @returns A boolean representing the result. */ function isSyntheticEvent(wat) { // tslint:disable-next-line:no-unsafe-any return isPlainObject(wat) && 'nativeEvent' in wat && 'preventDefault' in wat && 'stopPropagation' in wat; } /** * Requires a module which is protected _against bundler minification. * * @param request The module path to resolve */ function dynamicRequire(mod, request) { // tslint:disable-next-line: no-unsafe-any return mod.require(request); } /** * Checks whether we're in the Node.js or Browser environment * * @returns Answer to given question */ function isNodeEnv() { // tslint:disable:strict-type-predicates return Object.prototype.toString.call(typeof process !== 'undefined' ? process : 0) === '[object process]'; } var fallbackGlobalObject = {}; /** * Safely get global scope object * * @returns Global scope object */ function getGlobalObject() { return (isNodeEnv() ? global : typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : fallbackGlobalObject); } /** * UUID4 generator * * @returns string Generated UUID4. */ function uuid4() { var global = getGlobalObject(); var crypto = global.crypto || global.msCrypto; if (!(crypto === void 0) && crypto.getRandomValues) { // Use window.crypto API if available var arr = new Uint16Array(8); crypto.getRandomValues(arr); // set 4 in byte 7 // tslint:disable-next-line:no-bitwise arr[3] = (arr[3] & 0xfff) | 0x4000; // set 2 most significant bits of byte 9 to '10' // tslint:disable-next-line:no-bitwise arr[4] = (arr[4] & 0x3fff) | 0x8000; var pad = function (num) { var v = num.toString(16); while (v.length < 4) { v = "0" + v; } return v; }; return (pad(arr[0]) + pad(arr[1]) + pad(arr[2]) + pad(arr[3]) + pad(arr[4]) + pad(arr[5]) + pad(arr[6]) + pad(arr[7])); } // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 return 'xxxxxxxxxxxx4xxxyxxxxxxxxxxxxxxx'.replace(/[xy]/g, function (c) { // tslint:disable-next-line:no-bitwise var r = (Math.random() * 16) | 0; // tslint:disable-next-line:no-bitwise var v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); }); } /** * Parses string form of URL into an object * // borrowed from https://tools.ietf.org/html/rfc3986#appendix-B * // intentionally using regex and not <a/> href parsing trick because React Native and other * // environments where DOM might not be available * @returns parsed URL object */ function parseUrl(url) { if (!url) { return {}; } var match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?$/); if (!match) { return {}; } // coerce to undefined values to empty string so we don't get 'undefined' var query = match[6] || ''; var fragment = match[8] || ''; return { host: match[4], path: match[5], protocol: match[2], relative: match[5] + query + fragment, }; } /** * Extracts either message or type+value from an event that can be used for user-facing logs * @returns event's description */ function getEventDescription(event) { if (event.message) { return event.message; } if (event.exception && event.exception.values && event.exception.values[0]) { var exception = event.exception.values[0]; if (exception.type && exception.value) { return exception.type + ": " + exception.value; } return exception.type || exception.value || event.event_id || '<unknown>'; } return event.event_id || '<unknown>'; } /** JSDoc */ function consoleSandbox(callback) { var global = getGlobalObject(); var levels = ['debug', 'info', 'warn', 'error', 'log', 'assert']; if (!('console' in global)) { return callback(); } var originalConsole = global.console; var wrappedLevels = {}; // Restore all wrapped console methods levels.forEach(function (level) { if (level in global.console && originalConsole[level].__sentry__) { wrappedLevels[level] = originalConsole[level].__sentry_wrapped__; originalConsole[level] = originalConsole[level].__sentry_original__; } }); // Perform callback manipulations var result = callback(); // Revert restoration to wrapped state Object.keys(wrappedLevels).forEach(function (level) { originalConsole[level] = wrappedLevels[level]; }); return result; } /** * Adds exception values, type and value to an synthetic Exception. * @param event The event to modify. * @param value Value of the exception. * @param type Type of the exception. * @param mechanism Mechanism of the exception. * @hidden */ function addExceptionTypeValue(event, value, type, mechanism) { if (mechanism === void 0) { mechanism = { handled: true, type: 'generic', }; } event.exception = event.exception || {}; event.exception.values = event.exception.values || []; event.exception.values[0] = event.exception.values[0] || {}; event.exception.values[0].value = event.exception.values[0].value || value || ''; event.exception.values[0].type = event.exception.values[0].type || type || 'Error'; event.exception.values[0].mechanism = event.exception.values[0].mechanism || mechanism; } // TODO: Implement different loggers for different environments var global$1 = getGlobalObject(); /** Prefix for logging strings */ var PREFIX = 'Sentry Logger '; /** JSDoc */ var Logger = /** @class */ (function () { /** JSDoc */ function Logger() { this._enabled = false; } /** JSDoc */ Logger.prototype.disable = function () { this._enabled = false; }; /** JSDoc */ Logger.prototype.enable = function () { this._enabled = true; }; /** JSDoc */ Logger.prototype.log = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!this._enabled) { return; } consoleSandbox(function () { global$1.console.log(PREFIX + "[Log]: " + args.join(' ')); // tslint:disable-line:no-console }); }; /** JSDoc */ Logger.prototype.warn = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!this._enabled) { return; } consoleSandbox(function () { global$1.console.warn(PREFIX + "[Warn]: " + args.join(' ')); // tslint:disable-line:no-console }); }; /** JSDoc */ Logger.prototype.error = function () { var args = []; for (var _i = 0; _i < arguments.length; _i++) { args[_i] = arguments[_i]; } if (!this._enabled) { return; } consoleSandbox(function () { global$1.console.error(PREFIX + "[Error]: " + args.join(' ')); // tslint:disable-line:no-console }); }; return Logger; }()); // Ensure we only have a single logger instance, even if multiple versions of @sentry/utils are being used global$1.__SENTRY__ = global$1.__SENTRY__ || {}; var logger = global$1.__SENTRY__.logger || (global$1.__SENTRY__.logger = new Logger()); // tslint:disable:no-unsafe-any /** * Memo class used for decycle json objects. Uses WeakSet if available otherwise array. */ var Memo = /** @class */ (function () { function Memo() { // tslint:disable-next-line this._hasWeakSet = typeof WeakSet === 'function'; this._inner = this._hasWeakSet ? new WeakSet() : []; } /** * Sets obj to remember. * @param obj Object to remember */ Memo.prototype.memoize = function (obj) { if (this._hasWeakSet) { if (this._inner.has(obj)) { return true; } this._inner.add(obj); return false; } // tslint:disable-next-line:prefer-for-of for (var i = 0; i < this._inner.length; i++) { var value = this._inner[i]; if (value === obj) { return true; } } this._inner.push(obj); return false; }; /** * Removes object from internal storage. * @param obj Object to forget */ Memo.prototype.unmemoize = function (obj) { if (this._hasWeakSet) { this._inner.delete(obj); } else { for (var i = 0; i < this._inner.length; i++) { if (this._inner[i] === obj) { this._inner.splice(i, 1); break; } } } }; return Memo; }()); /** * Wrap a given object method with a higher-order function * * @param source An object that contains a method to be wrapped. * @param name A name of method to be wrapped. * @param replacement A function that should be used to wrap a given method. * @returns void */ function fill(source, name, replacement) { if (!(name in source)) { return; } var original = source[name]; var wrapped = replacement(original); // Make sure it's a function first, as we need to attach an empty prototype for `defineProperties` to work // otherwise it'll throw "TypeError: Object.defineProperties called on non-object" // tslint:disable-next-line:strict-type-predicates if (typeof wrapped === 'function') { try { wrapped.prototype = wrapped.prototype || {}; Object.defineProperties(wrapped, { __sentry__: { enumerable: false, value: true, }, __sentry_original__: { enumerable: false, value: original, }, __sentry_wrapped__: { enumerable: false, value: wrapped, }, }); } catch (_Oo) { // This can throw if multiple fill happens on a global object like XMLHttpRequest // Fixes https://github.com/getsentry/sentry-javascript/issues/2043 } } source[name] = wrapped; } /** * Encodes given object into url-friendly format * * @param object An object that contains serializable values * @returns string Encoded */ function urlEncode(object) { return Object.keys(object) .map( // tslint:disable-next-line:no-unsafe-any function (key) { return encodeURIComponent(key) + "=" + encodeURIComponent(object[key]); }) .join('&'); } /** * Transforms Error object into an object literal with all it's attributes * attached to it. * * Based on: https://github.com/ftlabs/js-abbreviate/blob/fa709e5f139e7770a71827b1893f22418097fbda/index.js#L95-L106 * * @param error An Error containing all relevant information * @returns An object with all error properties */ function objectifyError(error) { // These properties are implemented as magical getters and don't show up in `for-in` loop var err = { message: error.message, name: error.name, stack: error.stack, }; for (var i in error) { if (Object.prototype.hasOwnProperty.call(error, i)) { err[i] = error[i]; } } return err; } /** Calculates bytes size of input string */ function utf8Length(value) { // tslint:disable-next-line:no-bitwise return ~-encodeURI(value).split(/%..|./).length; } /** Calculates bytes size of input object */ function jsonSize(value) { return utf8Length(JSON.stringify(value)); } /** JSDoc */ function normalizeToSize(object, // Default Node.js REPL depth depth, // 100kB, as 200kB is max payload size, so half sounds reasonable maxSize) { if (depth === void 0) { depth = 3; } if (maxSize === void 0) { maxSize = 100 * 1024; } var serialized = normalize(object, depth); if (jsonSize(serialized) > maxSize) { return normalizeToSize(object, depth - 1, maxSize); } return serialized; } /** Transforms any input value into a string form, either primitive value or a type of the input */ function serializeValue(value) { var type = Object.prototype.toString.call(value); // Node.js REPL notation if (typeof value === 'string') { return value; } if (type === '[object Object]') { return '[Object]'; } if (type === '[object Array]') { return '[Array]'; } var normalized = normalizeValue(value); return isPrimitive(normalized) ? normalized : type; } /** * normalizeValue() * * Takes unserializable input and make it serializable friendly * * - translates undefined/NaN values to "[undefined]"/"[NaN]" respectively, * - serializes Error objects * - filter global objects */ function normalizeValue(value, key) { if (key === 'domain' && typeof value === 'object' && value._events) { return '[Domain]'; } if (key === 'domainEmitter') { return '[DomainEmitter]'; } if (typeof global !== 'undefined' && value === global) { return '[Global]'; } if (typeof window !== 'undefined' && value === window) { return '[Window]'; } if (typeof document !== 'undefined' && value === document) { return '[Document]'; } // tslint:disable-next-line:strict-type-predicates if (typeof Event !== 'undefined' && value instanceof Event) { return Object.getPrototypeOf(value) ? value.constructor.name : 'Event'; } // React's SyntheticEvent thingy if (isSyntheticEvent(value)) { return '[SyntheticEvent]'; } if (Number.isNaN(value)) { return '[NaN]'; } if (value === void 0) { return '[undefined]'; } if (typeof value === 'function') { return "[Function: " + (value.name || '<unknown-function-name>') + "]"; } return value; } /** * Walks an object to perform a normalization on it * * @param key of object that's walked in current iteration * @param value object to be walked * @param depth Optional number indicating how deep should walking be performed * @param memo Optional Memo class handling decycling */ function walk(key, value, depth, memo) { if (depth === void 0) { depth = +Infinity; } if (memo === void 0) { memo = new Memo(); } // If we reach the maximum depth, serialize whatever has left if (depth === 0) { return serializeValue(value); } // If value implements `toJSON` method, call it and return early // tslint:disable:no-unsafe-any if (value !== null && value !== undefined && typeof value.toJSON === 'function') { return value.toJSON(); } // tslint:enable:no-unsafe-any // If normalized value is a primitive, there are no branches left to walk, so we can just bail out, as theres no point in going down that branch any further var normalized = normalizeValue(value, key); if (isPrimitive(normalized)) { return normalized; } // Create source that we will use for next itterations, either objectified error object (Error type with extracted keys:value pairs) or the input itself var source = (isError(value) ? objectifyError(value) : value); // Create an accumulator that will act as a parent for all future itterations of that branch var acc = Array.isArray(value) ? [] : {}; // If we already walked that branch, bail out, as it's circular reference if (memo.memoize(value)) { return '[Circular ~]'; } // Walk all keys of the source for (var innerKey in source) { // Avoid iterating over fields in the prototype if they've somehow been exposed to enumeration. if (!Object.prototype.hasOwnProperty.call(source, innerKey)) { continue; } // Recursively walk through all the child nodes acc[innerKey] = walk(innerKey, source[innerKey], depth - 1, memo); } // Once walked through all the branches, remove the parent from memo storage memo.unmemoize(value); // Return accumulated values return acc; } /** * normalize() * * - Creates a copy to prevent original input mutation * - Skip non-enumerablers * - Calls `toJSON` if implemented * - Removes circular references * - Translates non-serializeable values (undefined/NaN/Functions) to serializable format * - Translates known global objects/Classes to a string representations * - Takes care of Error objects serialization * - Optionally limit depth of final output */ function normalize(input, depth) { try { // tslint:disable-next-line:no-unsafe-any return JSON.parse(JSON.stringify(input, function (key, value) { return walk(key, value, depth); })); } catch (_oO) { return '**non-serializable**'; } } // Slightly modified (no IE8 support, ES6) and transcribed to TypeScript /** A simple queue that holds promises. */ var PromiseBuffer = /** @class */ (function () { function PromiseBuffer(_limit) { this._limit = _limit; /** Internal set of queued Promises */ this._buffer = []; } /** * Says if the buffer is ready to take more requests */ PromiseBuffer.prototype.isReady = function () { return this._limit === undefined || this.length() < this._limit; }; /** * Add a promise to the queue. * * @param task Can be any Promise<T> * @returns The original promise. */ PromiseBuffer.prototype.add = function (task) { var _this = this; if (!this.isReady()) { return Promise.reject(new SentryError('Not adding Promise due to buffer limit reached.')); } if (this._buffer.indexOf(task) === -1) { this._buffer.push(task); } task .then(function () { return _this.remove(task); }) .catch(function () { return _this.remove(task).catch(function () { // We have to add this catch here otherwise we have an unhandledPromiseRejection // because it's a new Promise chain. }); }); return task; }; /** * Remove a promise to the queue. * * @param task Can be any Promise<T> * @returns Removed promise. */ PromiseBuffer.prototype.remove = function (task) { var removedTask = this._buffer.splice(this._buffer.indexOf(task), 1)[0]; return removedTask; }; /** * This function returns the number of unresolved promises in the queue. */ PromiseBuffer.prototype.length = function () { return this._buffer.length; }; /** * This will drain the whole queue, returns true if queue is empty or drained. * If timeout is provided and the queue takes longer to drain, the promise still resolves but with false. * * @param timeout Number in ms to wait until it resolves with false. */ PromiseBuffer.prototype.drain = function (timeout) { var _this = this; return new Promise(function (resolve) { var capturedSetTimeout = setTimeout(function () { if (timeout && timeout > 0) { resolve(false); } }, timeout); Promise.all(_this._buffer) .then(function () { clearTimeout(capturedSetTimeout); resolve(true); }) .catch(function () { resolve(true); }); }); }; return PromiseBuffer; }()); /** * Truncates given string to the maximum characters count * * @param str An object that contains serializable values * @param max Maximum number of characters in truncated string * @returns string Encoded */ function truncate(str, max) { if (max === void 0) { max = 0; } // tslint:disable-next-line:strict-type-predicates if (typeof str !== 'string' || max === 0) { return str; } return str.length <= max ? str : str.substr(0, max) + "..."; } /** * Join values in array * @param input array of values to be joined together * @param delimiter string to be placed in-between values * @returns Joined values */ function safeJoin(input, delimiter) { if (!Array.isArray(input)) { return ''; } var output = []; // tslint:disable-next-line:prefer-for-of for (var i = 0; i < input.length; i++) { var value = input[i]; try { output.push(String(value)); } catch (e) { output.push('[value cannot be serialized]'); } } return output.join(delimiter); } /** Merges provided array of keys into */ function keysToEventMessage(keys, maxLength) { if (maxLength === void 0) { maxLength = 40; } if (!keys.length) { return '[object has no keys]'; } if (keys[0].length >= maxLength) { return truncate(keys[0], maxLength); } for (var includedKeys = keys.length; includedKeys > 0; includedKeys--) { var serialized = keys.slice(0, includedKeys).join(', '); if (serialized.length > maxLength) { continue; } if (includedKeys === keys.length) { return serialized; } return truncate(serialized, maxLength); } return ''; } /** * Checks if the value matches a regex or includes the string * @param value The string value to be checked against * @param pattern Either a regex or a string that must be contained in value */ function isMatchingPattern(value, pattern) { if (isRegExp(pattern)) { return pattern.test(value); } if (typeof pattern === 'string') { return value.includes(pattern); } return false; } /** * Tells whether current environment supports Fetch API * {@link supportsFetch}. * * @returns Answer to the given question. */ function supportsFetch() { if (!('fetch' in getGlobalObject())) { return false; } try { // tslint:disable-next-line:no-unused-expression new Headers(); // tslint:disable-next-line:no-unused-expression new Request(''); // tslint:disable-next-line:no-unused-expression new Response(); return true; } catch (e) { return false; } } /** * Tells whether current environment supports Fetch API natively * {@link supportsNativeFetch}. * * @returns true if `window.fetch` is natively implemented, false otherwise */ function supportsNativeFetch() { if (!supportsFetch()) { return false; } var isNativeFunc = function (func) { return func.toString().indexOf('native') !== -1; }; var global = getGlobalObject(); var result = null; var doc = global.document; if (doc) { var sandbox = doc.createElement('iframe'); sandbox.hidden = true; try { doc.head.appendChild(sandbox); if (sandbox.contentWindow && sandbox.contentWindow.fetch) { // tslint:disable-next-line no-unbound-method result = isNativeFunc(sandbox.contentWindow.fetch); } doc.head.removeChild(sandbox); } catch (err) { logger.warn('Could not create sandbox iframe for pure fetch check, bailing to window.fetch: ', err); } } if (result === null) { // tslint:disable-next-line no-unbound-method result = isNativeFunc(global.fetch); } return result; } /** * Tells whether current environment supports History API * {@link supportsHistory}. * * @returns Answer to the given question. */ function supportsHistory() { // NOTE: in Chrome App environment, touching history.pushState, *even inside // a try/catch block*, will cause Chrome to output an error to console.error // borrowed from: https://github.com/angular/angular.js/pull/13945/files var global = getGlobalObject(); var chrome = global.chrome; // tslint:disable-next-line:no-unsafe-any var isChromePackagedApp = chrome && chrome.app && chrome.app.runtime; var hasHistoryApi = 'history' in global && !!global.history.pushState && !!global.history.replaceState; return !isChromePackagedApp && hasHistoryApi; } /** SyncPromise internal states */ var States; (function (States) { /** Pending */ States["PENDING"] = "PENDING"; /** Resolved / OK */ States["RESOLVED"] = "RESOLVED"; /** Rejected / Error */ States["REJECTED"] = "REJECTED"; })(States || (States = {})); /** JSDoc */ var SyncPromise = /** @class */ (function () { function SyncPromise(callback) { var _this = this; /** JSDoc */ this._state = States.PENDING; /** JSDoc */ this._handlers = []; /** JSDoc */ this._resolve = function (value) { _this._setResult(value, States.RESOLVED); }; /** JSDoc */ this._reject = function (reason) { _this._setResult(reason, States.REJECTED); }; /** JSDoc */ this._setResult = function (value, state) { if (_this._state !== States.PENDING) { return; } if (isThenable(value)) { value.then(_this._resolve, _this._reject); return; } _this._value = value; _this._state = state; _this._executeHandlers(); }; /** JSDoc */ this._executeHandlers = function () { if (_this._state === States.PENDING) { return; } if (_this._state === States.REJECTED) { // tslint:disable-next-line:no-unsafe-any _this._handlers.forEach(function (h) { return h.onFail && h.onFail(_this._value); }); } else { // tslint:disable-next-line:no-unsafe-any _this._handlers.forEach(function (h) { return h.onSuccess && h.onSuccess(_this._value); }); } _this._handlers = []; return; }; /** JSDoc */ this._attachHandler = function (handler) { _this._handlers = _this._handlers.concat(handler); _this._executeHandlers(); }; try { callback(this._resolve, this._reject); } catch (e) { this._reject(e); } } /** JSDoc */ SyncPromise.prototype.then = function (onfulfilled, onrejected) { var _this = this; // public then<U>(onSuccess?: HandlerOnSuccess<T, U>, onFail?: HandlerOnFail<U>): SyncPromise<T | U> { return new SyncPromise(function (resolve, reject) { _this._attachHandler({ onFail: function (reason) { if (!onrejected) { reject(reason); return; } try { resolve(onrejected(reason)); return; } catch (e) { reject(e); return; } }, onSuccess: function (result) { if (!onfulfilled) { resolve(result); return; } try { resolve(onfulfilled(result)); return; } catch (e) { reject(e); return; } }, }); }); }; /** JSDoc */ SyncPromise.prototype.catch = function (onFail) { // tslint:disable-next-line:no-unsafe-any return this.then(function (val) { return val; }, onFail); }; /** JSDoc */ SyncPromise.prototype.toString = function () { return "[object SyncPromise]"; }; /** JSDoc */ SyncPromise.resolve = function (value) { return new SyncPromise(function (resolve) { resolve(value); }); }; /** JSDoc */ SyncPromise.reject = function (reason) { return new SyncPromise(function (_, reject) { reject(reason); }); }; return SyncPromise; }()); var TRACEPARENT_REGEXP = /^[ \t]*([0-9a-f]{32})?-?([0-9a-f]{16})?-?([01])?[ \t]*$/; /** * Span containg all data about a span */ var Span = /** @class */ (function () { function Span(_traceId, _spanId, _sampled, _parent) { if (_traceId === void 0) { _traceId = uuid4(); } if (_spanId === void 0) { _spanId = uuid4().substring(16); } this._traceId = _traceId; this._spanId = _spanId; this._sampled = _sampled; this._parent = _parent; } /** * Setter for parent */ Span.prototype.setParent = function (parent) { this._parent = parent; return this; }; /** * Setter for sampled */ Span.prototype.setSampled = function (sampled) { this._sampled = sampled; return this; }; /** * Continues a trace * @param traceparent Traceparent string */ Span.fromTraceparent = function (traceparent) { var matches = traceparent.match(TRACEPARENT_REGEXP); if (matches) { var sampled = void 0; if (matches[3] === '1') { sampled = true; } else if (matches[3] === '0') { sampled = false; } var parent_1 = new Span(matches[1], matches[2], sampled); return new Span(matches[1], undefined, sampled, parent_1); } return undefined; }; /** * @inheritDoc */ Span.prototype.toTraceparent = function () { var sampled = ''; if (this._sampled === true) { sampled = '-1'; } else if (this._sampled === false) { sampled = '-0'; } return this._traceId + "-" + this._spanId + sampled; }; /** * @inheritDoc */ Span.prototype.toJSON = function () { return { parent: (this._parent && this._parent.toJSON()) || undefined, sampled: this._sampled, span_id: this._spanId, trace_id: this._traceId, }; }; return Span; }()); /** * Holds additional event information. {@link Scope.applyToEvent} will be * called by the client before an event will be sent. */ var Scope = /** @class */ (function () { function Scope() { /** Flag if notifiying is happening. */ this._notifyingListeners = false; /** Callback for client to receive scope changes. */ this._scopeListeners = []; /** Callback list that will be called after {@link applyToEvent}. */ this._eventProcessors = []; /** Array of breadcrumbs. */ this._breadcrumbs = []; /** User */ this._user = {}; /** Tags */ this._tags = {}; /** Extra */ this._extra = {}; /** Contexts */ this._context = {}; } /** * Add internal on change listener. Used for sub SDKs that need to store the scope. * @hidden */ Scope.prototype.addScopeListener = function (callback) { this._scopeListeners.push(callback); }; /** * @inheritDoc */ Scope.prototype.addEventProcessor = function (callback) { this._eventProcessors.push(callback); return this; }; /** * This will be called on every set call. */ Scope.prototype._notifyScopeListeners = function () { var _this = this; if (!this._notifyingListeners) { this._notifyingListeners = true; setTimeout(function () { _this._scopeListeners.forEach(function (callback) { callback(_this); }); _this._notifyingListeners = false; }); } }; /** * This will be called after {@link applyToEvent} is finished. */ Scope.prototype._notifyEventProcessors = function (processors, event, hint, index) { var _this = this; if (index === void 0) { index = 0; } return new SyncPromise(function (resolve, reject) { var processor = processors[index]; // tslint:disable-next-line:strict-type-predicates if (event === null || typeof processor !== 'function') { resolve(event); } else { var result = processor(__assign({}, event), hint); if (isThenable(result)) { result .then(function (final) { return _this._notifyEventProcessors(processors, final, hint, index + 1).then(resolve); }) .catch(reject); } else { _this._notifyEventProcessors(processors, result, hint, index + 1) .then(resolve) .catch(reject); } } }); }; /** * @inheritDoc */ Scope.prototype.setUser = function (user) { this._user = normalize(user); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setTags = function (tags) { this._tags = __assign({}, this._tags, normalize(tags)); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setTag = function (key, value) { var _a; this._tags = __assign({}, this._tags, (_a = {}, _a[key] = normalize(value), _a)); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setExtras = function (extra) { this._extra = __assign({}, this._extra, normalize(extra)); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setExtra = function (key, extra) { var _a; this._extra = __assign({}, this._extra, (_a = {}, _a[key] = normalize(extra), _a)); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setFingerprint = function (fingerprint) { this._fingerprint = normalize(fingerprint); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setLevel = function (level) { this._level = normalize(level); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setTransaction = function (transaction) { this._transaction = transaction; this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setContext = function (name, context) { this._context[name] = context ? normalize(context) : undefined; this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setSpan = function (span) { this._span = span; this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.startSpan = function (parentSpan) { var span = new Span(); span.setParent(parentSpan); this.setSpan(span); return span; }; /** * Internal getter for Span, used in Hub. * @hidden */ Scope.prototype.getSpan = function () { return this._span; }; /** * Inherit values from the parent scope. * @param scope to clone. */ Scope.clone = function (scope) { var newScope = new Scope(); Object.assign(newScope, scope, { _scopeListeners: [], }); if (scope) { newScope._breadcrumbs = __spread(scope._breadcrumbs); newScope._tags = __assign({}, scope._tags); newScope._extra = __assign({}, scope._extra); newScope._context = __assign({}, scope._context); newScope._user = scope._user; newScope._level = scope._level; newScope._span = scope._span; newScope._transaction = scope._transaction; newScope._fingerprint = scope._fingerprint; newScope._eventProcessors = __spread(scope._eventProcessors); } return newScope; }; /** * @inheritDoc */ Scope.prototype.clear = function () { this._breadcrumbs = []; this._tags = {}; this._extra = {}; this._user = {}; this._context = {}; this._level = undefined; this._transaction = undefined; this._fingerprint = undefined; this._span = undefined; this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.addBreadcrumb = function (breadcrumb, maxBreadcrumbs) { var timestamp = new Date().getTime() / 1000; var mergedBreadcrumb = __assign({ timestamp: timestamp }, breadcrumb); this._breadcrumbs = maxBreadcrumbs !== undefined && maxBreadcrumbs >= 0 ? __spread(this._breadcrumbs, [normalize(mergedBreadcrumb)]).slice(-maxBreadcrumbs) : __spread(this._breadcrumbs, [normalize(mergedBreadcrumb)]); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.clearBreadcrumbs = function () { this._breadcrumbs = []; this._notifyScopeListeners(); return this; }; /** * Applies fingerprint from the scope to the event if there's one, * uses message if there's one instead or get rid of empty fingerprint */ Scope.prototype._applyFingerprint = function (event) { // Make sure it's an array first and we actually have something in place event.fingerprint = event.fingerprint ? Array.isArray(event.fingerprint) ? event.fingerprint : [event.fingerprint] : []; // If we have something on the scope, then merge it with event if (this._fingerprint) { event.fingerprint = event.fingerprint.concat(this._fingerprint); } // If we have no data at all, remove empty array default if (event.fingerprint && !event.fingerprint.length) { delete event.fingerprint; } }; /** * Applies the current context and fingerprint to the event. * Note that breadcrumbs will be added by the client. * Also if the event has already breadcrumbs on it, we do not merge them. * @param event Event * @param hint May contain additional informartion about the original exception. * @hidden */ Scope.prototype.applyToEvent = function (event, hint) { if (this._extra && Object.keys(this._extra).length) { event.extra = __assign({}, this._extra, event.extra); } if (this._tags && Object.keys(this._tags).length) { event.tags = __assign({}, this._tags, event.tags); } if (this._user && Object.keys(this._user).length) { event.user = __assign({}, this._user, event.user); } if (this._context && Object.keys(this._context).length) { event.contexts = __assign({}, this._context, event.contexts); } if (this._level) { event.level = this._level; } if (this._transaction) { event.transaction = this._transaction; } if (this._span) { event.contexts = event.contexts || {}; event.contexts.trace = this._span; } this._applyFingerprint(event); event.breadcrumbs = __spread((event.breadcrumbs || []), this._breadcrumbs); event.breadcrumbs = event.breadcrumbs.length > 0 ? event.breadcrumbs : undefined; return this._notifyEventProcessors(__spread(getGlobalEventProcessors(), this._eventProcessors), event, hint); }; return Scope; }()); /** * Retruns the global event processors. */ function getGlobalEventProcessors() { var global = getGlobalObject(); global.__SENTRY__ = global.__SENTRY__ || {}; global.__SENTRY__.globalEventProcessors = global.__SENTRY__.globalEventProcessors || []; return global.