import { __assign, __read } from "tslib";
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
import { getCurrentHub } from '@sentry/core';
import { Severity } from '@sentry/types';
import { addExceptionMechanism, addInstrumentationHandler, getLocationHref, isDebugBuild, isErrorEvent, isPrimitive, isString, logger, } from '@sentry/utils';
import { eventFromUnknownInput } from '../eventbuilder';
import { shouldIgnoreOnError } from '../helpers';
/** Global handlers */
var GlobalHandlers = /** @class */ (function () {
    /** JSDoc */
    function GlobalHandlers(options) {
        /**
         * @inheritDoc
         */
        this.name = GlobalHandlers.id;
        /**
         * Stores references functions to installing handlers. Will set to undefined
         * after they have been run so that they are not used twice.
         */
        this._installFunc = {
            onerror: _installGlobalOnErrorHandler,
            onunhandledrejection: _installGlobalOnUnhandledRejectionHandler,
        };
        this._options = __assign({ onerror: true, onunhandledrejection: true }, options);
    }
    /**
     * @inheritDoc
     */
    GlobalHandlers.prototype.setupOnce = function () {
        Error.stackTraceLimit = 50;
        var options = this._options;
        // We can disable guard-for-in as we construct the options object above + do checks against
        // `this._installFunc` for the property.
        // eslint-disable-next-line guard-for-in
        for (var key in options) {
            var installFunc = this._installFunc[key];
            if (installFunc && options[key]) {
                globalHandlerLog(key);
                installFunc();
                this._installFunc[key] = undefined;
            }
        }
    };
    /**
     * @inheritDoc
     */
    GlobalHandlers.id = 'GlobalHandlers';
    return GlobalHandlers;
}());
export { GlobalHandlers };
/** JSDoc */
function _installGlobalOnErrorHandler() {
    addInstrumentationHandler('error', 
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function (data) {
        var _a = __read(getHubAndAttachStacktrace(), 2), hub = _a[0], attachStacktrace = _a[1];
        if (!hub.getIntegration(GlobalHandlers)) {
            return;
        }
        var msg = data.msg, url = data.url, line = data.line, column = data.column, error = data.error;
        if (shouldIgnoreOnError() || (error && error.__sentry_own_request__)) {
            return;
        }
        var event = error === undefined && isString(msg)
            ? _eventFromIncompleteOnError(msg, url, line, column)
            : _enhanceEventWithInitialFrame(eventFromUnknownInput(error || msg, undefined, attachStacktrace, false), url, line, column);
        event.level = Severity.Error;
        addMechanismAndCapture(hub, error, event, 'onerror');
    });
}
/** JSDoc */
function _installGlobalOnUnhandledRejectionHandler() {
    addInstrumentationHandler('unhandledrejection', 
    // eslint-disable-next-line @typescript-eslint/no-explicit-any
    function (e) {
        var _a = __read(getHubAndAttachStacktrace(), 2), hub = _a[0], attachStacktrace = _a[1];
        if (!hub.getIntegration(GlobalHandlers)) {
            return;
        }
        var error = e;
        // dig the object of the rejection out of known event types
        try {
            // PromiseRejectionEvents store the object of the rejection under 'reason'
            // see https://developer.mozilla.org/en-US/docs/Web/API/PromiseRejectionEvent
            if ('reason' in e) {
                error = e.reason;
            }
            // something, somewhere, (likely a browser extension) effectively casts PromiseRejectionEvents
            // to CustomEvents, moving the `promise` and `reason` attributes of the PRE into
            // the CustomEvent's `detail` attribute, since they're not part of CustomEvent's spec
            // see https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent and
            // https://github.com/getsentry/sentry-javascript/issues/2380
            else if ('detail' in e && 'reason' in e.detail) {
                error = e.detail.reason;
            }
        }
        catch (_oO) {
            // no-empty
        }
        if (shouldIgnoreOnError() || (error && error.__sentry_own_request__)) {
            return true;
        }
        var event = isPrimitive(error)
            ? _eventFromRejectionWithPrimitive(error)
            : eventFromUnknownInput(error, undefined, attachStacktrace, true);
        event.level = Severity.Error;
        addMechanismAndCapture(hub, error, event, 'onunhandledrejection');
        return;
    });
}
/**
 * Create an event from a promise rejection where the `reason` is a primitive.
 *
 * @param reason: The `reason` property of the promise rejection
 * @returns An Event object with an appropriate `exception` value
 */
function _eventFromRejectionWithPrimitive(reason) {
    return {
        exception: {
            values: [
                {
                    type: 'UnhandledRejection',
                    // String() is needed because the Primitive type includes symbols (which can't be automatically stringified)
                    value: "Non-Error promise rejection captured with value: " + String(reason),
                },
            ],
        },
    };
}
/**
 * This function creates a stack from an old, error-less onerror handler.
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function _eventFromIncompleteOnError(msg, url, line, column) {
    var ERROR_TYPES_RE = /^(?:[Uu]ncaught (?:exception: )?)?(?:((?:Eval|Internal|Range|Reference|Syntax|Type|URI|)Error): )?(.*)$/i;
    // If 'message' is ErrorEvent, get real message from inside
    var message = isErrorEvent(msg) ? msg.message : msg;
    var name = 'Error';
    var groups = message.match(ERROR_TYPES_RE);
    if (groups) {
        name = groups[1];
        message = groups[2];
    }
    var event = {
        exception: {
            values: [
                {
                    type: name,
                    value: message,
                },
            ],
        },
    };
    return _enhanceEventWithInitialFrame(event, url, line, column);
}
/** JSDoc */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
function _enhanceEventWithInitialFrame(event, url, line, column) {
    // event.exception
    var e = (event.exception = event.exception || {});
    // event.exception.values
    var ev = (e.values = e.values || []);
    // event.exception.values[0]
    var ev0 = (ev[0] = ev[0] || {});
    // event.exception.values[0].stacktrace
    var ev0s = (ev0.stacktrace = ev0.stacktrace || {});
    // event.exception.values[0].stacktrace.frames
    var ev0sf = (ev0s.frames = ev0s.frames || []);
    var colno = isNaN(parseInt(column, 10)) ? undefined : column;
    var lineno = isNaN(parseInt(line, 10)) ? undefined : line;
    var filename = isString(url) && url.length > 0 ? url : getLocationHref();
    // event.exception.values[0].stacktrace.frames
    if (ev0sf.length === 0) {
        ev0sf.push({
            colno: colno,
            filename: filename,
            function: '?',
            in_app: true,
            lineno: lineno,
        });
    }
    return event;
}
function globalHandlerLog(type) {
    if (isDebugBuild()) {
        logger.log("Global Handler attached: " + type);
    }
}
function addMechanismAndCapture(hub, error, event, type) {
    addExceptionMechanism(event, {
        handled: false,
        type: type,
    });
    hub.captureEvent(event, {
        originalException: error,
    });
}
function getHubAndAttachStacktrace() {
    var hub = getCurrentHub();
    var client = hub.getClient();
    var attachStacktrace = client && client.getOptions().attachStacktrace;
    return [hub, attachStacktrace];
}
//# sourceMappingURL=globalhandlers.js.map