import { __assign, __read, __spread } from "tslib"; import { dateTimestampInSeconds, getGlobalSingleton, isPlainObject, isThenable, SyncPromise } from '@sentry/utils'; /** * Absolute maximum number of breadcrumbs added to an event. * The `maxBreadcrumbs` option cannot be higher than this value. */ var MAX_BREADCRUMBS = 100; /** * 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 notifying 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._contexts = {}; /** * A place to stash data which is needed at some point in the SDK's event processing pipeline but which shouldn't get * sent to Sentry */ this._sdkProcessingMetadata = {}; } /** * Inherit values from the parent scope. * @param scope to clone. */ Scope.clone = function (scope) { var newScope = new Scope(); if (scope) { newScope._breadcrumbs = __spread(scope._breadcrumbs); newScope._tags = __assign({}, scope._tags); newScope._extra = __assign({}, scope._extra); newScope._contexts = __assign({}, scope._contexts); newScope._user = scope._user; newScope._level = scope._level; newScope._span = scope._span; newScope._session = scope._session; newScope._transactionName = scope._transactionName; newScope._fingerprint = scope._fingerprint; newScope._eventProcessors = __spread(scope._eventProcessors); newScope._requestSession = scope._requestSession; } return newScope; }; /** * 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; }; /** * @inheritDoc */ Scope.prototype.setUser = function (user) { this._user = user || {}; if (this._session) { this._session.update({ user: user }); } this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.getUser = function () { return this._user; }; /** * @inheritDoc */ Scope.prototype.getRequestSession = function () { return this._requestSession; }; /** * @inheritDoc */ Scope.prototype.setRequestSession = function (requestSession) { this._requestSession = requestSession; return this; }; /** * @inheritDoc */ Scope.prototype.setTags = function (tags) { this._tags = __assign(__assign({}, this._tags), tags); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setTag = function (key, value) { var _a; this._tags = __assign(__assign({}, this._tags), (_a = {}, _a[key] = value, _a)); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setExtras = function (extras) { this._extra = __assign(__assign({}, this._extra), extras); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setExtra = function (key, extra) { var _a; this._extra = __assign(__assign({}, this._extra), (_a = {}, _a[key] = extra, _a)); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setFingerprint = function (fingerprint) { this._fingerprint = fingerprint; this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setLevel = function (level) { this._level = level; this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setTransactionName = function (name) { this._transactionName = name; this._notifyScopeListeners(); return this; }; /** * Can be removed in major version. * @deprecated in favor of {@link this.setTransactionName} */ Scope.prototype.setTransaction = function (name) { return this.setTransactionName(name); }; /** * @inheritDoc */ Scope.prototype.setContext = function (key, context) { var _a; if (context === null) { // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete this._contexts[key]; } else { this._contexts = __assign(__assign({}, this._contexts), (_a = {}, _a[key] = context, _a)); } this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.setSpan = function (span) { this._span = span; this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.getSpan = function () { return this._span; }; /** * @inheritDoc */ Scope.prototype.getTransaction = function () { // Often, this span (if it exists at all) will be a transaction, but it's not guaranteed to be. Regardless, it will // have a pointer to the currently-active transaction. var span = this.getSpan(); return span && span.transaction; }; /** * @inheritDoc */ Scope.prototype.setSession = function (session) { if (!session) { delete this._session; } else { this._session = session; } this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.getSession = function () { return this._session; }; /** * @inheritDoc */ Scope.prototype.update = function (captureContext) { if (!captureContext) { return this; } if (typeof captureContext === 'function') { var updatedScope = captureContext(this); return updatedScope instanceof Scope ? updatedScope : this; } if (captureContext instanceof Scope) { this._tags = __assign(__assign({}, this._tags), captureContext._tags); this._extra = __assign(__assign({}, this._extra), captureContext._extra); this._contexts = __assign(__assign({}, this._contexts), captureContext._contexts); if (captureContext._user && Object.keys(captureContext._user).length) { this._user = captureContext._user; } if (captureContext._level) { this._level = captureContext._level; } if (captureContext._fingerprint) { this._fingerprint = captureContext._fingerprint; } if (captureContext._requestSession) { this._requestSession = captureContext._requestSession; } } else if (isPlainObject(captureContext)) { // eslint-disable-next-line no-param-reassign captureContext = captureContext; this._tags = __assign(__assign({}, this._tags), captureContext.tags); this._extra = __assign(__assign({}, this._extra), captureContext.extra); this._contexts = __assign(__assign({}, this._contexts), captureContext.contexts); if (captureContext.user) { this._user = captureContext.user; } if (captureContext.level) { this._level = captureContext.level; } if (captureContext.fingerprint) { this._fingerprint = captureContext.fingerprint; } if (captureContext.requestSession) { this._requestSession = captureContext.requestSession; } } return this; }; /** * @inheritDoc */ Scope.prototype.clear = function () { this._breadcrumbs = []; this._tags = {}; this._extra = {}; this._user = {}; this._contexts = {}; this._level = undefined; this._transactionName = undefined; this._fingerprint = undefined; this._requestSession = undefined; this._span = undefined; this._session = undefined; this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.addBreadcrumb = function (breadcrumb, maxBreadcrumbs) { var maxCrumbs = typeof maxBreadcrumbs === 'number' ? Math.min(maxBreadcrumbs, MAX_BREADCRUMBS) : MAX_BREADCRUMBS; // No data has been changed, so don't notify scope listeners if (maxCrumbs <= 0) { return this; } var mergedBreadcrumb = __assign({ timestamp: dateTimestampInSeconds() }, breadcrumb); this._breadcrumbs = __spread(this._breadcrumbs, [mergedBreadcrumb]).slice(-maxCrumbs); this._notifyScopeListeners(); return this; }; /** * @inheritDoc */ Scope.prototype.clearBreadcrumbs = function () { this._breadcrumbs = []; this._notifyScopeListeners(); return this; }; /** * 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 information about the original exception. * @hidden */ Scope.prototype.applyToEvent = function (event, hint) { if (this._extra && Object.keys(this._extra).length) { event.extra = __assign(__assign({}, this._extra), event.extra); } if (this._tags && Object.keys(this._tags).length) { event.tags = __assign(__assign({}, this._tags), event.tags); } if (this._user && Object.keys(this._user).length) { event.user = __assign(__assign({}, this._user), event.user); } if (this._contexts && Object.keys(this._contexts).length) { event.contexts = __assign(__assign({}, this._contexts), event.contexts); } if (this._level) { event.level = this._level; } if (this._transactionName) { event.transaction = this._transactionName; } // We want to set the trace context for normal events only if there isn't already // a trace context on the event. There is a product feature in place where we link // errors with transaction and it relies on that. if (this._span) { event.contexts = __assign({ trace: this._span.getTraceContext() }, event.contexts); var transactionName = this._span.transaction && this._span.transaction.name; if (transactionName) { event.tags = __assign({ transaction: transactionName }, event.tags); } } this._applyFingerprint(event); event.breadcrumbs = __spread((event.breadcrumbs || []), this._breadcrumbs); event.breadcrumbs = event.breadcrumbs.length > 0 ? event.breadcrumbs : undefined; event.sdkProcessingMetadata = this._sdkProcessingMetadata; return this._notifyEventProcessors(__spread(getGlobalEventProcessors(), this._eventProcessors), event, hint); }; /** * Add data which will be accessible during event processing but won't get sent to Sentry */ Scope.prototype.setSDKProcessingMetadata = function (newData) { this._sdkProcessingMetadata = __assign(__assign({}, this._sdkProcessingMetadata), newData); return this; }; /** * 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]; if (event === null || typeof processor !== 'function') { resolve(event); } else { var result = processor(__assign({}, event), hint); if (isThenable(result)) { void result .then(function (final) { return _this._notifyEventProcessors(processors, final, hint, index + 1).then(resolve); }) .then(null, reject); } else { void _this._notifyEventProcessors(processors, result, hint, index + 1) .then(resolve) .then(null, reject); } } }); }; /** * This will be called on every set call. */ Scope.prototype._notifyScopeListeners = function () { var _this = this; // We need this check for this._notifyingListeners to be able to work on scope during updates // If this check is not here we'll produce endless recursion when something is done with the scope // during the callback. if (!this._notifyingListeners) { this._notifyingListeners = true; this._scopeListeners.forEach(function (callback) { callback(_this); }); this._notifyingListeners = false; } }; /** * 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; } }; return Scope; }()); export { Scope }; /** * Returns the global event processors. */ function getGlobalEventProcessors() { return getGlobalSingleton('globalEventProcessors', function () { return []; }); } /** * Add a EventProcessor to be kept globally. * @param callback EventProcessor to add */ export function addGlobalEventProcessor(callback) { getGlobalEventProcessors().push(callback); } //# sourceMappingURL=scope.js.map