{"version":3,"file":"xss-prevention.mjs","sources":["../../../src/lib/security/xss-prevention.ts"],"sourcesContent":["/**\n * @fileoverview XSS Prevention Utilities\n * @module @/lib/security/xss-prevention\n *\n * Comprehensive XSS (Cross-Site Scripting) prevention utilities for the\n * Harbor React Framework. Provides input sanitization, output encoding,\n * dangerous content detection, and safe HTML rendering alternatives.\n *\n * @see https://owasp.org/www-community/attacks/xss/\n * @see https://cheatsheetseries.owasp.org/cheatsheets/Cross_Site_Scripting_Prevention_Cheat_Sheet.html\n *\n * @author Harbor Security Team\n * @version 1.0.0\n */\n\nimport type {\n  DangerousContentResult,\n  DangerousThreatType,\n  HTMLEncodingContext,\n  SafeHTMLResult,\n  SanitizationOptions,\n  SanitizedHTML,\n  TagTransformer,\n  ThreatDetail,\n} from './types';\nimport {\n  ALLOWED_HTML_ATTRIBUTES,\n  ALLOWED_HTML_TAGS,\n  ALLOWED_URL_SCHEMES,\n} from '@/config/security.config';\n\n// ============================================================================\n// Constants\n// ============================================================================\n\n/**\n * HTML entity encoding map\n */\nconst HTML_ENTITIES: Readonly<Record<string, string>> = {\n  '&': '&amp;',\n  '<': '&lt;',\n  '>': '&gt;',\n  '\"': '&quot;',\n  \"'\": '&#x27;',\n  '/': '&#x2F;',\n  '`': '&#x60;',\n  '=': '&#x3D;',\n};\n\n/**\n * Reverse HTML entity map for decoding\n */\nconst HTML_ENTITY_DECODE: Readonly<Record<string, string>> = {\n  '&amp;': '&',\n  '&lt;': '<',\n  '&gt;': '>',\n  '&quot;': '\"',\n  '&#x27;': \"'\",\n  '&#39;': \"'\",\n  '&#x2F;': '/',\n  '&#x60;': '`',\n  '&#x3D;': '=',\n  '&nbsp;': ' ',\n};\n\n/**\n * JavaScript escape sequences for string context\n */\nconst JS_ESCAPE: Readonly<Record<string, string>> = {\n  '\\\\': '\\\\\\\\',\n  \"'\": \"\\\\'\",\n  '\"': '\\\\\"',\n  '\\n': '\\\\n',\n  '\\r': '\\\\r',\n  '\\t': '\\\\t',\n  '\\0': '\\\\0',\n  '<': '\\\\x3c',\n  '>': '\\\\x3e',\n  '/': '\\\\/',\n};\n\n/**\n * Dangerous patterns for XSS detection\n */\nconst DANGEROUS_PATTERNS: ReadonlyArray<{\n  pattern: RegExp;\n  type: DangerousThreatType;\n  severity: 'low' | 'medium' | 'high' | 'critical';\n  recommendation: string;\n}> = [\n  // Script injection\n  {\n    pattern: /<script[\\s\\S]*?>[\\s\\S]*?<\\/script>/gi,\n    type: 'script-injection',\n    severity: 'critical',\n    recommendation: 'Remove all script tags from user content',\n  },\n  {\n    pattern: /<script[^>]*>/gi,\n    type: 'script-injection',\n    severity: 'critical',\n    recommendation: 'Remove script opening tags',\n  },\n  // Event handlers\n  {\n    pattern: /\\bon\\w+\\s*=/gi,\n    type: 'event-handler',\n    severity: 'critical',\n    recommendation: 'Remove all on* event handler attributes',\n  },\n  // JavaScript URLs\n  {\n    pattern: /javascript\\s*:/gi,\n    type: 'javascript-url',\n    severity: 'critical',\n    recommendation: 'Remove javascript: protocol URLs',\n  },\n  {\n    pattern: /vbscript\\s*:/gi,\n    type: 'javascript-url',\n    severity: 'critical',\n    recommendation: 'Remove vbscript: protocol URLs',\n  },\n  // Data URLs with potential script content\n  {\n    pattern: /data\\s*:\\s*text\\/html/gi,\n    type: 'data-url',\n    severity: 'high',\n    recommendation: 'Remove data: URLs with HTML content type',\n  },\n  {\n    pattern: /data\\s*:\\s*[^,]*;base64/gi,\n    type: 'data-url',\n    severity: 'medium',\n    recommendation: 'Validate data: URLs carefully',\n  },\n  // SVG scripts\n  {\n    pattern: /<svg[\\s\\S]*?onload/gi,\n    type: 'svg-script',\n    severity: 'critical',\n    recommendation: 'Remove SVG elements with event handlers',\n  },\n  {\n    pattern: /<svg[\\s\\S]*?<script/gi,\n    type: 'svg-script',\n    severity: 'critical',\n    recommendation: 'Remove SVG elements containing scripts',\n  },\n  // Meta refresh\n  {\n    pattern: /<meta[^>]*http-equiv\\s*=\\s*[\"']?refresh/gi,\n    type: 'meta-refresh',\n    severity: 'high',\n    recommendation: 'Remove meta refresh tags',\n  },\n  // Iframe injection\n  {\n    pattern: /<iframe[\\s\\S]*?>/gi,\n    type: 'iframe-injection',\n    severity: 'high',\n    recommendation: 'Remove or validate iframe elements',\n  },\n  // Object/embed injection\n  {\n    pattern: /<(?:object|embed|applet)[\\s\\S]*?>/gi,\n    type: 'object-embed',\n    severity: 'critical',\n    recommendation: 'Remove object, embed, and applet elements',\n  },\n  // Base tag hijacking\n  {\n    pattern: /<base[\\s\\S]*?>/gi,\n    type: 'base-hijack',\n    severity: 'critical',\n    recommendation: 'Remove base tags from user content',\n  },\n  // Form action hijacking\n  {\n    pattern: /<form[\\s\\S]*?action\\s*=/gi,\n    type: 'form-action-hijack',\n    severity: 'high',\n    recommendation: 'Validate form action URLs',\n  },\n  // CSS expressions (legacy IE)\n  {\n    pattern: /expression\\s*\\(/gi,\n    type: 'css-expression',\n    severity: 'medium',\n    recommendation: 'Remove CSS expression() calls',\n  },\n  {\n    pattern: /url\\s*\\(\\s*[\"']?\\s*javascript:/gi,\n    type: 'css-expression',\n    severity: 'critical',\n    recommendation: 'Remove javascript: URLs in CSS',\n  },\n  // Encoded payloads\n  {\n    pattern: /&#x?[0-9a-f]+;?\\s*(?:&#x?[0-9a-f]+;?\\s*){3,}/gi,\n    type: 'encoded-payload',\n    severity: 'medium',\n    recommendation: 'Decode and validate HTML entities',\n  },\n  // Template injection (for template engines)\n  {\n    pattern: /\\{\\{[\\s\\S]*?\\}\\}/g,\n    type: 'template-injection',\n    severity: 'medium',\n    recommendation: 'Escape template delimiters',\n  },\n  {\n    pattern: /\\$\\{[\\s\\S]*?\\}/g,\n    type: 'template-injection',\n    severity: 'medium',\n    recommendation: 'Escape template literals',\n  },\n];\n\n/**\n * Dangerous tag names that should always be removed\n */\nconst DANGEROUS_TAGS: ReadonlySet<string> = new Set([\n  'script',\n  'style',\n  'link',\n  'meta',\n  'base',\n  'object',\n  'embed',\n  'applet',\n  'form',\n  'input',\n  'button',\n  'select',\n  'textarea',\n  'iframe',\n  'frame',\n  'frameset',\n  'layer',\n  'ilayer',\n  'bgsound',\n  'title',\n  'head',\n  'html',\n  'body',\n  'xml',\n  'blink',\n  'marquee',\n  'plaintext',\n  'xmp',\n  'noscript',\n  'template',\n]);\n\n/**\n * Dangerous attributes that should always be removed\n */\nconst DANGEROUS_ATTRIBUTES: ReadonlySet<string> = new Set([\n  // Event handlers\n  'onabort',\n  'onafterprint',\n  'onanimationend',\n  'onanimationiteration',\n  'onanimationstart',\n  'onauxclick',\n  'onbeforecopy',\n  'onbeforecut',\n  'onbeforeinput',\n  'onbeforepaste',\n  'onbeforeprint',\n  'onbeforeunload',\n  'onblur',\n  'oncancel',\n  'oncanplay',\n  'oncanplaythrough',\n  'onchange',\n  'onclick',\n  'onclose',\n  'oncontextmenu',\n  'oncopy',\n  'oncuechange',\n  'oncut',\n  'ondblclick',\n  'ondrag',\n  'ondragend',\n  'ondragenter',\n  'ondragleave',\n  'ondragover',\n  'ondragstart',\n  'ondrop',\n  'ondurationchange',\n  'onemptied',\n  'onended',\n  'onerror',\n  'onfocus',\n  'onfocusin',\n  'onfocusout',\n  'onformdata',\n  'onfullscreenchange',\n  'onfullscreenerror',\n  'ongotpointercapture',\n  'onhashchange',\n  'oninput',\n  'oninvalid',\n  'onkeydown',\n  'onkeypress',\n  'onkeyup',\n  'onlanguagechange',\n  'onload',\n  'onloadeddata',\n  'onloadedmetadata',\n  'onloadstart',\n  'onlostpointercapture',\n  'onmessage',\n  'onmessageerror',\n  'onmousedown',\n  'onmouseenter',\n  'onmouseleave',\n  'onmousemove',\n  'onmouseout',\n  'onmouseover',\n  'onmouseup',\n  'onmousewheel',\n  'onoffline',\n  'ononline',\n  'onpagehide',\n  'onpageshow',\n  'onpaste',\n  'onpause',\n  'onplay',\n  'onplaying',\n  'onpointercancel',\n  'onpointerdown',\n  'onpointerenter',\n  'onpointerleave',\n  'onpointermove',\n  'onpointerout',\n  'onpointerover',\n  'onpointerup',\n  'onpopstate',\n  'onprogress',\n  'onratechange',\n  'onrejectionhandled',\n  'onreset',\n  'onresize',\n  'onscroll',\n  'onsearch',\n  'onseeked',\n  'onseeking',\n  'onselect',\n  'onselectionchange',\n  'onselectstart',\n  'onshow',\n  'onstalled',\n  'onstorage',\n  'onsubmit',\n  'onsuspend',\n  'ontimeupdate',\n  'ontoggle',\n  'ontouchcancel',\n  'ontouchend',\n  'ontouchmove',\n  'ontouchstart',\n  'ontransitioncancel',\n  'ontransitionend',\n  'ontransitionrun',\n  'ontransitionstart',\n  'onunhandledrejection',\n  'onunload',\n  'onvolumechange',\n  'onwaiting',\n  'onwebkitanimationend',\n  'onwebkitanimationiteration',\n  'onwebkitanimationstart',\n  'onwebkittransitionend',\n  'onwheel',\n  // Other dangerous attributes\n  'formaction',\n  'xlink:href',\n  'xmlns',\n]);\n\n// ============================================================================\n// Encoding Functions\n// ============================================================================\n\n/**\n * Encode a string for safe insertion into HTML content\n * @param input - The string to encode\n * @returns HTML-encoded string\n */\nexport function encodeHTML(input: string): string {\n  if (!input) return '';\n\n  return input.replace(/[&<>\"'`=/]/g, (char) => HTML_ENTITIES[char] ?? char);\n}\n\n/**\n * Encode a string for safe insertion into an HTML attribute\n * More aggressive encoding than content encoding\n * @param input - The string to encode\n * @returns Attribute-safe encoded string\n */\nexport function encodeHTMLAttribute(input: string): string {\n  if (!input) return '';\n\n  // Encode all non-alphanumeric characters\n  return input.replace(/[^a-zA-Z0-9]/g, (char) => {\n    const code = char.charCodeAt(0);\n    if (code < 256) {\n      return `&#x${code.toString(16).padStart(2, '0')};`;\n    }\n    return `&#x${code.toString(16)};`;\n  });\n}\n\n/**\n * Encode a string for safe insertion into JavaScript context\n * @param input - The string to encode\n * @returns JavaScript-safe encoded string\n */\nexport function encodeJavaScript(input: string): string {\n  if (!input) return '';\n\n  return input.replace(/[\\\\'\"\\n\\r\\t\\0<>/]/g, (char) => JS_ESCAPE[char] ?? char);\n}\n\n/**\n * Encode a string for safe insertion into CSS context\n * @param input - The string to encode\n * @returns CSS-safe encoded string\n */\nexport function encodeCSS(input: string): string {\n  if (!input) return '';\n\n  // Encode non-alphanumeric characters as CSS escape sequences\n  return input.replace(/[^a-zA-Z0-9]/g, (char) => {\n    const code = char.charCodeAt(0);\n    return `\\\\${code.toString(16)} `;\n  });\n}\n\n/**\n * Encode a string for safe insertion into a URL\n * @param input - The string to encode\n * @returns URL-encoded string\n */\nexport function encodeURL(input: string): string {\n  if (!input) return '';\n\n  return encodeURIComponent(input);\n}\n\n/**\n * Encode a string for safe use as a URL parameter\n * @param input - The string to encode\n * @returns URL parameter safe string\n */\nexport function encodeURLParam(input: string): string {\n  if (!input) return '';\n\n  // encodeURIComponent doesn't encode: !'()*\n  return encodeURIComponent(input).replace(\n    /[!'()*]/g,\n    (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`\n  );\n}\n\n/**\n * Context-aware encoding function\n * @param input - The string to encode\n * @param context - The encoding context\n * @returns Encoded string\n */\nexport function encodeForContext(input: string, context: HTMLEncodingContext): string {\n  switch (context) {\n    case 'html-content':\n      return encodeHTML(input);\n    case 'html-attribute':\n      return encodeHTMLAttribute(input);\n    case 'javascript':\n      return encodeJavaScript(input);\n    case 'css':\n      return encodeCSS(input);\n    case 'url':\n      return encodeURL(input);\n    case 'url-param':\n      return encodeURLParam(input);\n    default: {\n      // Exhaustive check\n\n      return context;\n    }\n  }\n}\n\n/**\n * Decode HTML entities\n * @param input - The string with HTML entities\n * @returns Decoded string\n */\nexport function decodeHTML(input: string): string {\n  if (!input) return '';\n\n  // First decode named entities\n  let result = input;\n  for (const [entity, char] of Object.entries(HTML_ENTITY_DECODE)) {\n    result = result.replace(new RegExp(entity, 'gi'), char);\n  }\n\n  // Decode numeric entities\n  result = result.replace(/&#x([0-9a-f]+);?/gi, (_, hex: string) =>\n    String.fromCharCode(parseInt(hex, 16))\n  );\n  result = result.replace(/&#(\\d+);?/g, (_, dec: string) => String.fromCharCode(parseInt(dec, 10)));\n\n  return result;\n}\n\n// ============================================================================\n// Sanitization Functions\n// ============================================================================\n\n/**\n * Default sanitization options\n */\nconst DEFAULT_SANITIZATION_OPTIONS: Required<SanitizationOptions> = {\n  allowedTags: ALLOWED_HTML_TAGS,\n  allowedAttributes: ALLOWED_HTML_ATTRIBUTES,\n  allowedSchemes: ALLOWED_URL_SCHEMES,\n  allowDataUrls: false,\n  stripAllHtml: false,\n  maxLength: 100000, // 100KB\n  transformTags: {},\n};\n\n/**\n * Sanitize HTML content\n * Removes dangerous elements and attributes while preserving safe content\n *\n * @param input - The HTML string to sanitize\n * @param options - Sanitization options\n * @returns Safe HTML result\n */\nexport function sanitizeHTML(input: string, options: SanitizationOptions = {}): SafeHTMLResult {\n  const opts = { ...DEFAULT_SANITIZATION_OPTIONS, ...options };\n  const removedItems: string[] = [];\n  const warnings: string[] = [];\n\n  if (!input) {\n    return {\n      html: '',\n      wasModified: false,\n      removedItems: [],\n      warnings: [],\n    };\n  }\n\n  // Enforce max length\n  let html = input;\n  if (html.length > opts.maxLength) {\n    html = html.slice(0, opts.maxLength);\n    warnings.push(`Content truncated to ${opts.maxLength} characters`);\n  }\n\n  // Strip all HTML if requested\n  if (opts.stripAllHtml) {\n    const stripped = stripTags(html);\n    return {\n      html: encodeHTML(stripped),\n      wasModified: html !== stripped,\n      removedItems: ['[all HTML tags]'],\n      warnings,\n    };\n  }\n\n  // Parse and sanitize\n  const parser = new DOMParser();\n  const doc = parser.parseFromString(`<div id=\"sanitize-root\">${html}</div>`, 'text/html');\n  const root = doc.getElementById('sanitize-root');\n\n  if (!root) {\n    return {\n      html: encodeHTML(input),\n      wasModified: true,\n      removedItems: ['[failed to parse]'],\n      warnings: ['Failed to parse HTML content'],\n    };\n  }\n\n  // Walk the DOM and sanitize\n  sanitizeNode(root, opts, removedItems);\n\n  const sanitized = root.innerHTML;\n\n  return {\n    html: sanitized as SanitizedHTML,\n    wasModified: sanitized !== input,\n    removedItems,\n    warnings,\n  };\n}\n\n/**\n * Recursively sanitize a DOM node\n */\nfunction sanitizeNode(\n  node: Node,\n  opts: Required<SanitizationOptions>,\n  removedItems: string[]\n): void {\n  const nodesToRemove: Node[] = [];\n\n  for (const child of Array.from(node.childNodes)) {\n    if (child.nodeType === Node.ELEMENT_NODE) {\n      const element = child as Element;\n      const tagName = element.tagName.toLowerCase();\n\n      // Check if tag is allowed\n      if (!isAllowedTag(tagName, opts.allowedTags)) {\n        nodesToRemove.push(element);\n        removedItems.push(`<${tagName}>`);\n        continue;\n      }\n\n      // Apply tag transformers\n      const transformer = opts.transformTags[tagName];\n      if (transformer) {\n        const attrs: Record<string, string> = {};\n        for (const attr of Array.from(element.attributes)) {\n          attrs[attr.name] = attr.value;\n        }\n\n        const result = transformer(tagName, attrs);\n        if (result === null) {\n          nodesToRemove.push(element);\n          removedItems.push(`<${tagName}> (transformer rejected)`);\n          continue;\n        }\n\n        // Apply transformed attributes\n        for (const attr of Array.from(element.attributes)) {\n          if (!(attr.name in result.attributes)) {\n            element.removeAttribute(attr.name);\n          }\n        }\n        for (const [name, value] of Object.entries(result.attributes)) {\n          element.setAttribute(name, value);\n        }\n      }\n\n      // Sanitize attributes\n      sanitizeAttributes(element, opts, removedItems);\n\n      // Recursively sanitize children\n      sanitizeNode(element, opts, removedItems);\n    } else if (child.nodeType === Node.COMMENT_NODE) {\n      // Remove comments (can contain conditional IE code)\n      nodesToRemove.push(child);\n      removedItems.push('<!-- comment -->');\n    }\n  }\n\n  // Remove collected nodes\n  for (const nodeToRemove of nodesToRemove) {\n    nodeToRemove.parentNode?.removeChild(nodeToRemove);\n  }\n}\n\n/**\n * Sanitize element attributes\n */\nfunction sanitizeAttributes(\n  element: Element,\n  opts: Required<SanitizationOptions>,\n  removedItems: string[]\n): void {\n  const tagName = element.tagName.toLowerCase();\n  const attributesToRemove: string[] = [];\n\n  for (const attr of Array.from(element.attributes)) {\n    const attrName = attr.name.toLowerCase();\n\n    // Check if attribute is dangerous\n    if (isDangerousAttribute(attrName)) {\n      attributesToRemove.push(attrName);\n      removedItems.push(`${attrName} (dangerous)`);\n      continue;\n    }\n\n    // Check if attribute is allowed for this tag\n    if (!isAllowedAttribute(tagName, attrName, opts.allowedAttributes)) {\n      attributesToRemove.push(attrName);\n      removedItems.push(`${attrName} on <${tagName}>`);\n      continue;\n    }\n\n    // Validate URL attributes\n    if (isUrlAttribute(attrName)) {\n      const sanitizedUrl = sanitizeUrl(attr.value, opts.allowedSchemes, opts.allowDataUrls);\n      if (sanitizedUrl === null) {\n        attributesToRemove.push(attrName);\n        removedItems.push(`${attrName}=\"${attr.value}\" (invalid URL)`);\n      } else if (sanitizedUrl !== attr.value) {\n        element.setAttribute(attrName, sanitizedUrl);\n      }\n    }\n  }\n\n  // Remove collected attributes\n  for (const attrName of attributesToRemove) {\n    element.removeAttribute(attrName);\n  }\n}\n\n/**\n * Check if a tag is allowed\n */\nfunction isAllowedTag(tagName: string, allowedTags: readonly string[]): boolean {\n  // Dangerous tags are never allowed\n  if (DANGEROUS_TAGS.has(tagName)) {\n    return false;\n  }\n  return allowedTags.includes(tagName);\n}\n\n/**\n * Check if an attribute is dangerous\n */\nfunction isDangerousAttribute(attrName: string): boolean {\n  // Check exact match\n  if (DANGEROUS_ATTRIBUTES.has(attrName)) {\n    return true;\n  }\n\n  // Check for event handlers (on*)\n  return attrName.startsWith('on');\n}\n\n/**\n * Check if an attribute is allowed for a tag\n */\nfunction isAllowedAttribute(\n  tagName: string,\n  attrName: string,\n  allowedAttributes: Readonly<Record<string, readonly string[]>>\n): boolean {\n  // Check global attributes\n  const globalAttrs = allowedAttributes['*'] ?? [];\n  if (matchesAttributePattern(attrName, globalAttrs)) {\n    return true;\n  }\n\n  // Check tag-specific attributes\n  const tagAttrs = allowedAttributes[tagName];\n  return !!(tagAttrs && matchesAttributePattern(attrName, tagAttrs));\n}\n\n/**\n * Check if attribute matches any pattern in the list\n */\nfunction matchesAttributePattern(attrName: string, patterns: readonly string[]): boolean {\n  for (const pattern of patterns) {\n    if (pattern.endsWith('*')) {\n      const prefix = pattern.slice(0, -1);\n      if (attrName.startsWith(prefix)) {\n        return true;\n      }\n    } else if (pattern === attrName) {\n      return true;\n    }\n  }\n  return false;\n}\n\n/**\n * Check if attribute is a URL attribute\n */\nfunction isUrlAttribute(attrName: string): boolean {\n  return ['href', 'src', 'action', 'formaction', 'data', 'poster', 'srcset'].includes(attrName);\n}\n\n/**\n * Sanitize a URL value\n */\nfunction sanitizeUrl(\n  url: string,\n  allowedSchemes: readonly string[],\n  allowDataUrls: boolean\n): string | null {\n  const trimmed = url.trim();\n\n  // Empty URLs are allowed\n  if (!trimmed) {\n    return '';\n  }\n\n  // Check for javascript: and other dangerous protocols\n  const lowerUrl = trimmed.toLowerCase().replace(/\\s+/g, '');\n  if (\n    lowerUrl.startsWith('javascript:') ||\n    lowerUrl.startsWith('vbscript:') ||\n    lowerUrl.startsWith('data:text/html')\n  ) {\n    return null;\n  }\n\n  // Handle data: URLs\n  if (lowerUrl.startsWith('data:')) {\n    if (!allowDataUrls) {\n      return null;\n    }\n    // Only allow safe data URL types\n    if (\n      !lowerUrl.startsWith('data:image/') &&\n      !lowerUrl.startsWith('data:audio/') &&\n      !lowerUrl.startsWith('data:video/')\n    ) {\n      return null;\n    }\n  }\n\n  // Check scheme\n  try {\n    const parsed = new URL(trimmed, 'https://example.com');\n    const scheme = parsed.protocol.slice(0, -1); // Remove trailing :\n\n    // Relative URLs are okay\n    if (trimmed.startsWith('/') || trimmed.startsWith('.')) {\n      return trimmed;\n    }\n\n    // Check allowed schemes\n    if (!allowedSchemes.includes(scheme)) {\n      return null;\n    }\n  } catch {\n    // If URL parsing fails, check if it's a relative URL\n    if (!trimmed.includes(':')) {\n      return trimmed;\n    }\n    return null;\n  }\n\n  return trimmed;\n}\n\n/**\n * Strip all HTML tags from a string\n */\nexport function stripTags(input: string): string {\n  if (!input) return '';\n\n  // Use DOM parser for accurate tag stripping\n  const parser = new DOMParser();\n  const doc = parser.parseFromString(input, 'text/html');\n  return doc.body.textContent ?? '';\n}\n\n// ============================================================================\n// Dangerous Content Detection\n// ============================================================================\n\n/**\n * Detect dangerous content in input\n * @param input - The content to analyze\n * @returns Detection result with threat details\n */\nexport function detectDangerousContent(input: string): DangerousContentResult {\n  if (!input) {\n    return {\n      isDangerous: false,\n      threats: [],\n      details: [],\n      sanitized: '',\n    };\n  }\n\n  const threats: DangerousThreatType[] = [];\n  const details: ThreatDetail[] = [];\n\n  // Check against all dangerous patterns\n  for (const { pattern, type, severity, recommendation } of DANGEROUS_PATTERNS) {\n    // Clone regex to reset lastIndex\n    const regex = new RegExp(pattern.source, pattern.flags);\n    let match: RegExpExecArray | null;\n\n    while ((match = regex.exec(input)) !== null) {\n      if (!threats.includes(type)) {\n        threats.push(type);\n      }\n\n      details.push({\n        type,\n        pattern: pattern.source,\n        position: match.index,\n        match: match[0],\n        severity,\n        recommendation,\n      });\n    }\n  }\n\n  // Sanitize the content\n  const { html: sanitized } = sanitizeHTML(input);\n\n  return {\n    isDangerous: threats.length > 0,\n    threats,\n    details,\n    sanitized,\n  };\n}\n\n/**\n * Check if content contains any dangerous patterns\n * Fast check without detailed analysis\n */\nexport function isDangerous(input: string): boolean {\n  if (!input) return false;\n\n  for (const { pattern } of DANGEROUS_PATTERNS) {\n    if (pattern.test(input)) {\n      return true;\n    }\n  }\n\n  return false;\n}\n\n// ============================================================================\n// Safe Alternatives to dangerouslySetInnerHTML\n// ============================================================================\n\n/**\n * Create safe props for setting HTML content in React\n * @param content - The HTML content\n * @param options - Sanitization options\n * @returns Props object for React element\n */\nexport function createSafeHTMLProps(\n  content: string,\n  options?: SanitizationOptions\n): { dangerouslySetInnerHTML: { __html: string } } {\n  const { html } = sanitizeHTML(content, options);\n  return {\n    dangerouslySetInnerHTML: { __html: html },\n  };\n}\n\n/**\n * Create a text-only version (no HTML)\n * @param content - The HTML content\n * @returns Plain text props\n */\nexport function createTextOnlyProps(content: string): { children: string } {\n  const text = stripTags(decodeHTML(content));\n  return { children: text };\n}\n\n// ============================================================================\n// Validation Functions\n// ============================================================================\n\n/**\n * Validate that a string is safe for the given context\n */\nexport function isContextSafe(input: string, context: HTMLEncodingContext): boolean {\n  switch (context) {\n    case 'html-content':\n      return !/<[^>]*>/g.test(input);\n    case 'html-attribute':\n      return !/[\"'<>&]/g.test(input);\n    case 'javascript':\n      return !/[\\\\'\"\\n\\r\\t\\0<>]/g.test(input);\n    case 'css':\n      return !/[{}<>()\\\\;]/g.test(input);\n    case 'url':\n    case 'url-param':\n      return !/[^a-zA-Z0-9\\-._~]/g.test(input);\n    default:\n      return false;\n  }\n}\n\n/**\n * Validate an email address format\n */\nexport function isValidEmail(email: string): boolean {\n  // RFC 5322 compliant regex (simplified)\n  const emailRegex =\n    /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n  return emailRegex.test(email);\n}\n\n/**\n * Validate a URL format\n */\nexport function isValidURL(url: string): boolean {\n  try {\n    const parsed = new URL(url);\n    return ['http:', 'https:'].includes(parsed.protocol);\n  } catch {\n    return false;\n  }\n}\n\n// ============================================================================\n// React-specific Utilities\n// ============================================================================\n\n/**\n * Create a safe ref callback that validates innerHTML\n */\nexport function createSafeInnerHTMLRef(\n  html: string,\n  options?: SanitizationOptions\n): (element: HTMLElement | null) => void {\n  const { html: sanitized } = sanitizeHTML(html, options);\n\n  return (element: HTMLElement | null) => {\n    if (element) {\n      element.innerHTML = sanitized;\n    }\n  };\n}\n\n/**\n * Type guard for sanitized HTML\n */\nexport function isSanitizedHTML(value: unknown): value is SanitizedHTML {\n  if (typeof value !== 'string') {\n    return false;\n  }\n  const result = detectDangerousContent(value);\n  return !result.isDangerous;\n}\n\n/**\n * Assert that a string is sanitized HTML\n * @throws Error if content is dangerous\n */\nexport function assertSanitizedHTML(content: string): SanitizedHTML {\n  const result = detectDangerousContent(content);\n  if (result.isDangerous) {\n    throw new Error(`Content contains dangerous patterns: ${result.threats.join(', ')}`);\n  }\n  return content as SanitizedHTML;\n}\n\n// ============================================================================\n// Export Types\n// ============================================================================\n\nexport type {\n  HTMLEncodingContext,\n  SanitizationOptions,\n  DangerousContentResult,\n  DangerousThreatType,\n  ThreatDetail,\n  SafeHTMLResult,\n  SanitizedHTML,\n  TagTransformer,\n};\n"],"names":["HTML_ENTITIES","HTML_ENTITY_DECODE","JS_ESCAPE","DANGEROUS_PATTERNS","DANGEROUS_TAGS","DANGEROUS_ATTRIBUTES","encodeHTML","input","char","encodeHTMLAttribute","code","encodeJavaScript","encodeCSS","encodeURL","encodeURLParam","encodeForContext","context","decodeHTML","result","entity","_","hex","dec","DEFAULT_SANITIZATION_OPTIONS","ALLOWED_HTML_TAGS","ALLOWED_HTML_ATTRIBUTES","ALLOWED_URL_SCHEMES","sanitizeHTML","options","opts","removedItems","warnings","html","stripped","stripTags","root","sanitizeNode","sanitized","node","nodesToRemove","child","element","tagName","isAllowedTag","transformer","attrs","attr","name","value","sanitizeAttributes","nodeToRemove","attributesToRemove","attrName","isDangerousAttribute","isAllowedAttribute","isUrlAttribute","sanitizedUrl","sanitizeUrl","allowedTags","allowedAttributes","globalAttrs","matchesAttributePattern","tagAttrs","patterns","pattern","prefix","url","allowedSchemes","allowDataUrls","trimmed","lowerUrl","scheme","detectDangerousContent","threats","details","type","severity","recommendation","regex","match","isDangerous","createSafeHTMLProps","content","createTextOnlyProps","isContextSafe","isValidEmail","email","isValidURL","parsed","createSafeInnerHTMLRef","isSanitizedHTML","assertSanitizedHTML"],"mappings":"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AA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC,GAKKC,wBAAgD,IAAI;AAAA;AAAA,EAExD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAWM,SAASC,EAAWC,GAAuB;AAChD,SAAKA,IAEEA,EAAM,QAAQ,eAAe,CAACC,MAASR,EAAcQ,CAAI,KAAKA,CAAI,IAFtD;AAGrB;AAQO,SAASC,EAAoBF,GAAuB;AACzD,SAAKA,IAGEA,EAAM,QAAQ,iBAAiB,CAACC,MAAS;AAC9C,UAAME,IAAOF,EAAK,WAAW,CAAC;AAC9B,WAAIE,IAAO,MACF,MAAMA,EAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,MAE1C,MAAMA,EAAK,SAAS,EAAE,CAAC;AAAA,EAChC,CAAC,IATkB;AAUrB;AAOO,SAASC,EAAiBJ,GAAuB;AACtD,SAAKA,IAEEA,EAAM,QAAQ,sBAAsB,CAACC,MAASN,EAAUM,CAAI,KAAKA,CAAI,IAFzD;AAGrB;AAOO,SAASI,EAAUL,GAAuB;AAC/C,SAAKA,IAGEA,EAAM,QAAQ,iBAAiB,CAACC,MAE9B,KADMA,EAAK,WAAW,CAAC,EACb,SAAS,EAAE,CAAC,GAC9B,IANkB;AAOrB;AAOO,SAASK,EAAUN,GAAuB;AAC/C,SAAKA,IAEE,mBAAmBA,CAAK,IAFZ;AAGrB;AAOO,SAASO,EAAeP,GAAuB;AACpD,SAAKA,IAGE,mBAAmBA,CAAK,EAAE;AAAA,IAC/B;AAAA,IACA,CAACC,MAAS,IAAIA,EAAK,WAAW,CAAC,EAAE,SAAS,EAAE,EAAE,aAAa;AAAA,EAAA,IAL1C;AAOrB;AAQO,SAASO,EAAiBR,GAAeS,GAAsC;AACpF,UAAQA,GAAA;AAAA,IACN,KAAK;AACH,aAAOV,EAAWC,CAAK;AAAA,IACzB,KAAK;AACH,aAAOE,EAAoBF,CAAK;AAAA,IAClC,KAAK;AACH,aAAOI,EAAiBJ,CAAK;AAAA,IAC/B,KAAK;AACH,aAAOK,EAAUL,CAAK;AAAA,IACxB,KAAK;AACH,aAAOM,EAAUN,CAAK;AAAA,IACxB,KAAK;AACH,aAAOO,EAAeP,CAAK;AAAA,IAC7B;AAGE,aAAOS;AAAA,EACT;AAEJ;AAOO,SAASC,EAAWV,GAAuB;AAChD,MAAI,CAACA,EAAO,QAAO;AAGnB,MAAIW,IAASX;AACb,aAAW,CAACY,GAAQX,CAAI,KAAK,OAAO,QAAQP,CAAkB;AAC5D,IAAAiB,IAASA,EAAO,QAAQ,IAAI,OAAOC,GAAQ,IAAI,GAAGX,CAAI;AAIxD,SAAAU,IAASA,EAAO;AAAA,IAAQ;AAAA,IAAsB,CAACE,GAAGC,MAChD,OAAO,aAAa,SAASA,GAAK,EAAE,CAAC;AAAA,EAAA,GAEvCH,IAASA,EAAO,QAAQ,cAAc,CAACE,GAAGE,MAAgB,OAAO,aAAa,SAASA,GAAK,EAAE,CAAC,CAAC,GAEzFJ;AACT;AASA,MAAMK,IAA8D;AAAA,EAClE,aAAaC;AAAA,EACb,mBAAmBC;AAAA,EACnB,gBAAgBC;AAAA,EAChB,eAAe;AAAA,EACf,cAAc;AAAA,EACd,WAAW;AAAA;AAAA,EACX,eAAe,CAAA;AACjB;AAUO,SAASC,EAAapB,GAAeqB,IAA+B,IAAoB;AAC7F,QAAMC,IAAO,EAAE,GAAGN,GAA8B,GAAGK,EAAA,GAC7CE,IAAyB,CAAA,GACzBC,IAAqB,CAAA;AAE3B,MAAI,CAACxB;AACH,WAAO;AAAA,MACL,MAAM;AAAA,MACN,aAAa;AAAA,MACb,cAAc,CAAA;AAAA,MACd,UAAU,CAAA;AAAA,IAAC;AAKf,MAAIyB,IAAOzB;AAOX,MANIyB,EAAK,SAASH,EAAK,cACrBG,IAAOA,EAAK,MAAM,GAAGH,EAAK,SAAS,GACnCE,EAAS,KAAK,wBAAwBF,EAAK,SAAS,aAAa,IAI/DA,EAAK,cAAc;AACrB,UAAMI,IAAWC,EAAUF,CAAI;AAC/B,WAAO;AAAA,MACL,MAAM1B,EAAW2B,CAAQ;AAAA,MACzB,aAAaD,MAASC;AAAA,MACtB,cAAc,CAAC,iBAAiB;AAAA,MAChC,UAAAF;AAAA,IAAA;AAAA,EAEJ;AAKA,QAAMI,IAFS,IAAI,UAAA,EACA,gBAAgB,2BAA2BH,CAAI,UAAU,WAAW,EACtE,eAAe,eAAe;AAE/C,MAAI,CAACG;AACH,WAAO;AAAA,MACL,MAAM7B,EAAWC,CAAK;AAAA,MACtB,aAAa;AAAA,MACb,cAAc,CAAC,mBAAmB;AAAA,MAClC,UAAU,CAAC,8BAA8B;AAAA,IAAA;AAK7C,EAAA6B,EAAaD,GAAMN,GAAMC,CAAY;AAErC,QAAMO,IAAYF,EAAK;AAEvB,SAAO;AAAA,IACL,MAAME;AAAA,IACN,aAAaA,MAAc9B;AAAA,IAC3B,cAAAuB;AAAA,IACA,UAAAC;AAAA,EAAA;AAEJ;AAKA,SAASK,EACPE,GACAT,GACAC,GACM;AACN,QAAMS,IAAwB,CAAA;AAE9B,aAAWC,KAAS,MAAM,KAAKF,EAAK,UAAU;AAC5C,QAAIE,EAAM,aAAa,KAAK,cAAc;AACxC,YAAMC,IAAUD,GACVE,IAAUD,EAAQ,QAAQ,YAAA;AAGhC,UAAI,CAACE,EAAaD,GAASb,EAAK,WAAW,GAAG;AAC5C,QAAAU,EAAc,KAAKE,CAAO,GAC1BX,EAAa,KAAK,IAAIY,CAAO,GAAG;AAChC;AAAA,MACF;AAGA,YAAME,IAAcf,EAAK,cAAca,CAAO;AAC9C,UAAIE,GAAa;AACf,cAAMC,IAAgC,CAAA;AACtC,mBAAWC,KAAQ,MAAM,KAAKL,EAAQ,UAAU;AAC9C,UAAAI,EAAMC,EAAK,IAAI,IAAIA,EAAK;AAG1B,cAAM5B,IAAS0B,EAAYF,GAASG,CAAK;AACzC,YAAI3B,MAAW,MAAM;AACnB,UAAAqB,EAAc,KAAKE,CAAO,GAC1BX,EAAa,KAAK,IAAIY,CAAO,0BAA0B;AACvD;AAAA,QACF;AAGA,mBAAWI,KAAQ,MAAM,KAAKL,EAAQ,UAAU;AAC9C,UAAMK,EAAK,QAAQ5B,EAAO,cACxBuB,EAAQ,gBAAgBK,EAAK,IAAI;AAGrC,mBAAW,CAACC,GAAMC,CAAK,KAAK,OAAO,QAAQ9B,EAAO,UAAU;AAC1D,UAAAuB,EAAQ,aAAaM,GAAMC,CAAK;AAAA,MAEpC;AAGA,MAAAC,EAAmBR,GAASZ,GAAMC,CAAY,GAG9CM,EAAaK,GAASZ,GAAMC,CAAY;AAAA,IAC1C,MAAA,CAAWU,EAAM,aAAa,KAAK,iBAEjCD,EAAc,KAAKC,CAAK,GACxBV,EAAa,KAAK,kBAAkB;AAKxC,aAAWoB,KAAgBX;AACzB,IAAAW,EAAa,YAAY,YAAYA,CAAY;AAErD;AAKA,SAASD,EACPR,GACAZ,GACAC,GACM;AACN,QAAMY,IAAUD,EAAQ,QAAQ,YAAA,GAC1BU,IAA+B,CAAA;AAErC,aAAWL,KAAQ,MAAM,KAAKL,EAAQ,UAAU,GAAG;AACjD,UAAMW,IAAWN,EAAK,KAAK,YAAA;AAG3B,QAAIO,EAAqBD,CAAQ,GAAG;AAClC,MAAAD,EAAmB,KAAKC,CAAQ,GAChCtB,EAAa,KAAK,GAAGsB,CAAQ,cAAc;AAC3C;AAAA,IACF;AAGA,QAAI,CAACE,EAAmBZ,GAASU,GAAUvB,EAAK,iBAAiB,GAAG;AAClE,MAAAsB,EAAmB,KAAKC,CAAQ,GAChCtB,EAAa,KAAK,GAAGsB,CAAQ,QAAQV,CAAO,GAAG;AAC/C;AAAA,IACF;AAGA,QAAIa,EAAeH,CAAQ,GAAG;AAC5B,YAAMI,IAAeC,EAAYX,EAAK,OAAOjB,EAAK,gBAAgBA,EAAK,aAAa;AACpF,MAAI2B,MAAiB,QACnBL,EAAmB,KAAKC,CAAQ,GAChCtB,EAAa,KAAK,GAAGsB,CAAQ,KAAKN,EAAK,KAAK,iBAAiB,KACpDU,MAAiBV,EAAK,SAC/BL,EAAQ,aAAaW,GAAUI,CAAY;AAAA,IAE/C;AAAA,EACF;AAGA,aAAWJ,KAAYD;AACrB,IAAAV,EAAQ,gBAAgBW,CAAQ;AAEpC;AAKA,SAAST,EAAaD,GAAiBgB,GAAyC;AAE9E,SAAItD,EAAe,IAAIsC,CAAO,IACrB,KAEFgB,EAAY,SAAShB,CAAO;AACrC;AAKA,SAASW,EAAqBD,GAA2B;AAEvD,SAAI/C,EAAqB,IAAI+C,CAAQ,IAC5B,KAIFA,EAAS,WAAW,IAAI;AACjC;AAKA,SAASE,EACPZ,GACAU,GACAO,GACS;AAET,QAAMC,IAAcD,EAAkB,GAAG,KAAK,CAAA;AAC9C,MAAIE,EAAwBT,GAAUQ,CAAW;AAC/C,WAAO;AAIT,QAAME,IAAWH,EAAkBjB,CAAO;AAC1C,SAAO,CAAC,EAAEoB,KAAYD,EAAwBT,GAAUU,CAAQ;AAClE;AAKA,SAASD,EAAwBT,GAAkBW,GAAsC;AACvF,aAAWC,KAAWD;AACpB,QAAIC,EAAQ,SAAS,GAAG,GAAG;AACzB,YAAMC,IAASD,EAAQ,MAAM,GAAG,EAAE;AAClC,UAAIZ,EAAS,WAAWa,CAAM;AAC5B,eAAO;AAAA,IAEX,WAAWD,MAAYZ;AACrB,aAAO;AAGX,SAAO;AACT;AAKA,SAASG,EAAeH,GAA2B;AACjD,SAAO,CAAC,QAAQ,OAAO,UAAU,cAAc,QAAQ,UAAU,QAAQ,EAAE,SAASA,CAAQ;AAC9F;AAKA,SAASK,EACPS,GACAC,GACAC,GACe;AACf,QAAMC,IAAUH,EAAI,KAAA;AAGpB,MAAI,CAACG;AACH,WAAO;AAIT,QAAMC,IAAWD,EAAQ,YAAA,EAAc,QAAQ,QAAQ,EAAE;AAUzD,MAREC,EAAS,WAAW,aAAa,KACjCA,EAAS,WAAW,WAAW,KAC/BA,EAAS,WAAW,gBAAgB,KAMlCA,EAAS,WAAW,OAAO,MACzB,CAACF,KAKH,CAACE,EAAS,WAAW,aAAa,KAClC,CAACA,EAAS,WAAW,aAAa,KAClC,CAACA,EAAS,WAAW,aAAa;AAElC,WAAO;AAKX,MAAI;AAEF,UAAMC,IADS,IAAI,IAAIF,GAAS,qBAAqB,EAC/B,SAAS,MAAM,GAAG,EAAE;AAG1C,QAAIA,EAAQ,WAAW,GAAG,KAAKA,EAAQ,WAAW,GAAG;AACnD,aAAOA;AAIT,QAAI,CAACF,EAAe,SAASI,CAAM;AACjC,aAAO;AAAA,EAEX,QAAQ;AAEN,WAAKF,EAAQ,SAAS,GAAG,IAGlB,OAFEA;AAAA,EAGX;AAEA,SAAOA;AACT;AAKO,SAASnC,EAAU3B,GAAuB;AAC/C,SAAKA,IAGU,IAAI,UAAA,EACA,gBAAgBA,GAAO,WAAW,EAC1C,KAAK,eAAe,KALZ;AAMrB;AAWO,SAASiE,EAAuBjE,GAAuC;AAC5E,MAAI,CAACA;AACH,WAAO;AAAA,MACL,aAAa;AAAA,MACb,SAAS,CAAA;AAAA,MACT,SAAS,CAAA;AAAA,MACT,WAAW;AAAA,IAAA;AAIf,QAAMkE,IAAiC,CAAA,GACjCC,IAA0B,CAAA;AAGhC,aAAW,EAAE,SAAAV,GAAS,MAAAW,GAAM,UAAAC,GAAU,gBAAAC,EAAA,KAAoB1E,GAAoB;AAE5E,UAAM2E,IAAQ,IAAI,OAAOd,EAAQ,QAAQA,EAAQ,KAAK;AACtD,QAAIe;AAEJ,YAAQA,IAAQD,EAAM,KAAKvE,CAAK,OAAO;AACrC,MAAKkE,EAAQ,SAASE,CAAI,KACxBF,EAAQ,KAAKE,CAAI,GAGnBD,EAAQ,KAAK;AAAA,QACX,MAAAC;AAAA,QACA,SAASX,EAAQ;AAAA,QACjB,UAAUe,EAAM;AAAA,QAChB,OAAOA,EAAM,CAAC;AAAA,QACd,UAAAH;AAAA,QACA,gBAAAC;AAAA,MAAA,CACD;AAAA,EAEL;AAGA,QAAM,EAAE,MAAMxC,MAAcV,EAAapB,CAAK;AAE9C,SAAO;AAAA,IACL,aAAakE,EAAQ,SAAS;AAAA,IAC9B,SAAAA;AAAA,IACA,SAAAC;AAAA,IACA,WAAArC;AAAA,EAAA;AAEJ;AAMO,SAAS2C,EAAYzE,GAAwB;AAClD,MAAI,CAACA,EAAO,QAAO;AAEnB,aAAW,EAAE,SAAAyD,EAAA,KAAa7D;AACxB,QAAI6D,EAAQ,KAAKzD,CAAK;AACpB,aAAO;AAIX,SAAO;AACT;AAYO,SAAS0E,EACdC,GACAtD,GACiD;AACjD,QAAM,EAAE,MAAAI,EAAA,IAASL,EAAauD,GAAStD,CAAO;AAC9C,SAAO;AAAA,IACL,yBAAyB,EAAE,QAAQI,EAAA;AAAA,EAAK;AAE5C;AAOO,SAASmD,EAAoBD,GAAuC;AAEzE,SAAO,EAAE,UADIhD,EAAUjB,EAAWiE,CAAO,CAAC,EACvB;AACrB;AASO,SAASE,EAAc7E,GAAeS,GAAuC;AAClF,UAAQA,GAAA;AAAA,IACN,KAAK;AACH,aAAO,CAAC,WAAW,KAAKT,CAAK;AAAA,IAC/B,KAAK;AACH,aAAO,CAAC,WAAW,KAAKA,CAAK;AAAA,IAC/B,KAAK;AACH,aAAO,CAAC,oBAAoB,KAAKA,CAAK;AAAA,IACxC,KAAK;AACH,aAAO,CAAC,eAAe,KAAKA,CAAK;AAAA,IACnC,KAAK;AAAA,IACL,KAAK;AACH,aAAO,CAAC,qBAAqB,KAAKA,CAAK;AAAA,IACzC;AACE,aAAO;AAAA,EAAA;AAEb;AAKO,SAAS8E,EAAaC,GAAwB;AAInD,SADE,uIACgB,KAAKA,CAAK;AAC9B;AAKO,SAASC,EAAWrB,GAAsB;AAC/C,MAAI;AACF,UAAMsB,IAAS,IAAI,IAAItB,CAAG;AAC1B,WAAO,CAAC,SAAS,QAAQ,EAAE,SAASsB,EAAO,QAAQ;AAAA,EACrD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AASO,SAASC,EACdzD,GACAJ,GACuC;AACvC,QAAM,EAAE,MAAMS,EAAA,IAAcV,EAAaK,GAAMJ,CAAO;AAEtD,SAAO,CAACa,MAAgC;AACtC,IAAIA,MACFA,EAAQ,YAAYJ;AAAA,EAExB;AACF;AAKO,SAASqD,EAAgB1C,GAAwC;AACtE,SAAI,OAAOA,KAAU,WACZ,KAGF,CADQwB,EAAuBxB,CAAK,EAC5B;AACjB;AAMO,SAAS2C,EAAoBT,GAAgC;AAClE,QAAMhE,IAASsD,EAAuBU,CAAO;AAC7C,MAAIhE,EAAO;AACT,UAAM,IAAI,MAAM,wCAAwCA,EAAO,QAAQ,KAAK,IAAI,CAAC,EAAE;AAErF,SAAOgE;AACT;"}