"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDebugConfig = exports.getStorageSize = exports.getPageUrl = exports.validateUGCFilterRules = exports.getServerUrl = exports.generateSessionReplayId = exports.getCurrentUrl = exports.maskAttributeFn = exports.maskFn = exports.isMasked = void 0;
var tslib_1 = require("tslib");
var analytics_core_1 = require("@amplitude/analytics-core");
var types_1 = require("./config/types");
var constants_1 = require("./constants");
var get_input_type_1 = require("./utils/get-input-type");
/**
 * Light: Subset of inputs
 * Medium: All inputs
 * Conservative: All inputs and all texts
 */
var isMaskedForLevel = function (elementType, level, element) {
    switch (level) {
        case 'light': {
            if (elementType !== 'input') {
                return true;
            }
            var inputType = element ? (0, get_input_type_1.getInputType)(element) : '';
            /* istanbul ignore if */ // TODO(lew): For some reason it's impossible to test this.
            if (!inputType) {
                return false;
            }
            if (['password', 'hidden', 'email', 'tel'].includes(inputType)) {
                return true;
            }
            if (element.autocomplete.startsWith('cc-')) {
                return true;
            }
            return false;
        }
        case 'medium':
        case 'conservative':
            return true;
        default:
            return isMaskedForLevel(elementType, types_1.DEFAULT_MASK_LEVEL, element);
    }
};
/**
 * Checks if the given element set to be masked by rrweb
 *
 * Priority is:
 *  1. [In code] Element/class based masking/unmasking <> [Config based] Selector based masking/unmasking
 *  2. Use app defaults
 */
var isMasked = function (elementType, config, element) {
    var _a, _b, _c;
    if (config === void 0) { config = { defaultMaskLevel: types_1.DEFAULT_MASK_LEVEL }; }
    if (element) {
        // Element or parent is explicitly instrumented in code to mask
        if (element.closest('.' + constants_1.MASK_TEXT_CLASS)) {
            return true;
        }
        // Config has override for mask
        var shouldMask = ((_a = config.maskSelector) !== null && _a !== void 0 ? _a : []).some(function (selector) { return element.closest(selector); });
        if (shouldMask) {
            return true;
        }
        // Code or config has override to unmask
        if (element.closest('.' + constants_1.UNMASK_TEXT_CLASS)) {
            return false;
        }
        // Here we are probably sent an element, but we want to match if they have a
        // parent with an unmask selector.
        var shouldUnmask = ((_b = config.unmaskSelector) !== null && _b !== void 0 ? _b : []).some(function (selector) { return element.closest(selector); });
        if (shouldUnmask) {
            return false;
        }
    }
    return isMaskedForLevel(elementType, (_c = config.defaultMaskLevel) !== null && _c !== void 0 ? _c : types_1.DEFAULT_MASK_LEVEL, element);
};
exports.isMasked = isMasked;
var maskFn = function (elementType, config) {
    return function (text, element) {
        return (0, exports.isMasked)(elementType, config, element) ? text.replace(/[^\s]/g, '*') : text;
    };
};
exports.maskFn = maskFn;
var maskAttributeFn = function (config) {
    return function (key, value, element) {
        var _a;
        // Never mask style — rrweb has a separate styleDiff path for attribute mutations
        // that reads directly from the DOM, bypassing maskAttributeFn.
        if (key === 'style')
            return value;
        // Short-circuit: only proceed if this attribute is in the allowlist.
        if (!((_a = config === null || config === void 0 ? void 0 : config.maskAttributes) !== null && _a !== void 0 ? _a : []).includes(key))
            return value;
        // Recompute masking every call so class/ancestor mutations do not stale-cache
        // the decision for later attribute mutations on the same element.
        return (0, exports.isMasked)('text', config, element) ? value.replace(/[^\s]/g, '*') : value;
    };
};
exports.maskAttributeFn = maskAttributeFn;
var getCurrentUrl = function () {
    var globalScope = (0, analytics_core_1.getGlobalScope)();
    return (globalScope === null || globalScope === void 0 ? void 0 : globalScope.location) ? globalScope.location.href : '';
};
exports.getCurrentUrl = getCurrentUrl;
var generateSessionReplayId = function (sessionId, deviceId) {
    return "".concat(deviceId, "/").concat(sessionId);
};
exports.generateSessionReplayId = generateSessionReplayId;
var getServerUrl = function (serverZone, trackServerUrl) {
    if (trackServerUrl) {
        return trackServerUrl;
    }
    if (serverZone === analytics_core_1.ServerZone.STAGING) {
        return constants_1.SESSION_REPLAY_STAGING_URL;
    }
    if (serverZone === analytics_core_1.ServerZone.EU) {
        return constants_1.SESSION_REPLAY_EU_URL;
    }
    return constants_1.SESSION_REPLAY_SERVER_URL;
};
exports.getServerUrl = getServerUrl;
var isValidGlobUrl = function (globUrl) {
    if (typeof globUrl !== 'string' || globUrl.trim() === '')
        return false;
    var urlPattern = /^\/|^https?:\/\/[^\s]+$/;
    if (!urlPattern.test(globUrl))
        return false;
    return true;
};
var globToRegex = function (glob) {
    // Escape special regex characters, then convert globs
    var escaped = glob
        .replace(/[.+^${}()|[\]\\]/g, '\\$&') // Escape regex specials
        .replace(/\*/g, '.*') // Convert * to .*
        .replace(/\?/g, '.'); // Convert ? to .
    return new RegExp("^".concat(escaped, "$"));
};
var validateUGCFilterRules = function (ugcFilterRules) {
    // validate ugcFilterRules
    if (!ugcFilterRules.every(function (rule) { return typeof rule.selector === 'string' && typeof rule.replacement === 'string'; })) {
        throw new Error('ugcFilterRules must be an array of objects with selector and replacement properties');
    }
    // validate ugcFilterRules are valid globs
    if (!ugcFilterRules.every(function (rule) { return isValidGlobUrl(rule.selector); })) {
        throw new Error('ugcFilterRules must be an array of objects with valid globs');
    }
};
exports.validateUGCFilterRules = validateUGCFilterRules;
var getPageUrl = function (pageUrl, ugcFilterRules) {
    var e_1, _a;
    try {
        // apply ugcFilterRules, order is important, first rule wins
        for (var ugcFilterRules_1 = tslib_1.__values(ugcFilterRules), ugcFilterRules_1_1 = ugcFilterRules_1.next(); !ugcFilterRules_1_1.done; ugcFilterRules_1_1 = ugcFilterRules_1.next()) {
            var rule = ugcFilterRules_1_1.value;
            var regex = globToRegex(rule.selector);
            if (regex.test(pageUrl)) {
                return pageUrl.replace(regex, rule.replacement);
            }
        }
    }
    catch (e_1_1) { e_1 = { error: e_1_1 }; }
    finally {
        try {
            if (ugcFilterRules_1_1 && !ugcFilterRules_1_1.done && (_a = ugcFilterRules_1.return)) _a.call(ugcFilterRules_1);
        }
        finally { if (e_1) throw e_1.error; }
    }
    return pageUrl;
};
exports.getPageUrl = getPageUrl;
var getStorageSize = function () { return tslib_1.__awaiter(void 0, void 0, void 0, function () {
    var globalScope, _a, usage, quota, usageDetails, totalStorageSize, percentOfQuota, e_2;
    return tslib_1.__generator(this, function (_b) {
        switch (_b.label) {
            case 0:
                _b.trys.push([0, 3, , 4]);
                globalScope = (0, analytics_core_1.getGlobalScope)();
                if (!globalScope) return [3 /*break*/, 2];
                return [4 /*yield*/, globalScope.navigator.storage.estimate()];
            case 1:
                _a = _b.sent(), usage = _a.usage, quota = _a.quota, usageDetails = _a.usageDetails;
                totalStorageSize = usage ? Math.round(usage / constants_1.KB_SIZE) : 0;
                percentOfQuota = usage && quota ? Math.round((usage / quota + Number.EPSILON) * 1000) / 1000 : 0;
                return [2 /*return*/, { totalStorageSize: totalStorageSize, percentOfQuota: percentOfQuota, usageDetails: JSON.stringify(usageDetails) }];
            case 2: return [3 /*break*/, 4];
            case 3:
                e_2 = _b.sent();
                return [3 /*break*/, 4];
            case 4: return [2 /*return*/, { totalStorageSize: 0, percentOfQuota: 0, usageDetails: '' }];
        }
    });
}); };
exports.getStorageSize = getStorageSize;
var getDebugConfig = function (config) {
    var debugConfig = tslib_1.__assign({}, config);
    var apiKey = debugConfig.apiKey;
    debugConfig.apiKey = "****".concat(apiKey.substring(apiKey.length - 4));
    return debugConfig;
};
exports.getDebugConfig = getDebugConfig;
//# sourceMappingURL=helpers.js.map