UNPKG

autotel

Version:
146 lines (144 loc) 4.24 kB
import { AsyncLocalStorage } from 'async_hooks'; // src/validation.ts var DEFAULT_CONFIG = { maxEventNameLength: 100, maxAttributeKeyLength: 100, maxAttributeValueLength: 1e3, maxAttributeCount: 50, maxNestingDepth: 3, sensitivePatterns: [ /password/i, /secret/i, /token/i, /api[_-]?key/i, /access[_-]?key/i, /private[_-]?key/i, /auth/i, /credential/i, /ssn/i, /credit[_-]?card/i ] }; var ValidationError = class extends Error { constructor(message) { super(message); this.name = "ValidationError"; } }; function validateEventName(eventName, config = DEFAULT_CONFIG) { if (typeof eventName !== "string") { throw new ValidationError( `Event name must be a string, got ${typeof eventName}` ); } const trimmed = eventName.trim(); if (trimmed.length === 0) { throw new ValidationError("Event name cannot be empty"); } if (trimmed.length > config.maxEventNameLength) { throw new ValidationError( `Event name too long (${trimmed.length} chars). Max: ${config.maxEventNameLength}` ); } if (!/^[a-zA-Z0-9._-]+$/.test(trimmed)) { throw new ValidationError( `Event name contains invalid characters: "${trimmed}". Use only letters, numbers, dots, underscores, and hyphens.` ); } return trimmed; } function validateAttributes(attributes, config = DEFAULT_CONFIG) { if (attributes === void 0 || attributes === null) { return void 0; } if (typeof attributes !== "object" || Array.isArray(attributes)) { throw new ValidationError("Attributes must be an object"); } const keys = Object.keys(attributes); if (keys.length > config.maxAttributeCount) { throw new ValidationError( `Too many attributes (${keys.length}). Max: ${config.maxAttributeCount}` ); } const sanitized = {}; for (const key of keys) { if (key.length > config.maxAttributeKeyLength) { throw new ValidationError( `Attribute key too long: "${key.slice(0, 20)}..." (${key.length} chars). Max: ${config.maxAttributeKeyLength}` ); } const isSensitive = config.sensitivePatterns.some( (pattern) => pattern.test(key) ); if (isSensitive) { sanitized[key] = "[REDACTED]"; continue; } const value = attributes[key]; sanitized[key] = sanitizeValue(value, config, 1); } return sanitized; } function sanitizeValue(value, config, depth) { if (depth > config.maxNestingDepth) { return "[MAX_DEPTH_EXCEEDED]"; } if (value === null || value === void 0) { return value; } if (typeof value === "string") { if (value.length > config.maxAttributeValueLength) { return value.slice(0, config.maxAttributeValueLength) + "..."; } return value; } if (typeof value === "number" || typeof value === "boolean") { return value; } if (Array.isArray(value)) { return value.map((item) => sanitizeValue(item, config, depth + 1)); } if (typeof value === "object") { try { JSON.stringify(value); const sanitized = {}; for (const key in value) { if (Object.prototype.hasOwnProperty.call(value, key)) { const isSensitive = config.sensitivePatterns.some( (pattern) => pattern.test(key) ); if (isSensitive) { sanitized[key] = "[REDACTED]"; } else { sanitized[key] = sanitizeValue( value[key], config, depth + 1 ); } } } return sanitized; } catch { return "[CIRCULAR]"; } } return `[${typeof value}]`; } function validateEvent(eventName, attributes, config) { const fullConfig = { ...DEFAULT_CONFIG, ...config }; return { eventName: validateEventName(eventName, fullConfig), attributes: validateAttributes(attributes, fullConfig) }; } var operationStorage = new AsyncLocalStorage(); function getOperationContext() { return operationStorage.getStore(); } function runInOperationContext(name, fn) { return operationStorage.run({ name }, fn); } export { getOperationContext, runInOperationContext, validateEvent }; //# sourceMappingURL=chunk-WD4RP6IV.js.map //# sourceMappingURL=chunk-WD4RP6IV.js.map