sanitize-request
Version:
A TypeScript library for safe display and sanitization to prevent XSS attacks.
1 lines • 22.3 kB
Source Map (JSON)
{"version":3,"sources":["../src/utils/sanitizer.ts","../src/constants/sensitiveFields.ts","../src/logger.ts","../src/config/sanitizationConfigs.ts","../src/middleware/sanitizeRequest.ts","../src/middleware/sanitizeStrings.ts"],"sourcesContent":["import DOMPurify from 'isomorphic-dompurify';\r\nimport {\r\n SanitizationConfig,\r\n SanitizationResult,\r\n SanitizationMetadata,\r\n SanitizableInput\r\n} from '../types/sanitization';\r\nimport { SENSITIVE_FIELDS } from '../constants/sensitiveFields';\r\nimport { logger } from '../logger';\r\n\r\nexport class SanitizationError extends Error {\r\n constructor(message: string, public field?: string) {\r\n super(message);\r\n this.name = 'SanitizationError';\r\n }\r\n}\r\n\r\nclass Sanitizer {\r\n private config: Required<SanitizationConfig>;\r\n private metadata: SanitizationMetadata;\r\n\r\n constructor(config: SanitizationConfig) {\r\n this.config = {\r\n allowedTags: config.allowedTags || [],\r\n allowedAttributes: config.allowedAttributes || {},\r\n stripIgnoreTag: config.stripIgnoreTag ?? true,\r\n stripIgnoreTagBody: config.stripIgnoreTagBody ?? false,\r\n allowEmptyTags: config.allowEmptyTags ?? false,\r\n maxTagDepth: config.maxTagDepth ?? 10,\r\n maxStringLength: config.maxStringLength ?? 10000,\r\n };\r\n\r\n this.metadata = {\r\n sanitized: false,\r\n warnings: [],\r\n errors: [],\r\n fieldsModified: [],\r\n };\r\n }\r\n\r\n private sanitizeString(input: string, fieldName?: string): string {\r\n try {\r\n const originalLength = input.length;\r\n\r\n // Check string length\r\n if (originalLength > this.config.maxStringLength) {\r\n this.metadata.warnings.push(\r\n `String in field '${fieldName || 'unknown'}' truncated from ${originalLength} to ${this.config.maxStringLength} characters`\r\n );\r\n input = input.substring(0, this.config.maxStringLength);\r\n this.metadata.sanitized = true;\r\n }\r\n\r\n // Configure DOMPurify\r\n const purifyConfig: any = {\r\n ALLOWED_TAGS: this.config.allowedTags,\r\n ALLOWED_ATTR: Object.values(this.config.allowedAttributes).flat(),\r\n KEEP_CONTENT: !this.config.stripIgnoreTagBody,\r\n ALLOW_EMPTY_TAGS: this.config.allowEmptyTags,\r\n };\r\n\r\n const sanitized = DOMPurify.sanitize(input, purifyConfig) as unknown as string;;\r\n\r\n if (sanitized !== input) {\r\n this.metadata.sanitized = true;\r\n if (fieldName) {\r\n this.metadata.fieldsModified.push(fieldName);\r\n }\r\n }\r\n\r\n return sanitized;\r\n } catch (error) {\r\n const message = `Failed to sanitize string in field '${fieldName || 'unknown'}': ${error instanceof Error ? error.message : 'Unknown error'}`;\r\n this.metadata.errors = this.metadata.errors || [];\r\n this.metadata.errors.push(message);\r\n logger.error(message);\r\n throw new SanitizationError(message, fieldName);\r\n }\r\n }\r\n\r\n private sanitizeValue(value: any, fieldName?: string): any {\r\n if (value === null || value === undefined) {\r\n return value;\r\n }\r\n\r\n // Skip sensitive fields\r\n if (fieldName && SENSITIVE_FIELDS.includes(fieldName as any)) {\r\n return value;\r\n }\r\n\r\n if (typeof value === 'string') {\r\n return this.sanitizeString(value, fieldName);\r\n }\r\n\r\n if (Array.isArray(value)) {\r\n return value.map((item, index) =>\r\n this.sanitizeValue(item, fieldName ? `${fieldName}[${index}]` : `[${index}]`)\r\n );\r\n }\r\n\r\n if (value && typeof value === 'object') {\r\n const sanitizedObj: any = {};\r\n for (const [key, val] of Object.entries(value)) {\r\n const fullFieldName = fieldName ? `${fieldName}.${key}` : key;\r\n sanitizedObj[key] = this.sanitizeValue(val, fullFieldName);\r\n }\r\n return sanitizedObj;\r\n }\r\n\r\n return value;\r\n }\r\n\r\n public sanitize<T extends SanitizableInput>(input: T): SanitizationResult<T> {\r\n this.metadata = {\r\n sanitized: false,\r\n warnings: [],\r\n errors: [],\r\n fieldsModified: [],\r\n originalSize: JSON.stringify(input).length,\r\n };\r\n\r\n try {\r\n const sanitizedData = this.sanitizeValue(input) as T;\r\n this.metadata.finalSize = JSON.stringify(sanitizedData).length;\r\n\r\n return {\r\n data: sanitizedData,\r\n sanitized: this.metadata.sanitized,\r\n warnings: this.metadata.warnings,\r\n errors: this.metadata.errors?.length ? this.metadata.errors : undefined,\r\n };\r\n } catch (error) {\r\n if (error instanceof SanitizationError) {\r\n throw error;\r\n }\r\n\r\n const message = `Sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`;\r\n logger.error(message);\r\n throw new SanitizationError(message);\r\n }\r\n }\r\n\r\n public getMetadata(): SanitizationMetadata {\r\n return { ...this.metadata };\r\n }\r\n}\r\n\r\nexport const sanitizeRequestData = <T extends Record<string, any>>(\r\n data: T,\r\n config: SanitizationConfig\r\n): SanitizationResult<T> => {\r\n const sanitizer = new Sanitizer(config);\r\n return sanitizer.sanitize(data);\r\n};\r\n\r\nexport const sanitizeString = (\r\n input: string,\r\n config: SanitizationConfig\r\n): SanitizationResult<string> => {\r\n const sanitizer = new Sanitizer(config);\r\n return sanitizer.sanitize(input);\r\n};\r\n","export const SENSITIVE_FIELDS = [\r\n 'password',\r\n 'confirmPassword',\r\n 'passwordConfirm',\r\n 'adminPassword',\r\n 'token',\r\n 'accessToken',\r\n 'refreshToken',\r\n 'apiKey',\r\n 'secret',\r\n 'privateKey',\r\n 'jwt',\r\n 'sessionId',\r\n 'csrfToken',\r\n 'authToken',\r\n] as const;\r\n\r\nexport type SensitiveKey = typeof SENSITIVE_FIELDS[number];\r\n","export const logger = {\r\n info: (...args: unknown[]) => console.info('[info]', ...args),\r\n warn: (...args: unknown[]) => console.warn('[warn]', ...args),\r\n error: (...args: unknown[]) => console.error('[error]', ...args),\r\n debug: (...args: unknown[]) => console.debug('[debug]', ...args)\r\n};\r\n\r\n","import { SanitizationConfig } from '../types/sanitization';\r\n\r\nexport const BASE_CONFIG: SanitizationConfig = {\r\n allowedTags: ['b', 'i', 'em', 'strong', 'p', 'br', 'ul', 'ol', 'li', 'a'],\r\n allowedAttributes: { a: ['href', 'title'] },\r\n stripIgnoreTag: true,\r\n stripIgnoreTagBody: false,\r\n allowEmptyTags: false,\r\n maxTagDepth: 10,\r\n maxStringLength: 10000,\r\n};\r\n\r\nexport const STRICT_CONFIG: SanitizationConfig = {\r\n allowedTags: ['b', 'i', 'em', 'strong'],\r\n allowedAttributes: {},\r\n stripIgnoreTag: true,\r\n stripIgnoreTagBody: true,\r\n allowEmptyTags: false,\r\n maxTagDepth: 5,\r\n maxStringLength: 1000,\r\n};\r\n\r\nexport const LIBERAL_CONFIG: SanitizationConfig = {\r\n allowedTags: [\r\n 'h1','h2','h3','h4','h5','h6','p','br','hr',\r\n 'b','i','em','strong','u','s','sub','sup',\r\n 'ul','ol','li','a','img',\r\n 'blockquote','code','pre',\r\n 'table','thead','tbody','tr','th','td',\r\n 'div','span'\r\n ],\r\n allowedAttributes: {\r\n a: ['href', 'title', 'target', 'rel'],\r\n img: ['src', 'alt', 'title', 'width', 'height'],\r\n blockquote: ['cite'],\r\n table: ['class'],\r\n th: ['scope'],\r\n td: ['colspan', 'rowspan'],\r\n },\r\n allowEmptyTags: true,\r\n maxTagDepth: 20,\r\n maxStringLength: 50000,\r\n};\r\n\r\nexport const BLOG_CONFIG: SanitizationConfig = {\r\n allowedTags: [\r\n 'h2','h3','h4','h5','h6','p','br',\r\n 'b','i','em','strong','u',\r\n 'ul','ol','li','a','img',\r\n 'blockquote','code','div','span'\r\n ],\r\n allowedAttributes: {\r\n a: ['href', 'title', 'rel'],\r\n img: ['src', 'alt', 'title'],\r\n blockquote: ['cite'],\r\n div: ['class'],\r\n span: ['class'],\r\n },\r\n stripIgnoreTag: true,\r\n allowEmptyTags: false,\r\n maxTagDepth: 15,\r\n maxStringLength: 25000,\r\n};\r\n\r\nexport const COMMENT_CONFIG: SanitizationConfig = {\r\n allowedTags: ['b', 'i', 'em', 'strong', 'br', 'a'],\r\n allowedAttributes: { a: ['href', 'title'] },\r\n stripIgnoreTag: true,\r\n stripIgnoreTagBody: true,\r\n allowEmptyTags: false,\r\n maxTagDepth: 3,\r\n maxStringLength: 2000,\r\n};\r\n\r\nexport const EMAIL_CONFIG: SanitizationConfig = {\r\n allowedTags: ['p','br','b','i','em','strong','a'],\r\n allowedAttributes: { a: ['href', 'title'] },\r\n stripIgnoreTag: true,\r\n stripIgnoreTagBody: true,\r\n allowEmptyTags: false,\r\n maxTagDepth: 5,\r\n maxStringLength: 5000,\r\n};\r\n\r\nexport const ADMIN_CONFIG: SanitizationConfig = {\r\n allowedTags: [\r\n 'h1','h2','h3','h4','h5','h6','p','br','hr',\r\n 'b','i','em','strong','u','s','sub','sup',\r\n 'ul','ol','li','a','img',\r\n 'blockquote','code','pre',\r\n 'table','thead','tbody','tr','th','td',\r\n 'div','span','section','article',\r\n 'form','input','textarea','select','option',\r\n 'button','label'\r\n ],\r\n allowedAttributes: {\r\n a: ['href', 'title', 'target', 'rel'],\r\n img: ['src', 'alt', 'title', 'width', 'height', 'class'],\r\n blockquote: ['cite'],\r\n table: ['class'],\r\n th: ['scope', 'class'],\r\n td: ['colspan', 'rowspan', 'class'],\r\n div: ['class', 'id'],\r\n span: ['class', 'id'],\r\n form: ['action', 'method'],\r\n input: ['type', 'name', 'value', 'placeholder', 'required'],\r\n textarea: ['name', 'placeholder', 'required', 'rows', 'cols'],\r\n select: ['name', 'required'],\r\n option: ['value'],\r\n button: ['type', 'class'],\r\n label: ['for'],\r\n },\r\n allowEmptyTags: true,\r\n maxTagDepth: 25,\r\n maxStringLength: 100000,\r\n};\r\n\r\nexport const SANITIZATION_CONFIGS = {\r\n base: BASE_CONFIG,\r\n strict: STRICT_CONFIG,\r\n liberal: LIBERAL_CONFIG,\r\n blog: BLOG_CONFIG,\r\n comment: COMMENT_CONFIG,\r\n email: EMAIL_CONFIG,\r\n admin: ADMIN_CONFIG,\r\n} as const;\r\n\r\nexport type ConfigName = keyof typeof SANITIZATION_CONFIGS;\r\n\r\nexport const getConfig = (name: ConfigName): SanitizationConfig => {\r\n const config = SANITIZATION_CONFIGS[name];\r\n if (!config) throw new Error(`Unknown sanitization config: ${name}`);\r\n return { ...config };\r\n};\r\n\r\nexport const createCustomConfig = (\r\n base: ConfigName | SanitizationConfig,\r\n overrides: Partial<SanitizationConfig>\r\n): SanitizationConfig => {\r\n const baseConfig = typeof base === 'string' ? getConfig(base) : { ...base };\r\n return {\r\n ...baseConfig,\r\n ...overrides,\r\n allowedAttributes: {\r\n ...baseConfig.allowedAttributes,\r\n ...overrides.allowedAttributes,\r\n },\r\n };\r\n};\r\n","import { Request, Response, NextFunction } from 'express';\r\nimport { sanitizeRequestData, SanitizationError } from '../utils/sanitizer';\r\nimport { SanitizationConfig } from '../types/sanitization';\r\nimport { ConfigName, getConfig } from '../config/sanitizationConfigs';\r\n\r\ninterface SanitizeRequestOptions {\r\n config?: SanitizationConfig | ConfigName;\r\n onSanitized?: (metadata: any) => void;\r\n onError?: (error: Error, req: Request) => void;\r\n skipPaths?: string[];\r\n logWarnings?: boolean;\r\n}\r\n\r\nexport const sanitizeRequest = (options: SanitizeRequestOptions = {}) => {\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n try {\r\n if (options.skipPaths?.some(path => req.path.includes(path))) return next();\r\n\r\n const config = options.config\r\n ? typeof options.config === 'string'\r\n ? getConfig(options.config)\r\n : options.config\r\n : getConfig('base');\r\n\r\n if (req.body && typeof req.body === 'object') {\r\n const { data, sanitized, warnings, errors } = sanitizeRequestData(req.body, config);\r\n req.body = data;\r\n\r\n if (sanitized || warnings.length > 0) {\r\n (req as any)._sanitization = { sanitized, warnings, errors, timestamp: new Date().toISOString() };\r\n if (options.logWarnings && warnings.length > 0) {\r\n console.warn(`Sanitization warnings for ${req.method} ${req.path}:`, warnings);\r\n }\r\n options.onSanitized?.((req as any)._sanitization);\r\n }\r\n\r\n if (errors?.length) {\r\n const error = new Error(`Sanitization errors: ${errors.join(', ')}`);\r\n options.onError?.(error, req);\r\n return next(error);\r\n }\r\n }\r\n\r\n next();\r\n } catch (error) {\r\n const sanitizationError = error instanceof SanitizationError\r\n ? error\r\n : new Error(`Request sanitization failed: ${error instanceof Error ? error.message : 'Unknown error'}`);\r\n options.onError?.(sanitizationError, req);\r\n next(sanitizationError);\r\n }\r\n };\r\n};\r\n","import { Request, Response, NextFunction } from 'express';\r\nimport { SENSITIVE_FIELDS } from '../constants/sensitiveFields';\r\n\r\ninterface SanitizeStringsOptions {\r\n customSensitiveFields?: string[];\r\n customSanitizer?: (value: string) => string;\r\n skipEmptyStrings?: boolean;\r\n}\r\n\r\nexport const sanitizeStrings = (options: SanitizeStringsOptions = {}) => {\r\n return (req: Request, res: Response, next: NextFunction) => {\r\n try {\r\n if (!req.body) return next();\r\n\r\n const sensitiveFields = [...SENSITIVE_FIELDS, ...(options.customSensitiveFields || [])];\r\n const defaultSanitizer = (value: string) => value.replace(/[<>\"'&]/g, '').trim();\r\n const sanitizer = options.customSanitizer || defaultSanitizer;\r\n\r\n for (const [key, value] of Object.entries(req.body)) {\r\n if (typeof value === 'string' && !sensitiveFields.includes(key)) {\r\n if (options.skipEmptyStrings && !value.trim()) continue;\r\n req.body[key] = sanitizer(value);\r\n }\r\n }\r\n\r\n next();\r\n } catch (error) {\r\n console.error('Error sanitizing string fields:', error);\r\n next(error);\r\n }\r\n };\r\n};\r\n"],"mappings":";;;;AAAA,OAAO,eAAe;;;ACAf,IAAM,mBAAmB;AAAA,EAC9B;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;AACF;;;ACfO,IAAM,SAAS;AAAA,EACpB,MAAM,2BAAI,SAAoB,QAAQ,KAAK,UAAU,GAAG,IAAI,GAAtD;AAAA,EACN,MAAM,2BAAI,SAAoB,QAAQ,KAAK,UAAU,GAAG,IAAI,GAAtD;AAAA,EACN,OAAO,2BAAI,SAAoB,QAAQ,MAAM,WAAW,GAAG,IAAI,GAAxD;AAAA,EACP,OAAO,2BAAI,SAAoB,QAAQ,MAAM,WAAW,GAAG,IAAI,GAAxD;AACT;;;AFKO,IAAM,qBAAN,MAAM,2BAA0B,MAAM;AAAA,EAC3C,YAAY,SAAwB,OAAgB;AAClD,UAAM,OAAO;AADqB;AAElC,SAAK,OAAO;AAAA,EACd;AACF;AAL6C;AAAtC,IAAM,oBAAN;AAOP,IAAM,aAAN,MAAM,WAAU;AAAA,EAId,YAAY,QAA4B;AACtC,SAAK,SAAS;AAAA,MACZ,aAAa,OAAO,eAAe,CAAC;AAAA,MACpC,mBAAmB,OAAO,qBAAqB,CAAC;AAAA,MAChD,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,oBAAoB,OAAO,sBAAsB;AAAA,MACjD,gBAAgB,OAAO,kBAAkB;AAAA,MACzC,aAAa,OAAO,eAAe;AAAA,MACnC,iBAAiB,OAAO,mBAAmB;AAAA,IAC7C;AAEA,SAAK,WAAW;AAAA,MACd,WAAW;AAAA,MACX,UAAU,CAAC;AAAA,MACX,QAAQ,CAAC;AAAA,MACT,gBAAgB,CAAC;AAAA,IACnB;AAAA,EACF;AAAA,EAEQ,eAAe,OAAe,WAA4B;AAChE,QAAI;AACF,YAAM,iBAAiB,MAAM;AAG7B,UAAI,iBAAiB,KAAK,OAAO,iBAAiB;AAChD,aAAK,SAAS,SAAS;AAAA,UACrB,oBAAoB,aAAa,SAAS,oBAAoB,cAAc,OAAO,KAAK,OAAO,eAAe;AAAA,QAChH;AACA,gBAAQ,MAAM,UAAU,GAAG,KAAK,OAAO,eAAe;AACtD,aAAK,SAAS,YAAY;AAAA,MAC5B;AAGA,YAAM,eAAoB;AAAA,QACxB,cAAc,KAAK,OAAO;AAAA,QAC1B,cAAc,OAAO,OAAO,KAAK,OAAO,iBAAiB,EAAE,KAAK;AAAA,QAChE,cAAc,CAAC,KAAK,OAAO;AAAA,QAC3B,kBAAkB,KAAK,OAAO;AAAA,MAChC;AAEA,YAAM,YAAY,UAAU,SAAS,OAAO,YAAY;AAAuB;AAE/E,UAAI,cAAc,OAAO;AACvB,aAAK,SAAS,YAAY;AAC1B,YAAI,WAAW;AACb,eAAK,SAAS,eAAe,KAAK,SAAS;AAAA,QAC7C;AAAA,MACF;AAEA,aAAO;AAAA,IACT,SAAS,OAAO;AACd,YAAM,UAAU,uCAAuC,aAAa,SAAS,MAAM,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAC3I,WAAK,SAAS,SAAS,KAAK,SAAS,UAAU,CAAC;AAChD,WAAK,SAAS,OAAO,KAAK,OAAO;AACjC,aAAO,MAAM,OAAO;AACpB,YAAM,IAAI,kBAAkB,SAAS,SAAS;AAAA,IAChD;AAAA,EACF;AAAA,EAEQ,cAAc,OAAY,WAAyB;AACzD,QAAI,UAAU,QAAQ,UAAU,QAAW;AACzC,aAAO;AAAA,IACT;AAGA,QAAI,aAAa,iBAAiB,SAAS,SAAgB,GAAG;AAC5D,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,UAAU,UAAU;AAC7B,aAAO,KAAK,eAAe,OAAO,SAAS;AAAA,IAC7C;AAEA,QAAI,MAAM,QAAQ,KAAK,GAAG;AACxB,aAAO,MAAM;AAAA,QAAI,CAAC,MAAM,UACtB,KAAK,cAAc,MAAM,YAAY,GAAG,SAAS,IAAI,KAAK,MAAM,IAAI,KAAK,GAAG;AAAA,MAC9E;AAAA,IACF;AAEA,QAAI,SAAS,OAAO,UAAU,UAAU;AACtC,YAAM,eAAoB,CAAC;AAC3B,iBAAW,CAAC,KAAK,GAAG,KAAK,OAAO,QAAQ,KAAK,GAAG;AAC9C,cAAM,gBAAgB,YAAY,GAAG,SAAS,IAAI,GAAG,KAAK;AAC1D,qBAAa,GAAG,IAAI,KAAK,cAAc,KAAK,aAAa;AAAA,MAC3D;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA,EAEO,SAAqC,OAAiC;AAC3E,SAAK,WAAW;AAAA,MACd,WAAW;AAAA,MACX,UAAU,CAAC;AAAA,MACX,QAAQ,CAAC;AAAA,MACT,gBAAgB,CAAC;AAAA,MACjB,cAAc,KAAK,UAAU,KAAK,EAAE;AAAA,IACtC;AAEA,QAAI;AACF,YAAM,gBAAgB,KAAK,cAAc,KAAK;AAC9C,WAAK,SAAS,YAAY,KAAK,UAAU,aAAa,EAAE;AAExD,aAAO;AAAA,QACL,MAAM;AAAA,QACN,WAAW,KAAK,SAAS;AAAA,QACzB,UAAU,KAAK,SAAS;AAAA,QACxB,QAAQ,KAAK,SAAS,QAAQ,SAAS,KAAK,SAAS,SAAS;AAAA,MAChE;AAAA,IACF,SAAS,OAAO;AACd,UAAI,iBAAiB,mBAAmB;AACtC,cAAM;AAAA,MACR;AAEA,YAAM,UAAU,wBAAwB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAChG,aAAO,MAAM,OAAO;AACpB,YAAM,IAAI,kBAAkB,OAAO;AAAA,IACrC;AAAA,EACF;AAAA,EAEO,cAAoC;AACzC,WAAO,EAAE,GAAG,KAAK,SAAS;AAAA,EAC5B;AACF;AAhIgB;AAAhB,IAAM,YAAN;AAkIO,IAAM,sBAAsB,wBACjC,MACA,WAC0B;AAC1B,QAAM,YAAY,IAAI,UAAU,MAAM;AACtC,SAAO,UAAU,SAAS,IAAI;AAChC,GANmC;;;AGjJ5B,IAAM,cAAkC;AAAA,EAC7C,aAAa,CAAC,KAAK,KAAK,MAAM,UAAU,KAAK,MAAM,MAAM,MAAM,MAAM,GAAG;AAAA,EACxE,mBAAmB,EAAE,GAAG,CAAC,QAAQ,OAAO,EAAE;AAAA,EAC1C,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,iBAAiB;AACnB;AAEO,IAAM,gBAAoC;AAAA,EAC/C,aAAa,CAAC,KAAK,KAAK,MAAM,QAAQ;AAAA,EACtC,mBAAmB,CAAC;AAAA,EACpB,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,iBAAiB;AACnB;AAEO,IAAM,iBAAqC;AAAA,EAChD,aAAa;AAAA,IACX;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAI;AAAA,IAAK;AAAA,IACvC;AAAA,IAAI;AAAA,IAAI;AAAA,IAAK;AAAA,IAAS;AAAA,IAAI;AAAA,IAAI;AAAA,IAAM;AAAA,IACpC;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAI;AAAA,IACnB;AAAA,IAAa;AAAA,IAAO;AAAA,IACpB;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAK;AAAA,IAAK;AAAA,IAClC;AAAA,IAAM;AAAA,EACR;AAAA,EACA,mBAAmB;AAAA,IACjB,GAAG,CAAC,QAAQ,SAAS,UAAU,KAAK;AAAA,IACpC,KAAK,CAAC,OAAO,OAAO,SAAS,SAAS,QAAQ;AAAA,IAC9C,YAAY,CAAC,MAAM;AAAA,IACnB,OAAO,CAAC,OAAO;AAAA,IACf,IAAI,CAAC,OAAO;AAAA,IACZ,IAAI,CAAC,WAAW,SAAS;AAAA,EAC3B;AAAA,EACA,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,iBAAiB;AACnB;AAEO,IAAM,cAAkC;AAAA,EAC7C,aAAa;AAAA,IACX;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAI;AAAA,IAC7B;AAAA,IAAI;AAAA,IAAI;AAAA,IAAK;AAAA,IAAS;AAAA,IACtB;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAI;AAAA,IACnB;AAAA,IAAa;AAAA,IAAO;AAAA,IAAM;AAAA,EAC5B;AAAA,EACA,mBAAmB;AAAA,IACjB,GAAG,CAAC,QAAQ,SAAS,KAAK;AAAA,IAC1B,KAAK,CAAC,OAAO,OAAO,OAAO;AAAA,IAC3B,YAAY,CAAC,MAAM;AAAA,IACnB,KAAK,CAAC,OAAO;AAAA,IACb,MAAM,CAAC,OAAO;AAAA,EAChB;AAAA,EACA,gBAAgB;AAAA,EAChB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,iBAAiB;AACnB;AAEO,IAAM,iBAAqC;AAAA,EAChD,aAAa,CAAC,KAAK,KAAK,MAAM,UAAU,MAAM,GAAG;AAAA,EACjD,mBAAmB,EAAE,GAAG,CAAC,QAAQ,OAAO,EAAE;AAAA,EAC1C,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,iBAAiB;AACnB;AAEO,IAAM,eAAmC;AAAA,EAC9C,aAAa,CAAC,KAAI,MAAK,KAAI,KAAI,MAAK,UAAS,GAAG;AAAA,EAChD,mBAAmB,EAAE,GAAG,CAAC,QAAQ,OAAO,EAAE;AAAA,EAC1C,gBAAgB;AAAA,EAChB,oBAAoB;AAAA,EACpB,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,iBAAiB;AACnB;AAEO,IAAM,eAAmC;AAAA,EAC9C,aAAa;AAAA,IACX;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAI;AAAA,IAAK;AAAA,IACvC;AAAA,IAAI;AAAA,IAAI;AAAA,IAAK;AAAA,IAAS;AAAA,IAAI;AAAA,IAAI;AAAA,IAAM;AAAA,IACpC;AAAA,IAAK;AAAA,IAAK;AAAA,IAAK;AAAA,IAAI;AAAA,IACnB;AAAA,IAAa;AAAA,IAAO;AAAA,IACpB;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAQ;AAAA,IAAK;AAAA,IAAK;AAAA,IAClC;AAAA,IAAM;AAAA,IAAO;AAAA,IAAU;AAAA,IACvB;AAAA,IAAO;AAAA,IAAQ;AAAA,IAAW;AAAA,IAAS;AAAA,IACnC;AAAA,IAAS;AAAA,EACX;AAAA,EACA,mBAAmB;AAAA,IACjB,GAAG,CAAC,QAAQ,SAAS,UAAU,KAAK;AAAA,IACpC,KAAK,CAAC,OAAO,OAAO,SAAS,SAAS,UAAU,OAAO;AAAA,IACvD,YAAY,CAAC,MAAM;AAAA,IACnB,OAAO,CAAC,OAAO;AAAA,IACf,IAAI,CAAC,SAAS,OAAO;AAAA,IACrB,IAAI,CAAC,WAAW,WAAW,OAAO;AAAA,IAClC,KAAK,CAAC,SAAS,IAAI;AAAA,IACnB,MAAM,CAAC,SAAS,IAAI;AAAA,IACpB,MAAM,CAAC,UAAU,QAAQ;AAAA,IACzB,OAAO,CAAC,QAAQ,QAAQ,SAAS,eAAe,UAAU;AAAA,IAC1D,UAAU,CAAC,QAAQ,eAAe,YAAY,QAAQ,MAAM;AAAA,IAC5D,QAAQ,CAAC,QAAQ,UAAU;AAAA,IAC3B,QAAQ,CAAC,OAAO;AAAA,IAChB,QAAQ,CAAC,QAAQ,OAAO;AAAA,IACxB,OAAO,CAAC,KAAK;AAAA,EACf;AAAA,EACA,gBAAgB;AAAA,EAChB,aAAa;AAAA,EACb,iBAAiB;AACnB;AAEO,IAAM,uBAAuB;AAAA,EAClC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,SAAS;AAAA,EACT,MAAM;AAAA,EACN,SAAS;AAAA,EACT,OAAO;AAAA,EACP,OAAO;AACT;AAIO,IAAM,YAAY,wBAAC,SAAyC;AACjE,QAAM,SAAS,qBAAqB,IAAI;AACxC,MAAI,CAAC,OAAQ,OAAM,IAAI,MAAM,gCAAgC,IAAI,EAAE;AACnE,SAAO,EAAE,GAAG,OAAO;AACrB,GAJyB;;;ACpHlB,IAAM,kBAAkB,wBAAC,UAAkC,CAAC,MAAM;AACvE,SAAO,CAAC,KAAc,KAAe,SAAuB;AAC1D,QAAI;AACF,UAAI,QAAQ,WAAW,KAAK,UAAQ,IAAI,KAAK,SAAS,IAAI,CAAC,EAAG,QAAO,KAAK;AAE1E,YAAM,SAAS,QAAQ,SACnB,OAAO,QAAQ,WAAW,WACxB,UAAU,QAAQ,MAAM,IACxB,QAAQ,SACV,UAAU,MAAM;AAEpB,UAAI,IAAI,QAAQ,OAAO,IAAI,SAAS,UAAU;AAC5C,cAAM,EAAE,MAAM,WAAW,UAAU,OAAO,IAAI,oBAAoB,IAAI,MAAM,MAAM;AAClF,YAAI,OAAO;AAEX,YAAI,aAAa,SAAS,SAAS,GAAG;AACpC,UAAC,IAAY,gBAAgB,EAAE,WAAW,UAAU,QAAQ,YAAW,oBAAI,KAAK,GAAE,YAAY,EAAE;AAChG,cAAI,QAAQ,eAAe,SAAS,SAAS,GAAG;AAC9C,oBAAQ,KAAK,6BAA6B,IAAI,MAAM,IAAI,IAAI,IAAI,KAAK,QAAQ;AAAA,UAC/E;AACA,kBAAQ,cAAe,IAAY,aAAa;AAAA,QAClD;AAEA,YAAI,QAAQ,QAAQ;AAClB,gBAAM,QAAQ,IAAI,MAAM,wBAAwB,OAAO,KAAK,IAAI,CAAC,EAAE;AACnE,kBAAQ,UAAU,OAAO,GAAG;AAC5B,iBAAO,KAAK,KAAK;AAAA,QACnB;AAAA,MACF;AAEA,WAAK;AAAA,IACP,SAAS,OAAO;AACd,YAAM,oBAAoB,iBAAiB,oBACvC,QACA,IAAI,MAAM,gCAAgC,iBAAiB,QAAQ,MAAM,UAAU,eAAe,EAAE;AACxG,cAAQ,UAAU,mBAAmB,GAAG;AACxC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AACF,GAvC+B;;;ACJxB,IAAM,kBAAkB,wBAAC,UAAkC,CAAC,MAAM;AACvE,SAAO,CAAC,KAAc,KAAe,SAAuB;AAC1D,QAAI;AACF,UAAI,CAAC,IAAI,KAAM,QAAO,KAAK;AAE3B,YAAM,kBAAkB,CAAC,GAAG,kBAAkB,GAAI,QAAQ,yBAAyB,CAAC,CAAE;AACtF,YAAM,mBAAmB,wBAAC,UAAkB,MAAM,QAAQ,YAAY,EAAE,EAAE,KAAK,GAAtD;AACzB,YAAM,YAAY,QAAQ,mBAAmB;AAE7C,iBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,IAAI,IAAI,GAAG;AACnD,YAAI,OAAO,UAAU,YAAY,CAAC,gBAAgB,SAAS,GAAG,GAAG;AAC/D,cAAI,QAAQ,oBAAoB,CAAC,MAAM,KAAK,EAAG;AAC/C,cAAI,KAAK,GAAG,IAAI,UAAU,KAAK;AAAA,QACjC;AAAA,MACF;AAEA,WAAK;AAAA,IACP,SAAS,OAAO;AACd,cAAQ,MAAM,mCAAmC,KAAK;AACtD,WAAK,KAAK;AAAA,IACZ;AAAA,EACF;AACF,GAtB+B;","names":[]}