html-preview-sandbox 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +45 -0
- package/LICENSE +21 -0
- package/README.md +163 -0
- package/SECURITY.md +40 -0
- package/THREAT_MODEL.md +51 -0
- package/dist/bridge.d.ts +3 -0
- package/dist/decode.d.ts +12 -0
- package/dist/document.browser.d.ts +2 -0
- package/dist/document.d.ts +2 -0
- package/dist/errors.d.ts +12 -0
- package/dist/index.browser.d.ts +9 -0
- package/dist/index.browser.js +988 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +990 -0
- package/dist/index.js.map +1 -0
- package/dist/policy.d.ts +10 -0
- package/dist/renderer-core.d.ts +4 -0
- package/dist/renderer.browser.d.ts +1 -0
- package/dist/renderer.d.ts +1 -0
- package/dist/sanitize-core.d.ts +5 -0
- package/dist/sanitize.browser.d.ts +4 -0
- package/dist/sanitize.d.ts +4 -0
- package/dist/scrollbar.d.ts +2 -0
- package/dist/types.d.ts +84 -0
- package/docs/BRANCHING.md +94 -0
- package/docs/BROWSER_SUPPORT.md +42 -0
- package/docs/INTEGRATION.md +145 -0
- package/docs/PROJECT_STRUCTURE.md +121 -0
- package/docs/ROADMAP.md +184 -0
- package/docs/SANITIZER_DECISION.md +78 -0
- package/docs/SECURITY_MODEL.md +100 -0
- package/docs//344/275/277/347/224/250/346/226/207/346/241/243.zh-CN.md +204 -0
- package/package.json +86 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/decode.ts","../src/sanitize.browser.ts","../src/sanitize-core.ts","../src/policy.ts","../src/bridge.ts","../src/scrollbar.ts","../src/document.browser.ts","../src/renderer-core.ts","../src/renderer.browser.ts"],"sourcesContent":["import type { PreviewErrorCode } from './types.js';\n\nexport class PreviewError extends Error {\n code: PreviewErrorCode;\n cause?: unknown;\n\n constructor(code: PreviewErrorCode, message: string, cause?: unknown) {\n super(message);\n this.name = 'PreviewError';\n this.code = code;\n this.cause = cause;\n }\n}\n\nexport const ERROR_CODES = {\n OVERSIZED: 'OVERSIZED',\n DECODE_FAILED: 'DECODE_FAILED',\n EMPTY_AFTER_SANITIZE: 'EMPTY_AFTER_SANITIZE',\n RENDER_FAILED: 'RENDER_FAILED',\n} as const satisfies Record<string, PreviewErrorCode>;\n","import { ERROR_CODES, PreviewError } from './errors.js';\nimport type { PreviewInput } from './types.js';\n\nexport const DEFAULT_MAX_BYTES = 100 * 1024 * 1024;\n\nconst BOM_UTF8 = [0xef, 0xbb, 0xbf];\nconst BOM_UTF16_LE = [0xff, 0xfe];\nconst BOM_UTF16_BE = [0xfe, 0xff];\n\nexport interface DecodeResult {\n html: string;\n encoding: string;\n usedBom: boolean;\n size: number;\n}\n\nfunction startsWithBytes(bytes: Uint8Array, prefix: number[]): boolean {\n if (bytes.length < prefix.length) return false;\n return prefix.every((byte, index) => bytes[index] === byte);\n}\n\nfunction decodeWith(bytes: Uint8Array, encoding: string, fatal = false): string | null {\n try {\n return new TextDecoder(encoding, { fatal }).decode(bytes);\n } catch {\n return null;\n }\n}\n\nfunction findDeclaredCharset(head: string): string | null {\n const metaCharset = head.match(/<meta[^>]+charset\\s*=\\s*[\"']?([\\w-]+)/i);\n if (metaCharset?.[1]) return metaCharset[1].toLowerCase();\n\n const contentType = head.match(/charset\\s*=\\s*[\"']?([\\w-]+)/i);\n if (contentType?.[1]) return contentType[1].toLowerCase();\n\n return null;\n}\n\nexport async function normalizeInput(input: PreviewInput, options: { maxBytes?: number } = {}): Promise<DecodeResult> {\n const maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n\n if (typeof input === 'string') {\n const size = new TextEncoder().encode(input).byteLength;\n if (size > maxBytes) {\n throw new PreviewError(ERROR_CODES.OVERSIZED, `HTML input exceeds ${maxBytes} bytes`);\n }\n return { html: input, encoding: 'utf-8', usedBom: false, size };\n }\n\n let bytes: Uint8Array;\n if (input instanceof Uint8Array) {\n bytes = input;\n } else if (input instanceof ArrayBuffer) {\n bytes = new Uint8Array(input);\n } else if (typeof Blob !== 'undefined' && input instanceof Blob) {\n // Check Blob.size before reading — arrayBuffer() would materialize the whole\n // file into memory first, so an oversized Blob must be rejected up front.\n if (input.size > maxBytes) {\n throw new PreviewError(ERROR_CODES.OVERSIZED, `HTML input exceeds ${maxBytes} bytes`);\n }\n bytes = new Uint8Array(await input.arrayBuffer());\n } else {\n throw new PreviewError(ERROR_CODES.DECODE_FAILED, 'Unsupported preview input');\n }\n\n if (bytes.byteLength > maxBytes) {\n throw new PreviewError(ERROR_CODES.OVERSIZED, `HTML input exceeds ${maxBytes} bytes`);\n }\n\n return decodeHtmlBytes(bytes);\n}\n\nexport function decodeHtmlBytes(input: ArrayBuffer | Uint8Array): DecodeResult {\n const bytes = input instanceof Uint8Array ? input : new Uint8Array(input);\n\n if (startsWithBytes(bytes, BOM_UTF8)) {\n return {\n html: decodeWith(bytes.subarray(BOM_UTF8.length), 'utf-8') ?? '',\n encoding: 'utf-8',\n usedBom: true,\n size: bytes.byteLength,\n };\n }\n\n if (startsWithBytes(bytes, BOM_UTF16_LE)) {\n return {\n html: decodeWith(bytes.subarray(BOM_UTF16_LE.length), 'utf-16le') ?? '',\n encoding: 'utf-16le',\n usedBom: true,\n size: bytes.byteLength,\n };\n }\n\n if (startsWithBytes(bytes, BOM_UTF16_BE)) {\n return {\n html: decodeWith(bytes.subarray(BOM_UTF16_BE.length), 'utf-16be') ?? '',\n encoding: 'utf-16be',\n usedBom: true,\n size: bytes.byteLength,\n };\n }\n\n const strictUtf8 = decodeWith(bytes, 'utf-8', true);\n if (strictUtf8 !== null) {\n return { html: strictUtf8, encoding: 'utf-8', usedBom: false, size: bytes.byteLength };\n }\n\n const head = decodeWith(bytes.subarray(0, 4096), 'iso-8859-1') ?? '';\n const declared = findDeclaredCharset(head);\n\n if (declared && declared !== 'utf-8' && declared !== 'utf8') {\n const decoded = decodeWith(bytes, declared);\n if (decoded !== null) {\n return { html: decoded, encoding: declared, usedBom: false, size: bytes.byteLength };\n }\n }\n\n return {\n html: decodeWith(bytes, 'utf-8') ?? '',\n encoding: 'utf-8',\n usedBom: false,\n size: bytes.byteLength,\n };\n}\n","import createDOMPurify from 'dompurify';\nimport { createSanitizer } from './sanitize-core.js';\n\nexport const sanitizeHtml = createSanitizer(window, createDOMPurify);\n","import type { SanitizeOptions, SanitizeReport } from './types.js';\n\nconst DEFAULT_ALLOWED_TAGS = [\n 'html', 'head', 'body', 'title', 'meta', 'link', 'style', 'script',\n 'main', 'section', 'article', 'aside', 'header', 'footer', 'nav',\n 'div', 'span', 'p', 'br', 'hr', 'pre', 'code', 'blockquote',\n 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'ul', 'ol', 'li', 'dl', 'dt', 'dd',\n 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td', 'caption', 'colgroup', 'col',\n 'a', 'strong', 'b', 'em', 'i', 'u', 's', 'small', 'mark', 'sub', 'sup',\n 'img', 'picture', 'source', 'audio', 'video', 'canvas',\n 'form', 'label', 'input', 'button', 'select', 'option', 'optgroup', 'textarea',\n 'fieldset', 'legend', 'details', 'summary',\n 'svg', 'g', 'defs', 'symbol', 'use', 'desc',\n 'rect', 'circle', 'ellipse', 'line', 'polyline', 'polygon', 'path',\n 'text', 'tspan', 'textPath', 'linearGradient', 'radialGradient', 'stop',\n 'pattern', 'mask', 'clipPath', 'filter', 'feGaussianBlur', 'feColorMatrix',\n 'feOffset', 'feMerge', 'feMergeNode', 'feBlend', 'feFlood', 'feComposite',\n 'feTurbulence', 'feDisplacementMap', 'feDropShadow', 'marker',\n 'animate', 'animateTransform', 'animateMotion', 'set', 'foreignObject',\n];\n\nconst DISALLOWED_TAGS = ['base', 'object', 'embed', 'applet'];\n\nconst GLOBAL_ATTRS = [\n 'class', 'id', 'style', 'title', 'lang', 'dir', 'role', 'tabindex', 'hidden',\n 'aria-*', 'data-*',\n];\n\nconst SAFE_INLINE_EVENTS = [\n 'onclick', 'onauxclick', 'ondblclick',\n 'oninput', 'onchange', 'onsubmit', 'onreset',\n 'onkeydown', 'onkeyup', 'onkeypress',\n 'onfocusin', 'onfocusout',\n];\n\nconst SVG_ATTRS = [\n 'x', 'y', 'cx', 'cy', 'r', 'rx', 'ry', 'x1', 'y1', 'x2', 'y2',\n 'width', 'height', 'd', 'points', 'transform', 'fill', 'fill-opacity',\n 'fill-rule', 'stroke', 'stroke-width', 'stroke-linecap', 'stroke-linejoin',\n 'stroke-dasharray', 'stroke-dashoffset', 'stroke-opacity', 'stroke-miterlimit',\n 'opacity', 'color', 'visibility', 'display', 'vector-effect',\n 'viewBox', 'preserveAspectRatio', 'xmlns', 'xmlns:xlink',\n 'href', 'xlink:href', 'offset', 'gradientUnits', 'gradientTransform',\n 'spreadMethod', 'stop-color', 'stop-opacity', 'text-anchor',\n 'dominant-baseline', 'alignment-baseline', 'font-family', 'font-size',\n 'font-weight', 'font-style', 'letter-spacing', 'word-spacing',\n 'text-decoration', 'dx', 'dy', 'rotate', 'startOffset', 'textLength',\n 'lengthAdjust', 'clip-path', 'clip-rule', 'mask', 'filter', 'stdDeviation',\n 'in', 'in2', 'result', 'mode', 'flood-color', 'flood-opacity', 'edgeMode',\n 'patternUnits', 'patternTransform', 'patternContentUnits', 'markerWidth',\n 'markerHeight', 'refX', 'refY', 'orient', 'markerUnits', 'marker-start',\n 'marker-mid', 'marker-end', 'attributeName', 'attributeType', 'from', 'to',\n 'by', 'values', 'dur', 'repeatCount', 'repeatDur', 'begin', 'end',\n 'calcMode', 'keyTimes', 'keySplines', 'additive', 'accumulate',\n 'fill-mode', 'restart',\n];\n\nconst ATTRS_BY_TAG: Record<string, string[]> = {\n a: ['href', 'name', 'target', 'rel', 'download'],\n link: ['rel', 'href', 'as', 'crossorigin', 'integrity', 'referrerpolicy', 'type', 'media', 'sizes'],\n meta: ['charset', 'name', 'content', 'http-equiv', 'property'],\n img: ['src', 'alt', 'width', 'height', 'loading', 'decoding', 'srcset', 'sizes'],\n source: ['src', 'srcset', 'type', 'media'],\n input: ['type', 'name', 'value', 'placeholder', 'min', 'max', 'step', 'required', 'checked', 'disabled', 'readonly', 'pattern', 'maxlength'],\n button: ['type', 'name', 'value', 'disabled'],\n select: ['name', 'value', 'multiple', 'disabled', 'required'],\n option: ['value', 'selected', 'disabled'],\n textarea: ['name', 'value', 'placeholder', 'rows', 'cols', 'maxlength', 'required', 'disabled', 'readonly'],\n form: ['method', 'enctype', 'novalidate'],\n label: ['for'],\n audio: ['src', 'controls', 'autoplay', 'loop', 'muted', 'preload'],\n video: ['src', 'controls', 'autoplay', 'loop', 'muted', 'preload', 'poster', 'width', 'height'],\n script: ['src', 'type', 'async', 'defer', 'crossorigin', 'integrity', 'referrerpolicy', 'nomodule', 'nonce'],\n};\n\nconst URL_ATTRS = new Set(['href', 'src', 'srcset', 'cite', 'xlink:href', 'action']);\nconst DEFAULT_SCHEMES = new Set(['http:', 'https:', 'mailto:', 'tel:']);\nconst MEDIA_TAGS = new Set(['img', 'audio', 'video', 'source', 'picture']);\n\nfunction emptyReport(): SanitizeReport {\n return {\n removedTags: [],\n removedAttributes: [],\n removedSchemes: [],\n strippedAll: false,\n };\n}\n\ntype CountedRecord = { count: number; [key: string]: unknown };\n\nfunction increment<T extends CountedRecord>(list: T[], predicate: (item: T) => boolean, create: () => Omit<T, 'count'>): void {\n const existing = list.find(predicate);\n if (existing) {\n existing.count += 1;\n return;\n }\n list.push({ ...create(), count: 1 } as T);\n}\n\nfunction reportTag(report: SanitizeReport, tag: string): void {\n increment(report.removedTags, (item) => item.tag === tag, () => ({ tag }));\n}\n\nfunction reportAttr(report: SanitizeReport, tag: string, attr: string): void {\n increment(report.removedAttributes, (item) => item.tag === tag && item.attr === attr, () => ({ tag, attr }));\n}\n\nfunction reportScheme(report: SanitizeReport, scheme: string): void {\n increment(report.removedSchemes, (item) => item.scheme === scheme, () => ({ scheme }));\n}\n\nfunction normalizeName(name: unknown): string {\n return String(name || '').toLowerCase();\n}\n\nfunction matchesPattern(attr: string, pattern: string): boolean {\n const normalizedPattern = normalizeName(pattern);\n return normalizedPattern.endsWith('*')\n ? attr.startsWith(normalizedPattern.slice(0, -1))\n : attr === normalizedPattern;\n}\n\nfunction getAllowedTags(options: SanitizeOptions = {}): Set<string> {\n const tags = new Set(DEFAULT_ALLOWED_TAGS.map(normalizeName));\n if (options.allowScripts === false) tags.delete('script');\n for (const tag of options.extraTags ?? []) tags.add(normalizeName(tag));\n for (const tag of options.dropTags ?? []) tags.delete(normalizeName(tag));\n return tags;\n}\n\nfunction getAllowedAttrs(options: SanitizeOptions = {}): string[] {\n return [\n ...GLOBAL_ATTRS,\n ...(options.allowInlineEvents === false ? [] : SAFE_INLINE_EVENTS),\n ...SVG_ATTRS,\n ...Object.values(ATTRS_BY_TAG).flat(),\n ...(options.extraAttributes?.['*'] ?? []),\n ...Object.values(options.extraAttributes ?? {}).flat(),\n ];\n}\n\nfunction isAllowedAttr(tag: string, attr: string, options: SanitizeOptions = {}): boolean {\n if (GLOBAL_ATTRS.some((pattern) => matchesPattern(attr, pattern))) return true;\n if (options.allowInlineEvents !== false && SAFE_INLINE_EVENTS.map(normalizeName).includes(attr)) return true;\n if (SVG_ATTRS.map(normalizeName).includes(attr)) return true;\n if ((ATTRS_BY_TAG[tag] ?? []).map(normalizeName).includes(attr)) return true;\n if ((options.extraAttributes?.['*'] ?? []).map(normalizeName).includes(attr)) return true;\n if ((options.extraAttributes?.[tag] ?? []).map(normalizeName).includes(attr)) return true;\n return false;\n}\n\nfunction getScheme(raw: unknown): string {\n const trimmed = String(raw || '').trim();\n const match = trimmed.match(/^([a-zA-Z][\\w+.-]*):/);\n return match ? `${match[1].toLowerCase()}:` : '';\n}\n\nfunction isAllowedUrl(raw: unknown, tag: string, options: SanitizeOptions = {}): boolean {\n const scheme = getScheme(raw);\n if (!scheme) return true;\n if (DEFAULT_SCHEMES.has(scheme)) return true;\n if (MEDIA_TAGS.has(tag) && (scheme === 'data:' || scheme === 'blob:')) return true;\n return (options.extraSchemes ?? [])\n .map((item) => (item.endsWith(':') ? item.toLowerCase() : `${item.toLowerCase()}:`))\n .includes(scheme);\n}\n\nfunction splitSrcsetCandidates(raw: unknown): string[] {\n return String(raw || '')\n .split(',')\n .map((candidate) => candidate.trim())\n .filter(Boolean)\n .map((candidate) => candidate.split(/\\s+/)[0])\n .filter(Boolean);\n}\n\nfunction disallowedSrcsetSchemes(raw: unknown, tag: string, options: SanitizeOptions = {}): string[] {\n const schemes = new Set<string>();\n for (const url of splitSrcsetCandidates(raw)) {\n if (!isAllowedUrl(url, tag, options)) {\n schemes.add(getScheme(url) || 'invalid');\n }\n }\n return [...schemes];\n}\n\nfunction isDangerousMeta(node: Element): boolean {\n if (normalizeName(node.nodeName) !== 'meta') return false;\n const equiv = normalizeName(node.getAttribute('http-equiv'));\n return equiv === 'refresh' || equiv === 'content-security-policy';\n}\n\n// SVG animation elements can rewrite URL attributes at runtime\n// (<animate attributeName=\"href\" values=\"javascript:...\">), and the animation\n// value attributes (values/from/to/by) do not go through URL scheme filtering.\n// Any animation element that targets a URL attribute is removed entirely.\nconst ANIMATION_TAGS = new Set(['animate', 'set', 'animatemotion', 'animatetransform']);\nconst URL_TARGET_ATTRS = new Set(['href', 'xlink:href', 'src']);\n\nfunction isUrlTargetingAnimation(node: Element): boolean {\n if (!ANIMATION_TAGS.has(normalizeName(node.nodeName))) return false;\n const target = normalizeName(node.getAttribute?.('attributeName'));\n return URL_TARGET_ATTRS.has(target);\n}\n\n// Resource-hint <link rel> values that can open a connection or fetch a resource\n// outside consistent CSP governance (browsers vary on whether preconnect/dns-prefetch\n// are subject to CSP). They are stripped at the sanitizer layer rather than relying on\n// CSP alone. Stylesheet/preload/modulepreload/icon remain allowed — those are governed\n// by the matching CSP directive (style-src / script-src / img-src).\nconst BLOCKED_LINK_RELS = new Set(['dns-prefetch', 'preconnect', 'prefetch', 'prerender']);\n\nfunction isBlockedResourceHintLink(node: Element): boolean {\n if (normalizeName(node.nodeName) !== 'link') return false;\n const rel = normalizeName(node.getAttribute?.('rel'));\n if (!rel) return false;\n return rel.split(/\\s+/).some((token) => BLOCKED_LINK_RELS.has(token));\n}\n\nfunction applyProjectHooks(purifier: any, report: SanitizeReport, options: SanitizeOptions): void {\n // Nodes flagged for removal during uponSanitizeElement (where their original\n // attributes are still readable) but detached later in afterSanitizeElements,\n // because detaching mid-walk breaks DOMPurify's tree traversal.\n const pendingRemoval = new WeakSet<Element>();\n\n purifier.addHook('uponSanitizeElement', (node: Element, data: { tagName?: string }) => {\n const tag = normalizeName(data.tagName || node.nodeName);\n if (DISALLOWED_TAGS.includes(tag)) reportTag(report, tag);\n if (isDangerousMeta(node)) reportAttr(report, 'meta', 'http-equiv');\n // Detect URL-targeting SVG animations here, before DOMPurify strips their\n // attributeName/values attributes (which would hide the vector from later hooks).\n if (isUrlTargetingAnimation(node)) {\n reportTag(report, tag);\n pendingRemoval.add(node);\n }\n // Drop connection/prefetch resource-hint links (see BLOCKED_LINK_RELS).\n if (isBlockedResourceHintLink(node)) {\n reportTag(report, tag);\n pendingRemoval.add(node);\n }\n });\n\n purifier.addHook('afterSanitizeElements', (node: Element) => {\n if (isDangerousMeta(node) || pendingRemoval.has(node)) {\n node.remove();\n }\n });\n\n purifier.addHook('afterSanitizeAttributes', (node: Element) => {\n const tag = normalizeName(node.nodeName);\n if (!node.attributes) return;\n\n for (const attrNode of [...node.attributes]) {\n const attr = normalizeName(attrNode.name);\n if (!isAllowedAttr(tag, attr, options)) {\n reportAttr(report, tag, attr);\n node.removeAttribute(attrNode.name);\n continue;\n }\n\n if (URL_ATTRS.has(attr) && !isAllowedUrl(attrNode.value, tag, options)) {\n reportAttr(report, tag, attr);\n reportScheme(report, getScheme(attrNode.value) || 'invalid');\n node.removeAttribute(attrNode.name);\n continue;\n }\n\n if (attr === 'srcset') {\n const blockedSchemes = disallowedSrcsetSchemes(attrNode.value, tag, options);\n if (blockedSchemes.length) {\n reportAttr(report, tag, attr);\n for (const scheme of blockedSchemes) reportScheme(report, scheme);\n node.removeAttribute(attrNode.name);\n }\n }\n }\n });\n}\n\nfunction collectDomPurifyRemoved(purifier: any, report: SanitizeReport): void {\n for (const item of purifier.removed ?? []) {\n if (item.element) {\n reportTag(report, normalizeName(item.element.nodeName));\n }\n if (item.attribute) {\n reportAttr(report, normalizeName(item.from?.nodeName || '*'), normalizeName(item.attribute.name));\n if (URL_ATTRS.has(normalizeName(item.attribute.name))) {\n reportScheme(report, getScheme(item.attribute.value) || 'invalid');\n }\n }\n }\n}\n\nexport function createSanitizer(runtimeWindow: any, createDOMPurify: any) {\n return function sanitizeHtml(rawHtml: string, options: SanitizeOptions = {}): { html: string; report: SanitizeReport } {\n const purifier = createDOMPurify(runtimeWindow);\n const report = emptyReport();\n const allowedTags = [...getAllowedTags(options)];\n\n applyProjectHooks(purifier, report, options);\n\n const html = purifier.sanitize(rawHtml, {\n WHOLE_DOCUMENT: true,\n // ALLOWED_TAGS/ALLOWED_ATTR are authoritative (they replace DOMPurify's\n // defaults). Per-tag attribute tightening happens in the afterSanitizeAttributes\n // hook; DISALLOWED_TAGS is the hard deny-list.\n ALLOWED_TAGS: allowedTags,\n ALLOWED_ATTR: getAllowedAttrs(options),\n FORBID_TAGS: DISALLOWED_TAGS,\n KEEP_CONTENT: true,\n ALLOW_DATA_ATTR: true,\n ALLOW_ARIA_ATTR: true,\n });\n\n collectDomPurifyRemoved(purifier, report);\n\n const parser = new runtimeWindow.DOMParser();\n const doc = parser.parseFromString(html, 'text/html');\n report.strippedAll = !doc.body.textContent?.trim() && !doc.body.querySelector('script,style,img,svg,canvas,video,audio');\n\n return { html, report };\n };\n}\n","import type { CspPolicy, CspPreset } from './types.js';\n\nconst DEFAULT_SCRIPT_HOSTS = [\n 'https://cdnjs.cloudflare.com',\n 'https://cdn.jsdelivr.net',\n 'https://cdn.tailwindcss.com',\n 'https://code.jquery.com',\n];\n\nconst DEFAULT_STYLE_HOSTS = [\n 'https://cdnjs.cloudflare.com',\n 'https://cdn.jsdelivr.net',\n 'https://cdn.tailwindcss.com',\n 'https://fonts.googleapis.com',\n];\n\nconst DEFAULT_FONT_HOSTS = ['https://fonts.gstatic.com'];\n\nexport const DEFAULT_SANDBOX_TOKENS = [\n 'allow-scripts',\n 'allow-forms',\n 'allow-popups',\n 'allow-popups-to-escape-sandbox',\n 'allow-modals',\n];\n\nexport const UNSAFE_SANDBOX_TOKENS = [\n 'allow-same-origin',\n 'allow-top-navigation',\n 'allow-top-navigation-by-user-activation',\n 'allow-downloads',\n];\n\nexport const DEFAULT_ALLOWED_EXTERNAL_PROTOCOLS = ['http:', 'https:', 'mailto:', 'tel:'];\n\nfunction normalizePolicy(policy?: CspPreset | CspPolicy): CspPolicy {\n if (!policy) return { preset: 'strict' };\n if (typeof policy === 'string') return { preset: policy };\n return { preset: 'strict', ...policy };\n}\n\nfunction join(values: string[]): string {\n return [...new Set(values.filter(Boolean))].join(' ');\n}\n\n// Presets are layered by exfiltration capability (egress), not resource loading (ingress):\n// offline — no network at all, nothing in or out.\n// strict — default. Blocks attacker-readable exfiltration channels (connect-src 'none',\n// form-action 'none', no wildcard img/media hosts). Fixed static CDN/font hosts\n// may be loaded; inline script and 'unsafe-eval' are permitted because they add\n// no attacker capability beyond already-permitted inline scripts and provide no\n// attacker-readable exfiltration sink.\n// balanced — compatibility-first. Opens https: images/media and connect-src https:,\n// which IS a general-purpose exfiltration surface; for semi-trusted content only.\nexport function buildCsp(policy?: CspPreset | CspPolicy): string {\n const normalized = normalizePolicy(policy);\n const preset = normalized.preset ?? 'strict';\n\n const scriptHosts = [...DEFAULT_SCRIPT_HOSTS, ...(normalized.scriptHosts ?? [])];\n const styleHosts = [...DEFAULT_STYLE_HOSTS, ...(normalized.styleHosts ?? [])];\n const fontHosts = [...DEFAULT_FONT_HOSTS, ...(normalized.fontHosts ?? [])];\n const imgHosts = normalized.imgHosts ?? [];\n const connectHosts = normalized.connectHosts ?? [];\n\n const directives: Record<string, string> = {\n 'default-src': \"'none'\",\n 'script-src': join([\"'unsafe-inline'\", \"'unsafe-eval'\", ...scriptHosts]),\n 'style-src': join([\"'unsafe-inline'\", ...styleHosts]),\n 'img-src': join(['blob:', 'data:', ...imgHosts]),\n 'media-src': 'blob: data:',\n 'font-src': join(['data:', ...fontHosts]),\n 'connect-src': \"'none'\",\n 'worker-src': \"'none'\",\n 'frame-src': 'blob:',\n 'object-src': \"'none'\",\n 'base-uri': \"'none'\",\n 'form-action': \"'none'\",\n 'upgrade-insecure-requests': '',\n 'block-all-mixed-content': '',\n };\n\n if (preset === 'balanced') {\n directives['script-src'] = join([\"'unsafe-inline'\", \"'unsafe-eval'\", ...scriptHosts, 'https://unpkg.com']);\n directives['style-src'] = join([\"'unsafe-inline'\", ...styleHosts, 'https://unpkg.com']);\n directives['img-src'] = join(['https:', 'blob:', 'data:', ...imgHosts]);\n directives['media-src'] = join(['https:', 'blob:', 'data:']);\n directives['connect-src'] = connectHosts.length ? join(['https:', ...connectHosts]) : 'https:';\n }\n\n if (preset === 'offline') {\n directives['script-src'] = \"'unsafe-inline'\";\n directives['style-src'] = \"'unsafe-inline'\";\n directives['img-src'] = 'blob: data:';\n directives['media-src'] = 'blob: data:';\n directives['font-src'] = 'data:';\n directives['connect-src'] = \"'none'\";\n }\n\n Object.assign(directives, normalized.directives ?? {});\n\n return Object.entries(directives)\n .map(([name, value]) => (value ? `${name} ${value}` : name))\n .join('; ');\n}\n\nexport function injectCspMeta(html: string, csp: string): string {\n const escaped = csp.replace(/\"/g, '"');\n const meta = `<meta http-equiv=\"Content-Security-Policy\" content=\"${escaped}\">`;\n\n if (/<head[^>]*>/i.test(html)) {\n return html.replace(/<head[^>]*>/i, (match: string) => `${match}${meta}`);\n }\n\n if (/<html[^>]*>/i.test(html)) {\n return html.replace(/<html[^>]*>/i, (match: string) => `${match}<head>${meta}</head>`);\n }\n\n return `<!doctype html><html><head>${meta}</head><body>${html}</body></html>`;\n}\n\nexport function getSandboxAttribute(tokens = DEFAULT_SANDBOX_TOKENS, options: { allowUnsafeTokens?: boolean } = {}): string {\n const allowUnsafeTokens = options.allowUnsafeTokens === true;\n return [...new Set(tokens)]\n .filter((token) => allowUnsafeTokens || !UNSAFE_SANDBOX_TOKENS.includes(token))\n .join(' ');\n}\n\nexport function isAllowedExternalUrl(url: string, protocols = DEFAULT_ALLOWED_EXTERNAL_PROTOCOLS): boolean {\n try {\n const parsed = new URL(url);\n const allowedProtocols = protocols.map((protocol) => {\n const normalized = String(protocol || '').toLowerCase();\n return normalized.endsWith(':') ? normalized : `${normalized}:`;\n });\n return allowedProtocols.includes(parsed.protocol);\n } catch {\n return false;\n }\n}\n","export const BRIDGE_OPEN_EXTERNAL = 'html-preview-sandbox:openExternal';\nexport const BRIDGE_CSP_VIOLATION = 'html-preview-sandbox:cspViolation';\n\nconst CSP_VIOLATION_LIMIT = 30;\n\nfunction bridgeScript(): string {\n return `<script>\n(() => {\n const OPEN_EXTERNAL = ${JSON.stringify(BRIDGE_OPEN_EXTERNAL)};\n const CSP_VIOLATION = ${JSON.stringify(BRIDGE_CSP_VIOLATION)};\n const LIMIT = ${CSP_VIOLATION_LIMIT};\n\n function post(type, payload) {\n try {\n window.parent.postMessage(Object.assign({ type }, payload), '*');\n } catch (_) {}\n }\n\n function postExternal(href, source) {\n post(OPEN_EXTERNAL, { href: String(href || ''), source });\n }\n\n document.addEventListener('click', (event) => {\n let element = event.target;\n while (element && element.nodeName !== 'A') element = element.parentElement;\n if (!element) return;\n\n const href = element.getAttribute('href');\n const resolved = element.href || '';\n\n if (href == null || href === '' || href.charAt(0) === '#') {\n event.preventDefault();\n event.stopPropagation();\n const fragment = href && href.length > 1 ? href.slice(1) : '';\n if (fragment) {\n let target = null;\n try {\n target = document.getElementById(fragment) || document.querySelector('a[name=\"' + CSS.escape(fragment) + '\"]');\n } catch (_) {}\n if (target && target.scrollIntoView) target.scrollIntoView({ behavior: 'smooth', block: 'start' });\n } else if (href === '#') {\n try { window.scrollTo({ top: 0, behavior: 'smooth' }); } catch (_) {}\n }\n return;\n }\n\n // Defense in depth: even if a relaxed custom sanitizer let a javascript: URL\n // through, the bridge must not allow the default click to run it.\n if (/^javascript:/i.test(resolved)) {\n event.preventDefault();\n event.stopPropagation();\n return;\n }\n\n try {\n const url = new URL(resolved);\n if (url.protocol === 'about:') return;\n } catch (_) {\n return;\n }\n\n event.preventDefault();\n event.stopPropagation();\n postExternal(resolved, 'link');\n }, true);\n\n window.open = (url) => {\n if (url) postExternal(url, 'window.open');\n return null;\n };\n\n const seen = new Set();\n let sent = 0;\n document.addEventListener('securitypolicyviolation', (event) => {\n if (sent >= LIMIT) return;\n const key = (event.effectiveDirective || event.violatedDirective || '') + '|' + (event.blockedURI || '');\n if (seen.has(key)) return;\n seen.add(key);\n sent += 1;\n post(CSP_VIOLATION, {\n blockedURI: String(event.blockedURI || ''),\n violatedDirective: String(event.violatedDirective || ''),\n effectiveDirective: String(event.effectiveDirective || ''),\n sourceFile: String(event.sourceFile || ''),\n lineNumber: Number(event.lineNumber || 0),\n columnNumber: Number(event.columnNumber || 0),\n disposition: String(event.disposition || ''),\n sample: String(event.sample || '').slice(0, 120),\n });\n });\n})();\n</script>`;\n}\n\nexport function injectBridgeScript(html: string): string {\n const script = bridgeScript();\n const cspMeta = /<meta[^>]*http-equiv\\s*=\\s*[\"']Content-Security-Policy[\"'][^>]*>/i;\n\n if (cspMeta.test(html)) {\n return html.replace(cspMeta, (match: string) => `${match}${script}`);\n }\n\n if (/<\\/head>/i.test(html)) {\n return html.replace(/<\\/head>/i, `${script}</head>`);\n }\n\n if (/<body[^>]*>/i.test(html)) {\n return html.replace(/<body[^>]*>/i, (match: string) => `${match}${script}`);\n }\n\n return `${html}${script}`;\n}\n","const AUTHOR_SCROLLBAR_RE = /::-webkit-scrollbar|scrollbar-width|scrollbar-color/i;\n\nconst SCROLLBAR_STYLE = `<style data-html-preview-sandbox-scrollbar>\n:root {\n color-scheme: light;\n}\nhtml, body {\n min-height: 100%;\n}\n* {\n scrollbar-width: thin;\n scrollbar-color: rgba(96, 112, 128, 0.45) transparent;\n}\n*::-webkit-scrollbar {\n width: 10px;\n height: 10px;\n}\n*::-webkit-scrollbar-thumb {\n background: rgba(96, 112, 128, 0.38);\n border-radius: 999px;\n border: 2px solid transparent;\n background-clip: content-box;\n}\n</style>`;\n\nexport function hasAuthorScrollbarStyle(html: string): boolean {\n return AUTHOR_SCROLLBAR_RE.test(html || '');\n}\n\nexport function injectScrollbarStyle(html: string): string {\n if (hasAuthorScrollbarStyle(html)) return html;\n\n if (/<\\/head>/i.test(html)) {\n return html.replace(/<\\/head>/i, `${SCROLLBAR_STYLE}</head>`);\n }\n\n if (/<body[^>]*>/i.test(html)) {\n return html.replace(/<body[^>]*>/i, (match: string) => `${match}${SCROLLBAR_STYLE}`);\n }\n\n return `${html}${SCROLLBAR_STYLE}`;\n}\n","import { normalizeInput } from './decode.js';\nimport { sanitizeHtml } from './sanitize.browser.js';\nimport { buildCsp, injectCspMeta } from './policy.js';\nimport { injectBridgeScript } from './bridge.js';\nimport { injectScrollbarStyle } from './scrollbar.js';\nimport { ERROR_CODES, PreviewError } from './errors.js';\nimport type { PreviewInput, PreviewOptions, RenderResult } from './types.js';\n\nexport async function createHtmlDocument(input: PreviewInput, options: PreviewOptions = {}): Promise<RenderResult> {\n const decoded = await normalizeInput(input, { maxBytes: options.maxBytes });\n const sanitized = sanitizeHtml(decoded.html, options.sanitize);\n\n if (!sanitized.html.trim()) {\n sanitized.report.strippedAll = true;\n throw new PreviewError(ERROR_CODES.EMPTY_AFTER_SANITIZE, 'HTML is empty after sanitization');\n }\n\n const csp = buildCsp(options.csp);\n const withCsp = injectCspMeta(sanitized.html, csp);\n const withBridge = injectBridgeScript(withCsp);\n const html = options.injectScrollbarStyle === false ? withBridge : injectScrollbarStyle(withBridge);\n\n return {\n html,\n encoding: decoded.encoding,\n sanitizeReport: sanitized.report,\n };\n}\n","import { BRIDGE_CSP_VIOLATION, BRIDGE_OPEN_EXTERNAL } from './bridge.js';\nimport { DEFAULT_SANDBOX_TOKENS, getSandboxAttribute, isAllowedExternalUrl } from './policy.js';\nimport { ERROR_CODES, PreviewError } from './errors.js';\nimport type { OpenExternalSource, PreviewErrorShape, PreviewHandle, PreviewInput, PreviewOptions, RenderResult } from './types.js';\n\nfunction toMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction toPreviewError(error: unknown): PreviewErrorShape {\n return error instanceof PreviewError ? error : new PreviewError(ERROR_CODES.RENDER_FAILED, toMessage(error), error);\n}\n\ntype OpenExternalContext = { source: OpenExternalSource };\ntype CreateHtmlDocument = (input: PreviewInput, options?: PreviewOptions) => Promise<RenderResult>;\n\n// The Node and browser entrypoints share this renderer; they only differ in\n// which createHtmlDocument implementation (jsdom-backed vs real DOM) they inject.\nexport function createPreviewFactory(createHtmlDocument: CreateHtmlDocument) {\n return function createPreview(container: HTMLElement, options: PreviewOptions = {}): PreviewHandle {\n if (!container || typeof container.appendChild !== 'function') {\n throw new TypeError('createPreview requires a container HTMLElement');\n }\n\n let currentOptions = { ...options };\n let iframe: HTMLIFrameElement | null = null;\n let destroyed = false;\n let lastHtml = '';\n\n function removeIframe(): void {\n if (iframe?.parentNode) iframe.parentNode.removeChild(iframe);\n iframe = null;\n }\n\n function ensureIframe(): HTMLIFrameElement {\n removeIframe();\n iframe = document.createElement('iframe');\n iframe.setAttribute('sandbox', getSandboxAttribute(currentOptions.sandboxTokens ?? DEFAULT_SANDBOX_TOKENS, {\n allowUnsafeTokens: currentOptions.allowUnsafeSandboxTokens,\n }));\n iframe.setAttribute('referrerpolicy', 'no-referrer');\n iframe.setAttribute('title', 'HTML preview sandbox');\n iframe.style.width = '100%';\n iframe.style.height = '100%';\n iframe.style.border = '0';\n iframe.style.display = 'block';\n iframe.style.background = '#fff';\n container.appendChild(iframe);\n return iframe;\n }\n\n function handleMessage(event: MessageEvent): void {\n const data = event?.data;\n if (!data || typeof data !== 'object') return;\n if (!iframe || event.source !== iframe.contentWindow) return;\n\n if ('type' in data && data.type === BRIDGE_CSP_VIOLATION) {\n currentOptions.onCspViolation?.({\n effectiveDirective: String(data.effectiveDirective || data.violatedDirective || ''),\n blockedURI: String(data.blockedURI || ''),\n sourceFile: String(data.sourceFile || ''),\n lineNumber: Number(data.lineNumber || 0),\n sample: String(data.sample || ''),\n });\n return;\n }\n\n if ('type' in data && data.type === BRIDGE_OPEN_EXTERNAL) {\n const href = String(data.href || '');\n const source: OpenExternalSource = data.source === 'window.open' ? 'window.open' : 'link';\n const context: OpenExternalContext = { source };\n if (!isAllowedExternal(href, context)) {\n currentOptions.logger?.warn?.(`Blocked external URL: ${href}`);\n return;\n }\n currentOptions.onOpenExternal?.(href, context);\n }\n }\n\n function isAllowedExternal(url: string, context: OpenExternalContext): boolean {\n if (!isAllowedExternalUrl(url, currentOptions.externalProtocols)) return false;\n if (!currentOptions.allowExternalUrl) return true;\n try {\n return currentOptions.allowExternalUrl(url, context) === true;\n } catch (error) {\n currentOptions.logger?.warn?.(`External URL policy threw: ${toMessage(error)}`);\n return false;\n }\n }\n\n function remountLastHtml(): void {\n if (!lastHtml) return;\n const target = ensureIframe();\n target.srcdoc = lastHtml;\n }\n\n window.addEventListener('message', handleMessage);\n\n return {\n async render(input) {\n if (destroyed) throw new Error('Preview has been destroyed');\n try {\n const result = await createHtmlDocument(input, currentOptions);\n currentOptions.onSanitize?.(result.sanitizeReport);\n lastHtml = result.html;\n const target = ensureIframe();\n target.srcdoc = result.html;\n return result;\n } catch (error) {\n currentOptions.onError?.(toPreviewError(error));\n throw error;\n }\n },\n updateOptions(patch) {\n currentOptions = { ...currentOptions, ...patch };\n },\n notifyNavigationAttempt(url, context = { source: 'navigation' as const }) {\n const href = String(url || '');\n if (!href) return;\n currentOptions.onNavigationAttempt?.(href, context);\n remountLastHtml();\n if (isAllowedExternal(href, context)) {\n currentOptions.onOpenExternal?.(href, context);\n } else {\n currentOptions.logger?.warn?.(`Blocked navigation URL: ${href}`);\n }\n },\n destroy() {\n destroyed = true;\n window.removeEventListener('message', handleMessage);\n removeIframe();\n lastHtml = '';\n },\n get iframe() {\n return iframe;\n },\n };\n };\n}\n","import { createHtmlDocument } from './document.browser.js';\nimport { createPreviewFactory } from './renderer-core.js';\n\nexport const createPreview = createPreviewFactory(createHtmlDocument);\n"],"mappings":";AAEO,IAAM,eAAN,cAA2B,MAAM;AAAA,EAItC,YAAY,MAAwB,SAAiB,OAAiB;AACpE,UAAM,OAAO;AACb,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,QAAQ;AAAA,EACf;AACF;AAEO,IAAM,cAAc;AAAA,EACzB,WAAW;AAAA,EACX,eAAe;AAAA,EACf,sBAAsB;AAAA,EACtB,eAAe;AACjB;;;AChBO,IAAM,oBAAoB,MAAM,OAAO;AAE9C,IAAM,WAAW,CAAC,KAAM,KAAM,GAAI;AAClC,IAAM,eAAe,CAAC,KAAM,GAAI;AAChC,IAAM,eAAe,CAAC,KAAM,GAAI;AAShC,SAAS,gBAAgB,OAAmB,QAA2B;AACrE,MAAI,MAAM,SAAS,OAAO,OAAQ,QAAO;AACzC,SAAO,OAAO,MAAM,CAAC,MAAM,UAAU,MAAM,KAAK,MAAM,IAAI;AAC5D;AAEA,SAAS,WAAW,OAAmB,UAAkB,QAAQ,OAAsB;AACrF,MAAI;AACF,WAAO,IAAI,YAAY,UAAU,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK;AAAA,EAC1D,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAEA,SAAS,oBAAoB,MAA6B;AACxD,QAAM,cAAc,KAAK,MAAM,wCAAwC;AACvE,MAAI,cAAc,CAAC,EAAG,QAAO,YAAY,CAAC,EAAE,YAAY;AAExD,QAAM,cAAc,KAAK,MAAM,8BAA8B;AAC7D,MAAI,cAAc,CAAC,EAAG,QAAO,YAAY,CAAC,EAAE,YAAY;AAExD,SAAO;AACT;AAEA,eAAsB,eAAe,OAAqB,UAAiC,CAAC,GAA0B;AACpH,QAAM,WAAW,QAAQ,YAAY;AAErC,MAAI,OAAO,UAAU,UAAU;AAC7B,UAAM,OAAO,IAAI,YAAY,EAAE,OAAO,KAAK,EAAE;AAC7C,QAAI,OAAO,UAAU;AACnB,YAAM,IAAI,aAAa,YAAY,WAAW,sBAAsB,QAAQ,QAAQ;AAAA,IACtF;AACA,WAAO,EAAE,MAAM,OAAO,UAAU,SAAS,SAAS,OAAO,KAAK;AAAA,EAChE;AAEA,MAAI;AACJ,MAAI,iBAAiB,YAAY;AAC/B,YAAQ;AAAA,EACV,WAAW,iBAAiB,aAAa;AACvC,YAAQ,IAAI,WAAW,KAAK;AAAA,EAC9B,WAAW,OAAO,SAAS,eAAe,iBAAiB,MAAM;AAG/D,QAAI,MAAM,OAAO,UAAU;AACzB,YAAM,IAAI,aAAa,YAAY,WAAW,sBAAsB,QAAQ,QAAQ;AAAA,IACtF;AACA,YAAQ,IAAI,WAAW,MAAM,MAAM,YAAY,CAAC;AAAA,EAClD,OAAO;AACL,UAAM,IAAI,aAAa,YAAY,eAAe,2BAA2B;AAAA,EAC/E;AAEA,MAAI,MAAM,aAAa,UAAU;AAC/B,UAAM,IAAI,aAAa,YAAY,WAAW,sBAAsB,QAAQ,QAAQ;AAAA,EACtF;AAEA,SAAO,gBAAgB,KAAK;AAC9B;AAEO,SAAS,gBAAgB,OAA+C;AAC7E,QAAM,QAAQ,iBAAiB,aAAa,QAAQ,IAAI,WAAW,KAAK;AAExE,MAAI,gBAAgB,OAAO,QAAQ,GAAG;AACpC,WAAO;AAAA,MACL,MAAM,WAAW,MAAM,SAAS,SAAS,MAAM,GAAG,OAAO,KAAK;AAAA,MAC9D,UAAU;AAAA,MACV,SAAS;AAAA,MACT,MAAM,MAAM;AAAA,IACd;AAAA,EACF;AAEA,MAAI,gBAAgB,OAAO,YAAY,GAAG;AACxC,WAAO;AAAA,MACL,MAAM,WAAW,MAAM,SAAS,aAAa,MAAM,GAAG,UAAU,KAAK;AAAA,MACrE,UAAU;AAAA,MACV,SAAS;AAAA,MACT,MAAM,MAAM;AAAA,IACd;AAAA,EACF;AAEA,MAAI,gBAAgB,OAAO,YAAY,GAAG;AACxC,WAAO;AAAA,MACL,MAAM,WAAW,MAAM,SAAS,aAAa,MAAM,GAAG,UAAU,KAAK;AAAA,MACrE,UAAU;AAAA,MACV,SAAS;AAAA,MACT,MAAM,MAAM;AAAA,IACd;AAAA,EACF;AAEA,QAAM,aAAa,WAAW,OAAO,SAAS,IAAI;AAClD,MAAI,eAAe,MAAM;AACvB,WAAO,EAAE,MAAM,YAAY,UAAU,SAAS,SAAS,OAAO,MAAM,MAAM,WAAW;AAAA,EACvF;AAEA,QAAM,OAAO,WAAW,MAAM,SAAS,GAAG,IAAI,GAAG,YAAY,KAAK;AAClE,QAAM,WAAW,oBAAoB,IAAI;AAEzC,MAAI,YAAY,aAAa,WAAW,aAAa,QAAQ;AAC3D,UAAM,UAAU,WAAW,OAAO,QAAQ;AAC1C,QAAI,YAAY,MAAM;AACpB,aAAO,EAAE,MAAM,SAAS,UAAU,UAAU,SAAS,OAAO,MAAM,MAAM,WAAW;AAAA,IACrF;AAAA,EACF;AAEA,SAAO;AAAA,IACL,MAAM,WAAW,OAAO,OAAO,KAAK;AAAA,IACpC,UAAU;AAAA,IACV,SAAS;AAAA,IACT,MAAM,MAAM;AAAA,EACd;AACF;;;AC5HA,OAAO,qBAAqB;;;ACE5B,IAAM,uBAAuB;AAAA,EAC3B;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAS;AAAA,EAC1D;AAAA,EAAQ;AAAA,EAAW;AAAA,EAAW;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAC3D;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAK;AAAA,EAAM;AAAA,EAAM;AAAA,EAAO;AAAA,EAAQ;AAAA,EAC/C;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC9B;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAC9B;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EAAS;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAW;AAAA,EAAY;AAAA,EAC7E;AAAA,EAAK;AAAA,EAAU;AAAA,EAAK;AAAA,EAAM;AAAA,EAAK;AAAA,EAAK;AAAA,EAAK;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAO;AAAA,EACjE;AAAA,EAAO;AAAA,EAAW;AAAA,EAAU;AAAA,EAAS;AAAA,EAAS;AAAA,EAC9C;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAS;AAAA,EAAU;AAAA,EAAU;AAAA,EAAU;AAAA,EAAY;AAAA,EACpE;AAAA,EAAY;AAAA,EAAU;AAAA,EAAW;AAAA,EACjC;AAAA,EAAO;AAAA,EAAK;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAO;AAAA,EACrC;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAW;AAAA,EAC5D;AAAA,EAAQ;AAAA,EAAS;AAAA,EAAY;AAAA,EAAkB;AAAA,EAAkB;AAAA,EACjE;AAAA,EAAW;AAAA,EAAQ;AAAA,EAAY;AAAA,EAAU;AAAA,EAAkB;AAAA,EAC3D;AAAA,EAAY;AAAA,EAAW;AAAA,EAAe;AAAA,EAAW;AAAA,EAAW;AAAA,EAC5D;AAAA,EAAgB;AAAA,EAAqB;AAAA,EAAgB;AAAA,EACrD;AAAA,EAAW;AAAA,EAAoB;AAAA,EAAiB;AAAA,EAAO;AACzD;AAEA,IAAM,kBAAkB,CAAC,QAAQ,UAAU,SAAS,QAAQ;AAE5D,IAAM,eAAe;AAAA,EACnB;AAAA,EAAS;AAAA,EAAM;AAAA,EAAS;AAAA,EAAS;AAAA,EAAQ;AAAA,EAAO;AAAA,EAAQ;AAAA,EAAY;AAAA,EACpE;AAAA,EAAU;AACZ;AAEA,IAAM,qBAAqB;AAAA,EACzB;AAAA,EAAW;AAAA,EAAc;AAAA,EACzB;AAAA,EAAW;AAAA,EAAY;AAAA,EAAY;AAAA,EACnC;AAAA,EAAa;AAAA,EAAW;AAAA,EACxB;AAAA,EAAa;AACf;AAEA,IAAM,YAAY;AAAA,EAChB;AAAA,EAAK;AAAA,EAAK;AAAA,EAAM;AAAA,EAAM;AAAA,EAAK;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EAAM;AAAA,EACzD;AAAA,EAAS;AAAA,EAAU;AAAA,EAAK;AAAA,EAAU;AAAA,EAAa;AAAA,EAAQ;AAAA,EACvD;AAAA,EAAa;AAAA,EAAU;AAAA,EAAgB;AAAA,EAAkB;AAAA,EACzD;AAAA,EAAoB;AAAA,EAAqB;AAAA,EAAkB;AAAA,EAC3D;AAAA,EAAW;AAAA,EAAS;AAAA,EAAc;AAAA,EAAW;AAAA,EAC7C;AAAA,EAAW;AAAA,EAAuB;AAAA,EAAS;AAAA,EAC3C;AAAA,EAAQ;AAAA,EAAc;AAAA,EAAU;AAAA,EAAiB;AAAA,EACjD;AAAA,EAAgB;AAAA,EAAc;AAAA,EAAgB;AAAA,EAC9C;AAAA,EAAqB;AAAA,EAAsB;AAAA,EAAe;AAAA,EAC1D;AAAA,EAAe;AAAA,EAAc;AAAA,EAAkB;AAAA,EAC/C;AAAA,EAAmB;AAAA,EAAM;AAAA,EAAM;AAAA,EAAU;AAAA,EAAe;AAAA,EACxD;AAAA,EAAgB;AAAA,EAAa;AAAA,EAAa;AAAA,EAAQ;AAAA,EAAU;AAAA,EAC5D;AAAA,EAAM;AAAA,EAAO;AAAA,EAAU;AAAA,EAAQ;AAAA,EAAe;AAAA,EAAiB;AAAA,EAC/D;AAAA,EAAgB;AAAA,EAAoB;AAAA,EAAuB;AAAA,EAC3D;AAAA,EAAgB;AAAA,EAAQ;AAAA,EAAQ;AAAA,EAAU;AAAA,EAAe;AAAA,EACzD;AAAA,EAAc;AAAA,EAAc;AAAA,EAAiB;AAAA,EAAiB;AAAA,EAAQ;AAAA,EACtE;AAAA,EAAM;AAAA,EAAU;AAAA,EAAO;AAAA,EAAe;AAAA,EAAa;AAAA,EAAS;AAAA,EAC5D;AAAA,EAAY;AAAA,EAAY;AAAA,EAAc;AAAA,EAAY;AAAA,EAClD;AAAA,EAAa;AACf;AAEA,IAAM,eAAyC;AAAA,EAC7C,GAAG,CAAC,QAAQ,QAAQ,UAAU,OAAO,UAAU;AAAA,EAC/C,MAAM,CAAC,OAAO,QAAQ,MAAM,eAAe,aAAa,kBAAkB,QAAQ,SAAS,OAAO;AAAA,EAClG,MAAM,CAAC,WAAW,QAAQ,WAAW,cAAc,UAAU;AAAA,EAC7D,KAAK,CAAC,OAAO,OAAO,SAAS,UAAU,WAAW,YAAY,UAAU,OAAO;AAAA,EAC/E,QAAQ,CAAC,OAAO,UAAU,QAAQ,OAAO;AAAA,EACzC,OAAO,CAAC,QAAQ,QAAQ,SAAS,eAAe,OAAO,OAAO,QAAQ,YAAY,WAAW,YAAY,YAAY,WAAW,WAAW;AAAA,EAC3I,QAAQ,CAAC,QAAQ,QAAQ,SAAS,UAAU;AAAA,EAC5C,QAAQ,CAAC,QAAQ,SAAS,YAAY,YAAY,UAAU;AAAA,EAC5D,QAAQ,CAAC,SAAS,YAAY,UAAU;AAAA,EACxC,UAAU,CAAC,QAAQ,SAAS,eAAe,QAAQ,QAAQ,aAAa,YAAY,YAAY,UAAU;AAAA,EAC1G,MAAM,CAAC,UAAU,WAAW,YAAY;AAAA,EACxC,OAAO,CAAC,KAAK;AAAA,EACb,OAAO,CAAC,OAAO,YAAY,YAAY,QAAQ,SAAS,SAAS;AAAA,EACjE,OAAO,CAAC,OAAO,YAAY,YAAY,QAAQ,SAAS,WAAW,UAAU,SAAS,QAAQ;AAAA,EAC9F,QAAQ,CAAC,OAAO,QAAQ,SAAS,SAAS,eAAe,aAAa,kBAAkB,YAAY,OAAO;AAC7G;AAEA,IAAM,YAAY,oBAAI,IAAI,CAAC,QAAQ,OAAO,UAAU,QAAQ,cAAc,QAAQ,CAAC;AACnF,IAAM,kBAAkB,oBAAI,IAAI,CAAC,SAAS,UAAU,WAAW,MAAM,CAAC;AACtE,IAAM,aAAa,oBAAI,IAAI,CAAC,OAAO,SAAS,SAAS,UAAU,SAAS,CAAC;AAEzE,SAAS,cAA8B;AACrC,SAAO;AAAA,IACL,aAAa,CAAC;AAAA,IACd,mBAAmB,CAAC;AAAA,IACpB,gBAAgB,CAAC;AAAA,IACjB,aAAa;AAAA,EACf;AACF;AAIA,SAAS,UAAmC,MAAW,WAAiC,QAAsC;AAC5H,QAAM,WAAW,KAAK,KAAK,SAAS;AACpC,MAAI,UAAU;AACZ,aAAS,SAAS;AAClB;AAAA,EACF;AACA,OAAK,KAAK,EAAE,GAAG,OAAO,GAAG,OAAO,EAAE,CAAM;AAC1C;AAEA,SAAS,UAAU,QAAwB,KAAmB;AAC5D,YAAU,OAAO,aAAa,CAAC,SAAS,KAAK,QAAQ,KAAK,OAAO,EAAE,IAAI,EAAE;AAC3E;AAEA,SAAS,WAAW,QAAwB,KAAa,MAAoB;AAC3E,YAAU,OAAO,mBAAmB,CAAC,SAAS,KAAK,QAAQ,OAAO,KAAK,SAAS,MAAM,OAAO,EAAE,KAAK,KAAK,EAAE;AAC7G;AAEA,SAAS,aAAa,QAAwB,QAAsB;AAClE,YAAU,OAAO,gBAAgB,CAAC,SAAS,KAAK,WAAW,QAAQ,OAAO,EAAE,OAAO,EAAE;AACvF;AAEA,SAAS,cAAc,MAAuB;AAC5C,SAAO,OAAO,QAAQ,EAAE,EAAE,YAAY;AACxC;AAEA,SAAS,eAAe,MAAc,SAA0B;AAC9D,QAAM,oBAAoB,cAAc,OAAO;AAC/C,SAAO,kBAAkB,SAAS,GAAG,IACjC,KAAK,WAAW,kBAAkB,MAAM,GAAG,EAAE,CAAC,IAC9C,SAAS;AACf;AAEA,SAAS,eAAe,UAA2B,CAAC,GAAgB;AAClE,QAAM,OAAO,IAAI,IAAI,qBAAqB,IAAI,aAAa,CAAC;AAC5D,MAAI,QAAQ,iBAAiB,MAAO,MAAK,OAAO,QAAQ;AACxD,aAAW,OAAO,QAAQ,aAAa,CAAC,EAAG,MAAK,IAAI,cAAc,GAAG,CAAC;AACtE,aAAW,OAAO,QAAQ,YAAY,CAAC,EAAG,MAAK,OAAO,cAAc,GAAG,CAAC;AACxE,SAAO;AACT;AAEA,SAAS,gBAAgB,UAA2B,CAAC,GAAa;AAChE,SAAO;AAAA,IACL,GAAG;AAAA,IACH,GAAI,QAAQ,sBAAsB,QAAQ,CAAC,IAAI;AAAA,IAC/C,GAAG;AAAA,IACH,GAAG,OAAO,OAAO,YAAY,EAAE,KAAK;AAAA,IACpC,GAAI,QAAQ,kBAAkB,GAAG,KAAK,CAAC;AAAA,IACvC,GAAG,OAAO,OAAO,QAAQ,mBAAmB,CAAC,CAAC,EAAE,KAAK;AAAA,EACvD;AACF;AAEA,SAAS,cAAc,KAAa,MAAc,UAA2B,CAAC,GAAY;AACxF,MAAI,aAAa,KAAK,CAAC,YAAY,eAAe,MAAM,OAAO,CAAC,EAAG,QAAO;AAC1E,MAAI,QAAQ,sBAAsB,SAAS,mBAAmB,IAAI,aAAa,EAAE,SAAS,IAAI,EAAG,QAAO;AACxG,MAAI,UAAU,IAAI,aAAa,EAAE,SAAS,IAAI,EAAG,QAAO;AACxD,OAAK,aAAa,GAAG,KAAK,CAAC,GAAG,IAAI,aAAa,EAAE,SAAS,IAAI,EAAG,QAAO;AACxE,OAAK,QAAQ,kBAAkB,GAAG,KAAK,CAAC,GAAG,IAAI,aAAa,EAAE,SAAS,IAAI,EAAG,QAAO;AACrF,OAAK,QAAQ,kBAAkB,GAAG,KAAK,CAAC,GAAG,IAAI,aAAa,EAAE,SAAS,IAAI,EAAG,QAAO;AACrF,SAAO;AACT;AAEA,SAAS,UAAU,KAAsB;AACvC,QAAM,UAAU,OAAO,OAAO,EAAE,EAAE,KAAK;AACvC,QAAM,QAAQ,QAAQ,MAAM,sBAAsB;AAClD,SAAO,QAAQ,GAAG,MAAM,CAAC,EAAE,YAAY,CAAC,MAAM;AAChD;AAEA,SAAS,aAAa,KAAc,KAAa,UAA2B,CAAC,GAAY;AACvF,QAAM,SAAS,UAAU,GAAG;AAC5B,MAAI,CAAC,OAAQ,QAAO;AACpB,MAAI,gBAAgB,IAAI,MAAM,EAAG,QAAO;AACxC,MAAI,WAAW,IAAI,GAAG,MAAM,WAAW,WAAW,WAAW,SAAU,QAAO;AAC9E,UAAQ,QAAQ,gBAAgB,CAAC,GAC9B,IAAI,CAAC,SAAU,KAAK,SAAS,GAAG,IAAI,KAAK,YAAY,IAAI,GAAG,KAAK,YAAY,CAAC,GAAI,EAClF,SAAS,MAAM;AACpB;AAEA,SAAS,sBAAsB,KAAwB;AACrD,SAAO,OAAO,OAAO,EAAE,EACpB,MAAM,GAAG,EACT,IAAI,CAAC,cAAc,UAAU,KAAK,CAAC,EACnC,OAAO,OAAO,EACd,IAAI,CAAC,cAAc,UAAU,MAAM,KAAK,EAAE,CAAC,CAAC,EAC5C,OAAO,OAAO;AACnB;AAEA,SAAS,wBAAwB,KAAc,KAAa,UAA2B,CAAC,GAAa;AACnG,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,OAAO,sBAAsB,GAAG,GAAG;AAC5C,QAAI,CAAC,aAAa,KAAK,KAAK,OAAO,GAAG;AACpC,cAAQ,IAAI,UAAU,GAAG,KAAK,SAAS;AAAA,IACzC;AAAA,EACF;AACA,SAAO,CAAC,GAAG,OAAO;AACpB;AAEA,SAAS,gBAAgB,MAAwB;AAC/C,MAAI,cAAc,KAAK,QAAQ,MAAM,OAAQ,QAAO;AACpD,QAAM,QAAQ,cAAc,KAAK,aAAa,YAAY,CAAC;AAC3D,SAAO,UAAU,aAAa,UAAU;AAC1C;AAMA,IAAM,iBAAiB,oBAAI,IAAI,CAAC,WAAW,OAAO,iBAAiB,kBAAkB,CAAC;AACtF,IAAM,mBAAmB,oBAAI,IAAI,CAAC,QAAQ,cAAc,KAAK,CAAC;AAE9D,SAAS,wBAAwB,MAAwB;AACvD,MAAI,CAAC,eAAe,IAAI,cAAc,KAAK,QAAQ,CAAC,EAAG,QAAO;AAC9D,QAAM,SAAS,cAAc,KAAK,eAAe,eAAe,CAAC;AACjE,SAAO,iBAAiB,IAAI,MAAM;AACpC;AAOA,IAAM,oBAAoB,oBAAI,IAAI,CAAC,gBAAgB,cAAc,YAAY,WAAW,CAAC;AAEzF,SAAS,0BAA0B,MAAwB;AACzD,MAAI,cAAc,KAAK,QAAQ,MAAM,OAAQ,QAAO;AACpD,QAAM,MAAM,cAAc,KAAK,eAAe,KAAK,CAAC;AACpD,MAAI,CAAC,IAAK,QAAO;AACjB,SAAO,IAAI,MAAM,KAAK,EAAE,KAAK,CAAC,UAAU,kBAAkB,IAAI,KAAK,CAAC;AACtE;AAEA,SAAS,kBAAkB,UAAe,QAAwB,SAAgC;AAIhG,QAAM,iBAAiB,oBAAI,QAAiB;AAE5C,WAAS,QAAQ,uBAAuB,CAAC,MAAe,SAA+B;AACrF,UAAM,MAAM,cAAc,KAAK,WAAW,KAAK,QAAQ;AACvD,QAAI,gBAAgB,SAAS,GAAG,EAAG,WAAU,QAAQ,GAAG;AACxD,QAAI,gBAAgB,IAAI,EAAG,YAAW,QAAQ,QAAQ,YAAY;AAGlE,QAAI,wBAAwB,IAAI,GAAG;AACjC,gBAAU,QAAQ,GAAG;AACrB,qBAAe,IAAI,IAAI;AAAA,IACzB;AAEA,QAAI,0BAA0B,IAAI,GAAG;AACnC,gBAAU,QAAQ,GAAG;AACrB,qBAAe,IAAI,IAAI;AAAA,IACzB;AAAA,EACF,CAAC;AAED,WAAS,QAAQ,yBAAyB,CAAC,SAAkB;AAC3D,QAAI,gBAAgB,IAAI,KAAK,eAAe,IAAI,IAAI,GAAG;AACrD,WAAK,OAAO;AAAA,IACd;AAAA,EACF,CAAC;AAED,WAAS,QAAQ,2BAA2B,CAAC,SAAkB;AAC7D,UAAM,MAAM,cAAc,KAAK,QAAQ;AACvC,QAAI,CAAC,KAAK,WAAY;AAEtB,eAAW,YAAY,CAAC,GAAG,KAAK,UAAU,GAAG;AAC3C,YAAM,OAAO,cAAc,SAAS,IAAI;AACxC,UAAI,CAAC,cAAc,KAAK,MAAM,OAAO,GAAG;AACtC,mBAAW,QAAQ,KAAK,IAAI;AAC5B,aAAK,gBAAgB,SAAS,IAAI;AAClC;AAAA,MACF;AAEA,UAAI,UAAU,IAAI,IAAI,KAAK,CAAC,aAAa,SAAS,OAAO,KAAK,OAAO,GAAG;AACtE,mBAAW,QAAQ,KAAK,IAAI;AAC5B,qBAAa,QAAQ,UAAU,SAAS,KAAK,KAAK,SAAS;AAC3D,aAAK,gBAAgB,SAAS,IAAI;AAClC;AAAA,MACF;AAEA,UAAI,SAAS,UAAU;AACrB,cAAM,iBAAiB,wBAAwB,SAAS,OAAO,KAAK,OAAO;AAC3E,YAAI,eAAe,QAAQ;AACzB,qBAAW,QAAQ,KAAK,IAAI;AAC5B,qBAAW,UAAU,eAAgB,cAAa,QAAQ,MAAM;AAChE,eAAK,gBAAgB,SAAS,IAAI;AAAA,QACpC;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AACH;AAEA,SAAS,wBAAwB,UAAe,QAA8B;AAC5E,aAAW,QAAQ,SAAS,WAAW,CAAC,GAAG;AACzC,QAAI,KAAK,SAAS;AAChB,gBAAU,QAAQ,cAAc,KAAK,QAAQ,QAAQ,CAAC;AAAA,IACxD;AACA,QAAI,KAAK,WAAW;AAClB,iBAAW,QAAQ,cAAc,KAAK,MAAM,YAAY,GAAG,GAAG,cAAc,KAAK,UAAU,IAAI,CAAC;AAChG,UAAI,UAAU,IAAI,cAAc,KAAK,UAAU,IAAI,CAAC,GAAG;AACrD,qBAAa,QAAQ,UAAU,KAAK,UAAU,KAAK,KAAK,SAAS;AAAA,MACnE;AAAA,IACF;AAAA,EACF;AACF;AAEO,SAAS,gBAAgB,eAAoBA,kBAAsB;AACxE,SAAO,SAASC,cAAa,SAAiB,UAA2B,CAAC,GAA6C;AACrH,UAAM,WAAWD,iBAAgB,aAAa;AAC9C,UAAM,SAAS,YAAY;AAC3B,UAAM,cAAc,CAAC,GAAG,eAAe,OAAO,CAAC;AAE/C,sBAAkB,UAAU,QAAQ,OAAO;AAE3C,UAAM,OAAO,SAAS,SAAS,SAAS;AAAA,MACtC,gBAAgB;AAAA;AAAA;AAAA;AAAA,MAIhB,cAAc;AAAA,MACd,cAAc,gBAAgB,OAAO;AAAA,MACrC,aAAa;AAAA,MACb,cAAc;AAAA,MACd,iBAAiB;AAAA,MACjB,iBAAiB;AAAA,IACnB,CAAC;AAED,4BAAwB,UAAU,MAAM;AAExC,UAAM,SAAS,IAAI,cAAc,UAAU;AAC3C,UAAM,MAAM,OAAO,gBAAgB,MAAM,WAAW;AACpD,WAAO,cAAc,CAAC,IAAI,KAAK,aAAa,KAAK,KAAK,CAAC,IAAI,KAAK,cAAc,yCAAyC;AAEvH,WAAO,EAAE,MAAM,OAAO;AAAA,EACxB;AACF;;;ADhUO,IAAM,eAAe,gBAAgB,QAAQ,eAAe;;;AEDnE,IAAM,uBAAuB;AAAA,EAC3B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAM,qBAAqB,CAAC,2BAA2B;AAEhD,IAAM,yBAAyB;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,wBAAwB;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEO,IAAM,qCAAqC,CAAC,SAAS,UAAU,WAAW,MAAM;AAEvF,SAAS,gBAAgB,QAA2C;AAClE,MAAI,CAAC,OAAQ,QAAO,EAAE,QAAQ,SAAS;AACvC,MAAI,OAAO,WAAW,SAAU,QAAO,EAAE,QAAQ,OAAO;AACxD,SAAO,EAAE,QAAQ,UAAU,GAAG,OAAO;AACvC;AAEA,SAAS,KAAK,QAA0B;AACtC,SAAO,CAAC,GAAG,IAAI,IAAI,OAAO,OAAO,OAAO,CAAC,CAAC,EAAE,KAAK,GAAG;AACtD;AAWO,SAAS,SAAS,QAAwC;AAC/D,QAAM,aAAa,gBAAgB,MAAM;AACzC,QAAM,SAAS,WAAW,UAAU;AAEpC,QAAM,cAAc,CAAC,GAAG,sBAAsB,GAAI,WAAW,eAAe,CAAC,CAAE;AAC/E,QAAM,aAAa,CAAC,GAAG,qBAAqB,GAAI,WAAW,cAAc,CAAC,CAAE;AAC5E,QAAM,YAAY,CAAC,GAAG,oBAAoB,GAAI,WAAW,aAAa,CAAC,CAAE;AACzE,QAAM,WAAW,WAAW,YAAY,CAAC;AACzC,QAAM,eAAe,WAAW,gBAAgB,CAAC;AAEjD,QAAM,aAAqC;AAAA,IACzC,eAAe;AAAA,IACf,cAAc,KAAK,CAAC,mBAAmB,iBAAiB,GAAG,WAAW,CAAC;AAAA,IACvE,aAAa,KAAK,CAAC,mBAAmB,GAAG,UAAU,CAAC;AAAA,IACpD,WAAW,KAAK,CAAC,SAAS,SAAS,GAAG,QAAQ,CAAC;AAAA,IAC/C,aAAa;AAAA,IACb,YAAY,KAAK,CAAC,SAAS,GAAG,SAAS,CAAC;AAAA,IACxC,eAAe;AAAA,IACf,cAAc;AAAA,IACd,aAAa;AAAA,IACb,cAAc;AAAA,IACd,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,6BAA6B;AAAA,IAC7B,2BAA2B;AAAA,EAC7B;AAEA,MAAI,WAAW,YAAY;AACzB,eAAW,YAAY,IAAI,KAAK,CAAC,mBAAmB,iBAAiB,GAAG,aAAa,mBAAmB,CAAC;AACzG,eAAW,WAAW,IAAI,KAAK,CAAC,mBAAmB,GAAG,YAAY,mBAAmB,CAAC;AACtF,eAAW,SAAS,IAAI,KAAK,CAAC,UAAU,SAAS,SAAS,GAAG,QAAQ,CAAC;AACtE,eAAW,WAAW,IAAI,KAAK,CAAC,UAAU,SAAS,OAAO,CAAC;AAC3D,eAAW,aAAa,IAAI,aAAa,SAAS,KAAK,CAAC,UAAU,GAAG,YAAY,CAAC,IAAI;AAAA,EACxF;AAEA,MAAI,WAAW,WAAW;AACxB,eAAW,YAAY,IAAI;AAC3B,eAAW,WAAW,IAAI;AAC1B,eAAW,SAAS,IAAI;AACxB,eAAW,WAAW,IAAI;AAC1B,eAAW,UAAU,IAAI;AACzB,eAAW,aAAa,IAAI;AAAA,EAC9B;AAEA,SAAO,OAAO,YAAY,WAAW,cAAc,CAAC,CAAC;AAErD,SAAO,OAAO,QAAQ,UAAU,EAC7B,IAAI,CAAC,CAAC,MAAM,KAAK,MAAO,QAAQ,GAAG,IAAI,IAAI,KAAK,KAAK,IAAK,EAC1D,KAAK,IAAI;AACd;AAEO,SAAS,cAAc,MAAc,KAAqB;AAC/D,QAAM,UAAU,IAAI,QAAQ,MAAM,QAAQ;AAC1C,QAAM,OAAO,uDAAuD,OAAO;AAE3E,MAAI,eAAe,KAAK,IAAI,GAAG;AAC7B,WAAO,KAAK,QAAQ,gBAAgB,CAAC,UAAkB,GAAG,KAAK,GAAG,IAAI,EAAE;AAAA,EAC1E;AAEA,MAAI,eAAe,KAAK,IAAI,GAAG;AAC7B,WAAO,KAAK,QAAQ,gBAAgB,CAAC,UAAkB,GAAG,KAAK,SAAS,IAAI,SAAS;AAAA,EACvF;AAEA,SAAO,8BAA8B,IAAI,gBAAgB,IAAI;AAC/D;AAEO,SAAS,oBAAoB,SAAS,wBAAwB,UAA2C,CAAC,GAAW;AAC1H,QAAM,oBAAoB,QAAQ,sBAAsB;AACxD,SAAO,CAAC,GAAG,IAAI,IAAI,MAAM,CAAC,EACvB,OAAO,CAAC,UAAU,qBAAqB,CAAC,sBAAsB,SAAS,KAAK,CAAC,EAC7E,KAAK,GAAG;AACb;AAEO,SAAS,qBAAqB,KAAa,YAAY,oCAA6C;AACzG,MAAI;AACF,UAAM,SAAS,IAAI,IAAI,GAAG;AAC1B,UAAM,mBAAmB,UAAU,IAAI,CAAC,aAAa;AACnD,YAAM,aAAa,OAAO,YAAY,EAAE,EAAE,YAAY;AACtD,aAAO,WAAW,SAAS,GAAG,IAAI,aAAa,GAAG,UAAU;AAAA,IAC9D,CAAC;AACD,WAAO,iBAAiB,SAAS,OAAO,QAAQ;AAAA,EAClD,QAAQ;AACN,WAAO;AAAA,EACT;AACF;;;AC1IO,IAAM,uBAAuB;AAC7B,IAAM,uBAAuB;AAEpC,IAAM,sBAAsB;AAE5B,SAAS,eAAuB;AAC9B,SAAO;AAAA;AAAA,0BAEiB,KAAK,UAAU,oBAAoB,CAAC;AAAA,0BACpC,KAAK,UAAU,oBAAoB,CAAC;AAAA,kBAC5C,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkFrC;AAEO,SAAS,mBAAmB,MAAsB;AACvD,QAAM,SAAS,aAAa;AAC5B,QAAM,UAAU;AAEhB,MAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,WAAO,KAAK,QAAQ,SAAS,CAAC,UAAkB,GAAG,KAAK,GAAG,MAAM,EAAE;AAAA,EACrE;AAEA,MAAI,YAAY,KAAK,IAAI,GAAG;AAC1B,WAAO,KAAK,QAAQ,aAAa,GAAG,MAAM,SAAS;AAAA,EACrD;AAEA,MAAI,eAAe,KAAK,IAAI,GAAG;AAC7B,WAAO,KAAK,QAAQ,gBAAgB,CAAC,UAAkB,GAAG,KAAK,GAAG,MAAM,EAAE;AAAA,EAC5E;AAEA,SAAO,GAAG,IAAI,GAAG,MAAM;AACzB;;;AC/GA,IAAM,sBAAsB;AAE5B,IAAM,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuBjB,SAAS,wBAAwB,MAAuB;AAC7D,SAAO,oBAAoB,KAAK,QAAQ,EAAE;AAC5C;AAEO,SAAS,qBAAqB,MAAsB;AACzD,MAAI,wBAAwB,IAAI,EAAG,QAAO;AAE1C,MAAI,YAAY,KAAK,IAAI,GAAG;AAC1B,WAAO,KAAK,QAAQ,aAAa,GAAG,eAAe,SAAS;AAAA,EAC9D;AAEA,MAAI,eAAe,KAAK,IAAI,GAAG;AAC7B,WAAO,KAAK,QAAQ,gBAAgB,CAAC,UAAkB,GAAG,KAAK,GAAG,eAAe,EAAE;AAAA,EACrF;AAEA,SAAO,GAAG,IAAI,GAAG,eAAe;AAClC;;;ACjCA,eAAsB,mBAAmB,OAAqB,UAA0B,CAAC,GAA0B;AACjH,QAAM,UAAU,MAAM,eAAe,OAAO,EAAE,UAAU,QAAQ,SAAS,CAAC;AAC1E,QAAM,YAAY,aAAa,QAAQ,MAAM,QAAQ,QAAQ;AAE7D,MAAI,CAAC,UAAU,KAAK,KAAK,GAAG;AAC1B,cAAU,OAAO,cAAc;AAC/B,UAAM,IAAI,aAAa,YAAY,sBAAsB,kCAAkC;AAAA,EAC7F;AAEA,QAAM,MAAM,SAAS,QAAQ,GAAG;AAChC,QAAM,UAAU,cAAc,UAAU,MAAM,GAAG;AACjD,QAAM,aAAa,mBAAmB,OAAO;AAC7C,QAAM,OAAO,QAAQ,yBAAyB,QAAQ,aAAa,qBAAqB,UAAU;AAElG,SAAO;AAAA,IACL;AAAA,IACA,UAAU,QAAQ;AAAA,IAClB,gBAAgB,UAAU;AAAA,EAC5B;AACF;;;ACtBA,SAAS,UAAU,OAAwB;AACzC,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEA,SAAS,eAAe,OAAmC;AACzD,SAAO,iBAAiB,eAAe,QAAQ,IAAI,aAAa,YAAY,eAAe,UAAU,KAAK,GAAG,KAAK;AACpH;AAOO,SAAS,qBAAqBE,qBAAwC;AAC3E,SAAO,SAASC,eAAc,WAAwB,UAA0B,CAAC,GAAkB;AACjG,QAAI,CAAC,aAAa,OAAO,UAAU,gBAAgB,YAAY;AAC7D,YAAM,IAAI,UAAU,gDAAgD;AAAA,IACtE;AAEA,QAAI,iBAAiB,EAAE,GAAG,QAAQ;AAClC,QAAI,SAAmC;AACvC,QAAI,YAAY;AAChB,QAAI,WAAW;AAEf,aAAS,eAAqB;AAC5B,UAAI,QAAQ,WAAY,QAAO,WAAW,YAAY,MAAM;AAC5D,eAAS;AAAA,IACX;AAEA,aAAS,eAAkC;AACzC,mBAAa;AACb,eAAS,SAAS,cAAc,QAAQ;AACxC,aAAO,aAAa,WAAW,oBAAoB,eAAe,iBAAiB,wBAAwB;AAAA,QACzG,mBAAmB,eAAe;AAAA,MACpC,CAAC,CAAC;AACF,aAAO,aAAa,kBAAkB,aAAa;AACnD,aAAO,aAAa,SAAS,sBAAsB;AACnD,aAAO,MAAM,QAAQ;AACrB,aAAO,MAAM,SAAS;AACtB,aAAO,MAAM,SAAS;AACtB,aAAO,MAAM,UAAU;AACvB,aAAO,MAAM,aAAa;AAC1B,gBAAU,YAAY,MAAM;AAC5B,aAAO;AAAA,IACT;AAEA,aAAS,cAAc,OAA2B;AAChD,YAAM,OAAO,OAAO;AACpB,UAAI,CAAC,QAAQ,OAAO,SAAS,SAAU;AACvC,UAAI,CAAC,UAAU,MAAM,WAAW,OAAO,cAAe;AAEtD,UAAI,UAAU,QAAQ,KAAK,SAAS,sBAAsB;AACxD,uBAAe,iBAAiB;AAAA,UAC9B,oBAAoB,OAAO,KAAK,sBAAsB,KAAK,qBAAqB,EAAE;AAAA,UAClF,YAAY,OAAO,KAAK,cAAc,EAAE;AAAA,UACxC,YAAY,OAAO,KAAK,cAAc,EAAE;AAAA,UACxC,YAAY,OAAO,KAAK,cAAc,CAAC;AAAA,UACvC,QAAQ,OAAO,KAAK,UAAU,EAAE;AAAA,QAClC,CAAC;AACD;AAAA,MACF;AAEA,UAAI,UAAU,QAAQ,KAAK,SAAS,sBAAsB;AACxD,cAAM,OAAO,OAAO,KAAK,QAAQ,EAAE;AACnC,cAAM,SAA6B,KAAK,WAAW,gBAAgB,gBAAgB;AACnF,cAAM,UAA+B,EAAE,OAAO;AAC9C,YAAI,CAAC,kBAAkB,MAAM,OAAO,GAAG;AACrC,yBAAe,QAAQ,OAAO,yBAAyB,IAAI,EAAE;AAC7D;AAAA,QACF;AACA,uBAAe,iBAAiB,MAAM,OAAO;AAAA,MAC/C;AAAA,IACF;AAEA,aAAS,kBAAkB,KAAa,SAAuC;AAC7E,UAAI,CAAC,qBAAqB,KAAK,eAAe,iBAAiB,EAAG,QAAO;AACzE,UAAI,CAAC,eAAe,iBAAkB,QAAO;AAC7C,UAAI;AACF,eAAO,eAAe,iBAAiB,KAAK,OAAO,MAAM;AAAA,MAC3D,SAAS,OAAO;AACd,uBAAe,QAAQ,OAAO,8BAA8B,UAAU,KAAK,CAAC,EAAE;AAC9E,eAAO;AAAA,MACT;AAAA,IACF;AAEA,aAAS,kBAAwB;AAC/B,UAAI,CAAC,SAAU;AACf,YAAM,SAAS,aAAa;AAC5B,aAAO,SAAS;AAAA,IAClB;AAEA,WAAO,iBAAiB,WAAW,aAAa;AAEhD,WAAO;AAAA,MACL,MAAM,OAAO,OAAO;AAClB,YAAI,UAAW,OAAM,IAAI,MAAM,4BAA4B;AAC3D,YAAI;AACF,gBAAM,SAAS,MAAMD,oBAAmB,OAAO,cAAc;AAC7D,yBAAe,aAAa,OAAO,cAAc;AACjD,qBAAW,OAAO;AAClB,gBAAM,SAAS,aAAa;AAC5B,iBAAO,SAAS,OAAO;AACvB,iBAAO;AAAA,QACT,SAAS,OAAO;AACd,yBAAe,UAAU,eAAe,KAAK,CAAC;AAC9C,gBAAM;AAAA,QACR;AAAA,MACF;AAAA,MACA,cAAc,OAAO;AACnB,yBAAiB,EAAE,GAAG,gBAAgB,GAAG,MAAM;AAAA,MACjD;AAAA,MACA,wBAAwB,KAAK,UAAU,EAAE,QAAQ,aAAsB,GAAG;AACxE,cAAM,OAAO,OAAO,OAAO,EAAE;AAC7B,YAAI,CAAC,KAAM;AACX,uBAAe,sBAAsB,MAAM,OAAO;AAClD,wBAAgB;AAChB,YAAI,kBAAkB,MAAM,OAAO,GAAG;AACpC,yBAAe,iBAAiB,MAAM,OAAO;AAAA,QAC/C,OAAO;AACL,yBAAe,QAAQ,OAAO,2BAA2B,IAAI,EAAE;AAAA,QACjE;AAAA,MACF;AAAA,MACA,UAAU;AACR,oBAAY;AACZ,eAAO,oBAAoB,WAAW,aAAa;AACnD,qBAAa;AACb,mBAAW;AAAA,MACb;AAAA,MACA,IAAI,SAAS;AACX,eAAO;AAAA,MACT;AAAA,IACF;AAAA,EACF;AACF;;;ACvIO,IAAM,gBAAgB,qBAAqB,kBAAkB;","names":["createDOMPurify","sanitizeHtml","createHtmlDocument","createPreview"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type { CspPolicy, CspPreset, CspViolationReport, OpenExternalSource, PreviewErrorCode, PreviewErrorShape, PreviewHandle, PreviewInput, PreviewOptions, RenderResult, SanitizeOptions, SanitizeReport, } from './types.js';
|
|
2
|
+
export { createPreview } from './renderer.js';
|
|
3
|
+
export { createHtmlDocument } from './document.js';
|
|
4
|
+
export { decodeHtmlBytes, normalizeInput, DEFAULT_MAX_BYTES } from './decode.js';
|
|
5
|
+
export { sanitizeHtml } from './sanitize.js';
|
|
6
|
+
export { DEFAULT_ALLOWED_EXTERNAL_PROTOCOLS, DEFAULT_SANDBOX_TOKENS, UNSAFE_SANDBOX_TOKENS, buildCsp, getSandboxAttribute, injectCspMeta, isAllowedExternalUrl, } from './policy.js';
|
|
7
|
+
export { hasAuthorScrollbarStyle, injectScrollbarStyle, } from './scrollbar.js';
|
|
8
|
+
export { BRIDGE_CSP_VIOLATION, BRIDGE_OPEN_EXTERNAL, injectBridgeScript, } from './bridge.js';
|
|
9
|
+
export { PreviewError, ERROR_CODES } from './errors.js';
|