UNPKG

react-native-avo-inspector

Version:

[![npm version](https://badge.fury.io/js/react-native-avo-inspector.svg)](https://badge.fury.io/js/react-native-avo-inspector)

847 lines (846 loc) 36.8 kB
"use strict"; /** * EventValidator - Client-side validation of tracking events against the Avo Tracking Plan. * * This module validates property values against constraints: * - Pinned values (exact match required) * - Allowed values (must be in list) * - Regex patterns (must match pattern, with safe-regex2 check and 1s timeout) * - Min/max ranges (numeric values must be in range) * * No schema validation (types/required) is performed - only value constraints. * Validation runs against ALL events/variants in the response. * * Adapted for React Native: uses safe-regex2 for regex safety and * Promise.race + clearTimeout for per-match 1-second timeout. */ var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(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); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.validateEvent = validateEvent; var safe = require("safe-regex2"); // ============================================================================= // HELPER FUNCTIONS FOR NESTED PROPERTIES // ============================================================================= /** * Deep copies a constraint mapping (pinnedValues, allowedValues, etc.), * including the arrays inside to avoid shared references. */ function deepCopyConstraintMapping(mapping) { var result = {}; for (var _i = 0, _a = Object.entries(mapping); _i < _a.length; _i++) { var _b = _a[_i], key = _b[0], arr = _b[1]; result[key] = __spreadArray([], arr, true); } return result; } /** * Deep copies children constraints recursively. */ function deepCopyChildren(children) { var result = {}; for (var _i = 0, _a = Object.entries(children); _i < _a.length; _i++) { var _b = _a[_i], propName = _b[0], constraints = _b[1]; result[propName] = { type: constraints.type, required: constraints.required, pinnedValues: constraints.pinnedValues ? deepCopyConstraintMapping(constraints.pinnedValues) : undefined, allowedValues: constraints.allowedValues ? deepCopyConstraintMapping(constraints.allowedValues) : undefined, regexPatterns: constraints.regexPatterns ? deepCopyConstraintMapping(constraints.regexPatterns) : undefined, minMaxRanges: constraints.minMaxRanges ? deepCopyConstraintMapping(constraints.minMaxRanges) : undefined, children: constraints.children ? deepCopyChildren(constraints.children) : undefined }; } return result; } /** * Merges children constraints from source into target recursively. */ function mergeChildren(target, source) { for (var _i = 0, _a = Object.entries(source); _i < _a.length; _i++) { var _b = _a[_i], propName = _b[0], sourceConstraints = _b[1]; if (!target[propName]) { // New child property - deep copy it target[propName] = { type: sourceConstraints.type, required: sourceConstraints.required, pinnedValues: sourceConstraints.pinnedValues ? deepCopyConstraintMapping(sourceConstraints.pinnedValues) : undefined, allowedValues: sourceConstraints.allowedValues ? deepCopyConstraintMapping(sourceConstraints.allowedValues) : undefined, regexPatterns: sourceConstraints.regexPatterns ? deepCopyConstraintMapping(sourceConstraints.regexPatterns) : undefined, minMaxRanges: sourceConstraints.minMaxRanges ? deepCopyConstraintMapping(sourceConstraints.minMaxRanges) : undefined, children: sourceConstraints.children ? deepCopyChildren(sourceConstraints.children) : undefined }; } else { // Merge into existing child property var targetConstraints = target[propName]; mergeConstraintMappings(targetConstraints, sourceConstraints); // Recursively merge nested children if (sourceConstraints.children) { if (!targetConstraints.children) { targetConstraints.children = deepCopyChildren(sourceConstraints.children); } else { mergeChildren(targetConstraints.children, sourceConstraints.children); } } } } } /** * Merges constraint mappings (pinnedValues, allowedValues, etc.) from source into target. */ function mergeConstraintMappings(target, source) { if (source.pinnedValues) { if (!target.pinnedValues) { target.pinnedValues = {}; } for (var _i = 0, _a = Object.keys(source.pinnedValues); _i < _a.length; _i++) { var key = _a[_i]; if (target.pinnedValues[key]) { var merged = new Set(target.pinnedValues[key]); for (var _b = 0, _c = source.pinnedValues[key]; _b < _c.length; _b++) { var id = _c[_b]; merged.add(id); } target.pinnedValues[key] = Array.from(merged); } else { target.pinnedValues[key] = __spreadArray([], source.pinnedValues[key], true); } } } if (source.allowedValues) { if (!target.allowedValues) { target.allowedValues = {}; } for (var _d = 0, _e = Object.keys(source.allowedValues); _d < _e.length; _d++) { var key = _e[_d]; if (target.allowedValues[key]) { var merged = new Set(target.allowedValues[key]); for (var _f = 0, _g = source.allowedValues[key]; _f < _g.length; _f++) { var id = _g[_f]; merged.add(id); } target.allowedValues[key] = Array.from(merged); } else { target.allowedValues[key] = __spreadArray([], source.allowedValues[key], true); } } } if (source.regexPatterns) { if (!target.regexPatterns) { target.regexPatterns = {}; } for (var _h = 0, _j = Object.keys(source.regexPatterns); _h < _j.length; _h++) { var key = _j[_h]; if (target.regexPatterns[key]) { var merged = new Set(target.regexPatterns[key]); for (var _k = 0, _l = source.regexPatterns[key]; _k < _l.length; _k++) { var id = _l[_k]; merged.add(id); } target.regexPatterns[key] = Array.from(merged); } else { target.regexPatterns[key] = __spreadArray([], source.regexPatterns[key], true); } } } if (source.minMaxRanges) { if (!target.minMaxRanges) { target.minMaxRanges = {}; } for (var _m = 0, _o = Object.keys(source.minMaxRanges); _m < _o.length; _m++) { var key = _o[_m]; if (target.minMaxRanges[key]) { var merged = new Set(target.minMaxRanges[key]); for (var _p = 0, _q = source.minMaxRanges[key]; _p < _q.length; _p++) { var id = _q[_p]; merged.add(id); } target.minMaxRanges[key] = Array.from(merged); } else { target.minMaxRanges[key] = __spreadArray([], source.minMaxRanges[key], true); } } } } // ============================================================================= // CACHES // ============================================================================= /** * Cache for compiled regex objects to avoid recompilation on every event. * Patterns are expected to be stable per session. * Only safe patterns (per safe-regex2) are cached. */ var regexCache = new Map(); /** * Gets a compiled regex from cache or compiles and caches it. * Uses safe-regex2 to validate patterns before compilation. * Returns null if the pattern is unsafe or invalid. */ function getOrCompileRegex(pattern) { var regex = regexCache.get(pattern); if (regex) { return regex; } // Check pattern safety with safe-regex2 if (!safe(pattern)) { console.warn("[Avo Inspector] Warning: unsafe regex pattern skipped: ".concat(pattern)); return null; } try { regex = new RegExp(pattern); regexCache.set(pattern, regex); return regex; } catch (e) { console.warn("[Avo Inspector] Warning: invalid regex pattern skipped: ".concat(pattern)); return null; } } /** * Tests a regex match with a 1-second timeout using Promise.race + clearTimeout. * The timer is cleared on regex completion to prevent timer accumulation. * Returns true if pattern matches, false if not or on timeout. * * Note: safe-regex2 is the primary ReDoS protection — it screens out catastrophic * patterns before they are compiled. This timeout is a safety net for future async * regex engines or edge cases where safe-regex2 does not catch the pattern. */ function testRegexWithTimeout(regex_1, value_1) { return __awaiter(this, arguments, void 0, function (regex, value, timeoutMs) { if (timeoutMs === void 0) { timeoutMs = 1000; } return __generator(this, function (_a) { return [2 /*return*/, new Promise(function (resolve) { var settled = false; var timer = setTimeout(function () { if (!settled) { settled = true; console.warn("[Avo Inspector] Warning: regex match timed out after ".concat(timeoutMs, "ms")); resolve(false); } }, timeoutMs); try { var result = regex.test(value); if (!settled) { settled = true; clearTimeout(timer); resolve(result); } } catch (e) { if (!settled) { settled = true; clearTimeout(timer); resolve(false); } } })]; }); }); } /** * Cache for parsed allowed values JSON. * Key: JSON string, Value: Set of allowed values for O(1) lookup. */ var allowedValuesCache = new Map(); /** * Parses allowed values JSON string and returns a Set for O(1) lookup. * Results are cached to avoid repeated JSON.parse calls. * @returns Set of allowed values, or null if JSON is invalid */ function getOrParseAllowedValues(jsonString) { var allowedSet = allowedValuesCache.get(jsonString); if (!allowedSet) { try { var allowedArray = JSON.parse(jsonString); allowedSet = new Set(allowedArray); allowedValuesCache.set(jsonString, allowedSet); } catch (e) { // Invalid JSON - return null return null; } } return allowedSet; } // ============================================================================= // MAIN VALIDATION FUNCTION // ============================================================================= /** * Validates runtime properties against all events in the EventSpecResponse. * * For each property: * - If property not in spec: no validation needed (empty result) * - If property in spec: check constraints and collect failed/passed eventIds * - Return whichever list is smaller for bandwidth optimization * * This is an async function because regex validation uses Promise.race for timeout. * * @param properties - The properties observed at runtime * @param specResponse - The EventSpecResponse from the backend * @returns ValidationResult with metadata and per-property results */ function validateEvent(properties, specResponse) { return __awaiter(this, void 0, void 0, function () { var allEventIds, constraintsByProperty, propertyResults, _i, _a, propName, value, constraints, result; return __generator(this, function (_b) { switch (_b.label) { case 0: allEventIds = collectAllEventIds(specResponse.events); constraintsByProperty = collectConstraintsByPropertyName(specResponse.events); propertyResults = {}; _i = 0, _a = Object.keys(properties); _b.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 5]; propName = _a[_i]; value = properties[propName]; constraints = constraintsByProperty[propName]; if (!!constraints) return [3 /*break*/, 2]; // Property not in spec - no constraints to fail propertyResults[propName] = {}; return [3 /*break*/, 4]; case 2: return [4 /*yield*/, validatePropertyConstraints(value, constraints, allEventIds)]; case 3: result = _b.sent(); propertyResults[propName] = result; _b.label = 4; case 4: _i++; return [3 /*break*/, 1]; case 5: return [2 /*return*/, { metadata: specResponse.metadata, propertyResults: propertyResults }]; } }); }); } // ============================================================================= // HELPER FUNCTIONS // ============================================================================= /** * Collects all eventIds (baseEventId + variantIds) from all events. */ function collectAllEventIds(events) { var ids = []; for (var _i = 0, events_1 = events; _i < events_1.length; _i++) { var event_1 = events_1[_i]; ids.push(event_1.baseEventId); for (var j = 0; j < event_1.variantIds.length; j++) { ids.push(event_1.variantIds[j]); } } return ids; } /** * Collects all property constraints from all events into a single lookup table. */ function collectConstraintsByPropertyName(events) { // Fast path: no events if (events.length === 0) { return {}; } // Fast path: single event, return props directly (no aggregation needed) if (events.length === 1) { return events[0].props; } // Multiple events: aggregate constraints from all events var result = {}; for (var _i = 0, events_2 = events; _i < events_2.length; _i++) { var event_2 = events_2[_i]; for (var _a = 0, _b = Object.entries(event_2.props); _a < _b.length; _a++) { var _c = _b[_a], propName = _c[0], constraints = _c[1]; if (!result[propName]) { // First time seeing this property - initialize with copies result[propName] = { type: constraints.type, required: constraints.required, pinnedValues: constraints.pinnedValues ? __assign({}, constraints.pinnedValues) : undefined, allowedValues: constraints.allowedValues ? __assign({}, constraints.allowedValues) : undefined, regexPatterns: constraints.regexPatterns ? __assign({}, constraints.regexPatterns) : undefined, minMaxRanges: constraints.minMaxRanges ? __assign({}, constraints.minMaxRanges) : undefined, children: constraints.children ? deepCopyChildren(constraints.children) : undefined }; } else { // Aggregate constraint mappings from additional events var existing = result[propName]; mergeConstraintMappings(existing, constraints); // Recursively merge nested children if (constraints.children) { if (!existing.children) { existing.children = deepCopyChildren(constraints.children); } else { mergeChildren(existing.children, constraints.children); } } } } } return result; } /** * Maximum nesting depth for recursive value validation. */ var MAX_CHILD_DEPTH = 2; /** * Validates a property value against its constraints. */ function validatePropertyConstraints(value_1, constraints_1, allEventIds_1) { return __awaiter(this, arguments, void 0, function (value, constraints, allEventIds, depth) { var result; if (depth === void 0) { depth = 0; } return __generator(this, function (_a) { result = {}; if (depth >= MAX_CHILD_DEPTH) { return [2 /*return*/, result]; } // Handle list types (isList=true) if (constraints.isList) { return [2 /*return*/, validateListProperty(value, constraints, allEventIds, depth)]; } // Handle nested object properties with children (single object, not list) if (constraints.children) { return [2 /*return*/, validateObjectProperty(value, constraints, allEventIds, depth)]; } // For primitive properties only: skip validation for null/undefined on non-required properties. if ((value === null || value === undefined) && !constraints.required) { return [2 /*return*/, result]; } // Validate value constraints for primitive properties return [2 /*return*/, validatePrimitiveProperty(value, constraints, allEventIds)]; }); }); } /** * Validates a list property (array of items). */ function validateListProperty(value, constraints, allEventIds, depth) { return __awaiter(this, void 0, void 0, function () { var result, childrenResults, _loop_1, _i, _a, _b, childName, childConstraints, failedIds, _c, value_1, item; return __generator(this, function (_d) { switch (_d.label) { case 0: result = {}; if (!Array.isArray(value)) { return [2 /*return*/, result]; } if (!constraints.children) return [3 /*break*/, 5]; childrenResults = {}; _loop_1 = function (childName, childConstraints) { var aggregatedFailedIds, _e, value_2, item, itemObj, childValue, childResult, _f, _g, id, passedSet, _h, allEventIds_1, id, failedArray, passedIds; return __generator(this, function (_j) { switch (_j.label) { case 0: aggregatedFailedIds = new Set(); _e = 0, value_2 = value; _j.label = 1; case 1: if (!(_e < value_2.length)) return [3 /*break*/, 4]; item = value_2[_e]; itemObj = (typeof item === "object" && item !== null && !Array.isArray(item)) ? item : {}; childValue = itemObj[childName]; return [4 /*yield*/, validatePropertyConstraints(childValue, childConstraints, allEventIds, depth + 1)]; case 2: childResult = _j.sent(); if (childResult.failedEventIds) { for (_f = 0, _g = childResult.failedEventIds; _f < _g.length; _f++) { id = _g[_f]; aggregatedFailedIds.add(id); } } if (childResult.passedEventIds) { passedSet = new Set(childResult.passedEventIds); for (_h = 0, allEventIds_1 = allEventIds; _h < allEventIds_1.length; _h++) { id = allEventIds_1[_h]; if (!passedSet.has(id)) { aggregatedFailedIds.add(id); } } } _j.label = 3; case 3: _e++; return [3 /*break*/, 1]; case 4: if (aggregatedFailedIds.size > 0) { failedArray = Array.from(aggregatedFailedIds); passedIds = allEventIds.filter(function (id) { return !aggregatedFailedIds.has(id); }); if (passedIds.length < failedArray.length && passedIds.length > 0) { childrenResults[childName] = { passedEventIds: passedIds }; } else { childrenResults[childName] = { failedEventIds: failedArray }; } } return [2 /*return*/]; } }); }; _i = 0, _a = Object.entries(constraints.children); _d.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 4]; _b = _a[_i], childName = _b[0], childConstraints = _b[1]; return [5 /*yield**/, _loop_1(childName, childConstraints)]; case 2: _d.sent(); _d.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: if (Object.keys(childrenResults).length > 0) { result.children = childrenResults; } return [2 /*return*/, result]; case 5: failedIds = new Set(); _c = 0, value_1 = value; _d.label = 6; case 6: if (!(_c < value_1.length)) return [3 /*break*/, 10]; item = value_1[_c]; if (constraints.pinnedValues) { checkPinnedValues(item, constraints.pinnedValues, failedIds); } if (constraints.allowedValues) { checkAllowedValues(item, constraints.allowedValues, failedIds); } if (!constraints.regexPatterns) return [3 /*break*/, 8]; return [4 /*yield*/, checkRegexPatterns(item, constraints.regexPatterns, failedIds)]; case 7: _d.sent(); _d.label = 8; case 8: if (constraints.minMaxRanges) { checkMinMaxRanges(item, constraints.minMaxRanges, failedIds); } _d.label = 9; case 9: _c++; return [3 /*break*/, 6]; case 10: return [2 /*return*/, buildValidationResult(failedIds, allEventIds)]; } }); }); } /** * Validates an object property (single object with children). */ function validateObjectProperty(value, constraints, allEventIds, depth) { return __awaiter(this, void 0, void 0, function () { var result, childrenResults, valueObj, _i, _a, _b, childName, childConstraints, childValue, childResult; return __generator(this, function (_c) { switch (_c.label) { case 0: result = {}; childrenResults = {}; valueObj = (typeof value === "object" && value !== null && !Array.isArray(value)) ? value : {}; _i = 0, _a = Object.entries(constraints.children); _c.label = 1; case 1: if (!(_i < _a.length)) return [3 /*break*/, 4]; _b = _a[_i], childName = _b[0], childConstraints = _b[1]; childValue = valueObj[childName]; return [4 /*yield*/, validatePropertyConstraints(childValue, childConstraints, allEventIds, depth + 1)]; case 2: childResult = _c.sent(); if (childResult.failedEventIds || childResult.passedEventIds || childResult.children) { childrenResults[childName] = childResult; } _c.label = 3; case 3: _i++; return [3 /*break*/, 1]; case 4: if (Object.keys(childrenResults).length > 0) { result.children = childrenResults; } return [2 /*return*/, result]; } }); }); } /** * Validates a primitive property (not list, not object with children). */ function validatePrimitiveProperty(value, constraints, allEventIds) { return __awaiter(this, void 0, void 0, function () { var failedIds; return __generator(this, function (_a) { switch (_a.label) { case 0: failedIds = new Set(); if (constraints.pinnedValues) { checkPinnedValues(value, constraints.pinnedValues, failedIds); } if (constraints.allowedValues) { checkAllowedValues(value, constraints.allowedValues, failedIds); } if (!constraints.regexPatterns) return [3 /*break*/, 2]; return [4 /*yield*/, checkRegexPatterns(value, constraints.regexPatterns, failedIds)]; case 1: _a.sent(); _a.label = 2; case 2: if (constraints.minMaxRanges) { checkMinMaxRanges(value, constraints.minMaxRanges, failedIds); } return [2 /*return*/, buildValidationResult(failedIds, allEventIds)]; } }); }); } /** * Builds the validation result from failed IDs, returning whichever list is smaller. */ function buildValidationResult(failedIds, allEventIds) { var passedIds = allEventIds.filter(function (id) { return !failedIds.has(id); }); var failedArray = Array.from(failedIds); if (failedArray.length === 0 && passedIds.length === 0) { return {}; } // Prefer passedEventIds only when strictly smaller than failedEventIds if (passedIds.length < failedArray.length && passedIds.length > 0) { return { passedEventIds: passedIds }; } else if (failedArray.length > 0) { return { failedEventIds: failedArray }; } else { return {}; } } // ============================================================================= // CONSTRAINT VALIDATION FUNCTIONS // ============================================================================= /** * Adds all IDs from the array to the set. */ function addIdsToSet(ids, set) { for (var _i = 0, ids_1 = ids; _i < ids_1.length; _i++) { var id = ids_1[_i]; set.add(id); } } /** * Converts runtime value to string for comparison. */ function convertValueToString(value) { if (value === null || value === undefined || typeof value === "boolean" || typeof value === "number" || typeof value === "string") { return String(value); } if (Array.isArray(value) || typeof value === "object") { try { return JSON.stringify(value); } catch (e) { console.warn("[Avo Inspector] Failed to stringify value: ".concat(e)); return String(value); } } return String(value); } /** * Checks pinned values constraint. */ function checkPinnedValues(value, pinnedValues, failedIds) { var stringValue = convertValueToString(value); for (var _i = 0, _a = Object.entries(pinnedValues); _i < _a.length; _i++) { var _b = _a[_i], pinnedValue = _b[0], eventIds = _b[1]; if (stringValue !== pinnedValue) { addIdsToSet(eventIds, failedIds); } } } /** * Checks allowed values constraint. */ function checkAllowedValues(value, allowedValues, failedIds) { var stringValue = convertValueToString(value); for (var _i = 0, _a = Object.entries(allowedValues); _i < _a.length; _i++) { var _b = _a[_i], allowedArrayJson = _b[0], eventIds = _b[1]; var allowedSet = getOrParseAllowedValues(allowedArrayJson); if (allowedSet === null) { console.warn("[Avo Inspector] Invalid allowed values JSON: ".concat(allowedArrayJson)); continue; } if (!allowedSet.has(stringValue)) { addIdsToSet(eventIds, failedIds); } } } /** * Checks regex pattern constraint with safe-regex2 validation and 1-second timeout. * Unsafe patterns are skipped with a console.warn. */ function checkRegexPatterns(value, regexPatterns, failedIds) { return __awaiter(this, void 0, void 0, function () { var _i, _a, eventIds, _b, _c, _d, pattern, eventIds, regex, matched; return __generator(this, function (_e) { switch (_e.label) { case 0: // Only check regex for string values if (typeof value !== "string") { for (_i = 0, _a = Object.values(regexPatterns); _i < _a.length; _i++) { eventIds = _a[_i]; addIdsToSet(eventIds, failedIds); } return [2 /*return*/]; } _b = 0, _c = Object.entries(regexPatterns); _e.label = 1; case 1: if (!(_b < _c.length)) return [3 /*break*/, 4]; _d = _c[_b], pattern = _d[0], eventIds = _d[1]; regex = getOrCompileRegex(pattern); if (regex === null) { // Pattern was unsafe or invalid - skip (warning already logged) return [3 /*break*/, 3]; } return [4 /*yield*/, testRegexWithTimeout(regex, value, 1000)]; case 2: matched = _e.sent(); if (!matched) { addIdsToSet(eventIds, failedIds); } _e.label = 3; case 3: _b++; return [3 /*break*/, 1]; case 4: return [2 /*return*/]; } }); }); } /** * Checks min/max range constraint. */ function checkMinMaxRanges(value, minMaxRanges, failedIds) { if (typeof value !== "number") { for (var _i = 0, _a = Object.values(minMaxRanges); _i < _a.length; _i++) { var eventIds = _a[_i]; addIdsToSet(eventIds, failedIds); } return; } if (Number.isNaN(value)) { console.warn("[Avo Inspector] NaN value fails min/max constraint"); for (var _b = 0, _c = Object.values(minMaxRanges); _b < _c.length; _b++) { var eventIds = _c[_b]; addIdsToSet(eventIds, failedIds); } return; } for (var _d = 0, _e = Object.entries(minMaxRanges); _d < _e.length; _d++) { var _f = _e[_d], rangeStr = _f[0], eventIds = _f[1]; var _g = rangeStr.split(","), minStr = _g[0], maxStr = _g[1]; var hasMin = minStr !== "" && minStr !== undefined; var hasMax = maxStr !== "" && maxStr !== undefined; var min = hasMin ? parseFloat(minStr) : -Infinity; var max = hasMax ? parseFloat(maxStr) : Infinity; if ((hasMin && isNaN(min)) || (hasMax && isNaN(max))) { console.warn("[Avo Inspector] Invalid min/max range: ".concat(rangeStr)); continue; } if (value < min || value > max) { addIdsToSet(eventIds, failedIds); } } }